diff --git a/doc/contributions.txt b/doc/contributions.txt index 28c41debe7..c18d3eb171 100644 --- a/doc/contributions.txt +++ b/doc/contributions.txt @@ -44,6 +44,7 @@ Aleric Inglewood VWR-10001 VWR-10759 VWR-10837 + VWR-13996 Ales Beaumont VWR-9352 Alissa Sabre @@ -275,6 +276,9 @@ Jacek Antonelli VWR-597 VWR-2054 VWR-2448 + VWR-2896 + VWR-2947 + VWR-2948 VWR-3605 JB Kraft VWR-5283 diff --git a/etc/message.xml b/etc/message.xml index b26a4812a8..7ad392d0b5 100644 --- a/etc/message.xml +++ b/etc/message.xml @@ -377,7 +377,23 @@ trusted-sender true + + ParcelMediaURLFilter + + flavor + llsd + trusted-sender + false + + ParcelNavigateMedia + + flavor + llsd + trusted-sender + false + + ParcelObjectOwnersReply flavor diff --git a/indra/CMakeLists.txt b/indra/CMakeLists.txt index 7f4c2c33c1..9418dbf271 100644 --- a/indra/CMakeLists.txt +++ b/indra/CMakeLists.txt @@ -1,3 +1,4 @@ + # -*- cmake -*- # cmake_minimum_required should appear before any @@ -42,7 +43,6 @@ add_subdirectory(${LIBS_OPEN_PREFIX}llimage) add_subdirectory(${LIBS_OPEN_PREFIX}llimagej2coj) add_subdirectory(${LIBS_OPEN_PREFIX}llinventory) add_subdirectory(${LIBS_OPEN_PREFIX}llmath) -add_subdirectory(${LIBS_OPEN_PREFIX}llmedia) add_subdirectory(${LIBS_OPEN_PREFIX}llmessage) add_subdirectory(${LIBS_OPEN_PREFIX}llprimitive) add_subdirectory(${LIBS_OPEN_PREFIX}llrender) @@ -63,11 +63,22 @@ endif (WINDOWS AND EXISTS ${LIBS_CLOSED_DIR}copy_win_scripts) add_custom_target(viewer) if (VIEWER) add_subdirectory(${LIBS_OPEN_PREFIX}llcrashlogger) + add_subdirectory(${LIBS_OPEN_PREFIX}llplugin) add_subdirectory(${LIBS_OPEN_PREFIX}llui) + add_subdirectory(${LIBS_OPEN_PREFIX}llxuixml) + + # viewer media plugins + add_subdirectory(${LIBS_OPEN_PREFIX}media_plugins) + + # llplugin testbed code (is this the right way to include it?) + if (NOT LINUX) + add_subdirectory(${VIEWER_PREFIX}test_apps/llplugintest) + endif (NOT LINUX) if (LINUX) add_subdirectory(${VIEWER_PREFIX}linux_crash_logger) - add_dependencies(viewer linux-crash-logger-strip-target) + add_subdirectory(${VIEWER_PREFIX}linux_updater) + add_dependencies(viewer linux-crash-logger-strip-target linux-updater) elseif (DARWIN) add_subdirectory(${VIEWER_PREFIX}mac_crash_logger) add_subdirectory(${VIEWER_PREFIX}mac_updater) @@ -110,3 +121,7 @@ if (SERVER) add_subdirectory(${SERVER_PREFIX}tools) endif (WINDOWS) endif (SERVER) + +# Define after the custom viewer and server targets are created so individual +# apps can add themselves as dependencies +add_subdirectory(${INTEGRATION_TESTS_PREFIX}integration_tests) diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake index ad7529ea0a..2a70263446 100644 --- a/indra/cmake/00-Common.cmake +++ b/indra/cmake/00-Common.cmake @@ -192,7 +192,7 @@ endif (DARWIN) if (LINUX OR DARWIN) - set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor") + set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual") if (NOT GCC_DISABLE_FATAL_WARNINGS) set(GCC_WARNINGS "${GCC_WARNINGS} -Werror") @@ -227,7 +227,6 @@ else (STANDALONE) glib-2.0 gstreamer-0.10 gtk-2.0 - llfreetype2 pango-1.0 ) endif (STANDALONE) diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 658441dab1..3ce393b659 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -34,7 +34,7 @@ set(cmake_SOURCE_FILES FindXmlRpcEpi.cmake FMOD.cmake FreeType.cmake - GStreamer.cmake + GStreamer010Plugin.cmake GooglePerfTools.cmake JPEG.cmake LLAddBuildTest.cmake @@ -48,8 +48,8 @@ set(cmake_SOURCE_FILES LLInventory.cmake LLKDU.cmake LLMath.cmake - LLMedia.cmake LLMessage.cmake + LLPlugin.cmake LLPrimitive.cmake LLRender.cmake LLScene.cmake @@ -60,7 +60,6 @@ set(cmake_SOURCE_FILES LScript.cmake Linking.cmake MonoEmbed.cmake - Mozlib.cmake MySQL.cmake NDOF.cmake OPENAL.cmake @@ -70,7 +69,6 @@ set(cmake_SOURCE_FILES PNG.cmake Python.cmake Prebuilt.cmake - QuickTime.cmake RunBuildTest.cmake TemplateCheck.cmake Tut.cmake diff --git a/indra/cmake/GStreamer010Plugin.cmake b/indra/cmake/GStreamer010Plugin.cmake new file mode 100644 index 0000000000..0d334837d4 --- /dev/null +++ b/indra/cmake/GStreamer010Plugin.cmake @@ -0,0 +1,39 @@ +# -*- cmake -*- +include(Prebuilt) + +if (STANDALONE) + include(FindPkgConfig) + + pkg_check_modules(GSTREAMER010 REQUIRED gstreamer-0.10) + pkg_check_modules(GSTREAMER010_PLUGINS_BASE REQUIRED gstreamer-plugins-base-0.10) +elseif (LINUX) + use_prebuilt_binary(gstreamer) + # possible libxml should have its own .cmake file instead + use_prebuilt_binary(libxml) + set(GSTREAMER010_FOUND ON FORCE BOOL) + set(GSTREAMER010_PLUGINS_BASE_FOUND ON FORCE BOOL) + set(GSTREAMER010_INCLUDE_DIRS + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/gstreamer-0.10 + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/glib-2.0 + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/libxml2 + ) + # We don't need to explicitly link against gstreamer itself, because + # LLMediaImplGStreamer probes for the system's copy at runtime. + set(GSTREAMER010_LIBRARIES + gobject-2.0 + gmodule-2.0 + dl + gthread-2.0 + rt + glib-2.0 + ) +endif (STANDALONE) + +if (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) + set(GSTREAMER010 ON CACHE BOOL "Build with GStreamer-0.10 streaming media support.") +endif (GSTREAMER010_FOUND AND GSTREAMER010_PLUGINS_BASE_FOUND) + +if (GSTREAMER010) + add_definitions(-DLL_GSTREAMER010_ENABLED=1) +endif (GSTREAMER010) + diff --git a/indra/cmake/Glui.cmake b/indra/cmake/Glui.cmake new file mode 100644 index 0000000000..f62a56856c --- /dev/null +++ b/indra/cmake/Glui.cmake @@ -0,0 +1,28 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (STANDALONE) + set(GLUI OFF CACHE BOOL + "GLUI support for the llplugin/llmedia test apps.") +else (STANDALONE) + use_prebuilt_binary(glui) + set(GLUI ON CACHE BOOL + "GLUI support for the llplugin/llmedia test apps.") +endif (STANDALONE) + +if (LINUX) + set(GLUI ON CACHE BOOL + "llplugin media apps HACK for Linux.") +endif (LINUX) + +if (DARWIN OR LINUX) + set(GLUI_LIBRARY + glui) +endif (DARWIN OR LINUX) + +if (WINDOWS) + set(GLUI_LIBRARY + debug glui32.lib + optimized glui32.lib) +endif (WINDOWS) diff --git a/indra/cmake/Glut.cmake b/indra/cmake/Glut.cmake new file mode 100644 index 0000000000..314da30652 --- /dev/null +++ b/indra/cmake/Glut.cmake @@ -0,0 +1,19 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (WINDOWS) + use_prebuilt_binary(freeglut) + set(GLUT_LIBRARY + debug freeglut_static.lib + optimized freeglut_static.lib) +endif (WINDOWS) + +if (LINUX) + FIND_LIBRARY(GLUT_LIBRARY glut) +endif (LINUX) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(GLUT_LIBRARY GLUT) +endif (DARWIN) diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake index aff65cb53e..355ecb58f0 100644 --- a/indra/cmake/GooglePerfTools.cmake +++ b/indra/cmake/GooglePerfTools.cmake @@ -6,9 +6,11 @@ if (STANDALONE) else (STANDALONE) use_prebuilt_binary(google) if (WINDOWS) + use_prebuilt_binary(google-perftools) set(TCMALLOC_LIBRARIES debug libtcmalloc_minimal-debug - optimized libtcmalloc_minimal-debug) + optimized libtcmalloc_minimal) + set(GOOGLE_PERFTOOLS_FOUND "YES") endif (WINDOWS) if (LINUX) set(TCMALLOC_LIBRARIES tcmalloc) @@ -27,6 +29,10 @@ endif (GOOGLE_PERFTOOLS_FOUND) # XXX Disable temporarily, until we have compilation issues on 64-bit # Etch sorted. set(USE_GOOGLE_PERFTOOLS OFF) +if (WINDOWS) + # *TODO -reenable this once we get server usage sorted out + #set(USE_GOOGLE_PERFTOOLS ON) +endif (WINDOWS) if (USE_GOOGLE_PERFTOOLS) set(TCMALLOC_FLAG -DLL_USE_TCMALLOC=1) diff --git a/indra/cmake/LLAddBuildTest.cmake b/indra/cmake/LLAddBuildTest.cmake index 4da0824120..373ad4d4e9 100644 --- a/indra/cmake/LLAddBuildTest.cmake +++ b/indra/cmake/LLAddBuildTest.cmake @@ -157,3 +157,79 @@ INCLUDE(GoogleMock) ADD_DEPENDENCIES(${project} ${project}_tests) ENDMACRO(LL_ADD_PROJECT_UNIT_TESTS) +FUNCTION(LL_ADD_INTEGRATION_TEST + testname + additional_source_files + library_dependencies +# variable args + ) + if(TEST_DEBUG) + message(STATUS "Adding INTEGRATION_TEST_${testname} - debug output is on") + endif(TEST_DEBUG) + + SET(source_files + tests/${testname}_test.cpp + ${CMAKE_SOURCE_DIR}/test/test.cpp + ${CMAKE_SOURCE_DIR}/test/lltut.cpp + ${additional_source_files} + ) + + SET(libraries + ${library_dependencies} + ${PTHREAD_LIBRARY} + ) + + # Add test executable build target + if(TEST_DEBUG) + message(STATUS "ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files})") + endif(TEST_DEBUG) + ADD_EXECUTABLE(INTEGRATION_TEST_${testname} ${source_files}) + + # Add link deps to the executable + if(TEST_DEBUG) + message(STATUS "TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries})") + endif(TEST_DEBUG) + TARGET_LINK_LIBRARIES(INTEGRATION_TEST_${testname} ${libraries}) + + # Create the test running command + SET(test_command ${ARGN}) + GET_TARGET_PROPERTY(TEST_EXE INTEGRATION_TEST_${testname} LOCATION) + LIST(FIND test_command "{}" test_exe_pos) + IF(test_exe_pos LESS 0) + # The {} marker means "the full pathname of the test executable." + # test_exe_pos -1 means we didn't find it -- so append the test executable + # name to $ARGN, the variable part of the arg list. This is convenient + # shorthand for both straightforward execution of the test program (empty + # $ARGN) and for running a "wrapper" program of some kind accepting the + # pathname of the test program as the last of its args. You need specify + # {} only if the test program's pathname isn't the last argument in the + # desired command line. + LIST(APPEND test_command "${TEST_EXE}") + ELSE (test_exe_pos LESS 0) + # Found {} marker at test_exe_pos. Remove the {}... + LIST(REMOVE_AT test_command test_exe_pos) + # ...and replace it with the actual name of the test executable. + LIST(INSERT test_command test_exe_pos "${TEST_EXE}") + ENDIF (test_exe_pos LESS 0) + + SET(TEST_SCRIPT_CMD + ${CMAKE_COMMAND} + -DLD_LIBRARY_PATH=${ARCH_PREBUILT_DIRS}:/usr/lib + -DTEST_CMD:STRING="${test_command}" + -P ${CMAKE_SOURCE_DIR}/cmake/RunBuildTest.cmake + ) + + if(TEST_DEBUG) + message(STATUS "TEST_SCRIPT_CMD: ${TEST_SCRIPT_CMD}") + endif(TEST_DEBUG) + + ADD_CUSTOM_COMMAND( + TARGET INTEGRATION_TEST_${testname} + POST_BUILD + COMMAND ${TEST_SCRIPT_CMD} + ) + + # Use CTEST? Not sure how to yet... + # ADD_TEST(INTEGRATION_TEST_RUNNER_${testname} ${TEST_SCRIPT_CMD}) + +ENDFUNCTION(LL_ADD_INTEGRATION_TEST) \ No newline at end of file diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 410766e4f9..ef202dd879 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -4,6 +4,7 @@ include(APR) include(Boost) include(EXPAT) include(ZLIB) +include(GooglePerfTools) set(LLCOMMON_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llcommon @@ -13,3 +14,6 @@ set(LLCOMMON_INCLUDE_DIRS ) set(LLCOMMON_LIBRARIES llcommon) + +add_definitions(${TCMALLOC_FLAG}) + diff --git a/indra/cmake/LLPlugin.cmake b/indra/cmake/LLPlugin.cmake new file mode 100644 index 0000000000..9722f16c3c --- /dev/null +++ b/indra/cmake/LLPlugin.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- + + +set(LLPLUGIN_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llplugin + ) + +set(LLPLUGIN_LIBRARIES llplugin) diff --git a/indra/cmake/LLXUIXML.cmake b/indra/cmake/LLXUIXML.cmake new file mode 100644 index 0000000000..b8bfe48c77 --- /dev/null +++ b/indra/cmake/LLXUIXML.cmake @@ -0,0 +1,7 @@ +# -*- cmake -*- + +set(LLXUIXML_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/llxuixml + ) + +set(LLXUIXML_LIBRARIES llxuixml) diff --git a/indra/cmake/Linking.cmake b/indra/cmake/Linking.cmake index 2bddb95178..eaa8a6dc29 100644 --- a/indra/cmake/Linking.cmake +++ b/indra/cmake/Linking.cmake @@ -42,6 +42,7 @@ if (WINDOWS) wldap32 gdi32 user32 + dbghelp ) else (WINDOWS) set(WINDOWS_LIBRARIES "") diff --git a/indra/cmake/MediaPluginBase.cmake b/indra/cmake/MediaPluginBase.cmake new file mode 100644 index 0000000000..2be035b641 --- /dev/null +++ b/indra/cmake/MediaPluginBase.cmake @@ -0,0 +1,8 @@ +# -*- cmake -*- + + +set(MEDIA_PLUGIN_BASE_INCLUDE_DIRS + ${LIBS_OPEN_DIR}/media_plugins/base/ + ) + +set(MEDIA_PLUGIN_BASE_LIBRARIES media_plugin_base) diff --git a/indra/cmake/PluginAPI.cmake b/indra/cmake/PluginAPI.cmake new file mode 100644 index 0000000000..d1649e8248 --- /dev/null +++ b/indra/cmake/PluginAPI.cmake @@ -0,0 +1,16 @@ +# -*- cmake -*- + +if (WINDOWS) + set(PLUGIN_API_WINDOWS_LIBRARIES + wsock32 + ws2_32 + psapi + netapi32 + advapi32 + user32 + ) +else (WINDOWS) + set(PLUGIN_API_WINDOWS_LIBRARIES "") +endif (WINDOWS) + + diff --git a/indra/cmake/QuickTimePlugin.cmake b/indra/cmake/QuickTimePlugin.cmake new file mode 100644 index 0000000000..8afd8f304c --- /dev/null +++ b/indra/cmake/QuickTimePlugin.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +if(INSTALL_PROPRIETARY) + include(Prebuilt) + use_prebuilt_binary(quicktime) +endif(INSTALL_PROPRIETARY) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(QUICKTIME_LIBRARY QuickTime) +elseif (WINDOWS) + set(QUICKTIME_SDK_DIR "$ENV{PROGRAMFILES}/QuickTime SDK" + CACHE PATH "Location of the QuickTime SDK.") + + find_library(DEBUG_QUICKTIME_LIBRARY qtmlclient + PATHS + ${ARCH_PREBUILT_DIRS_DEBUG} + "${QUICKTIME_SDK_DIR}\\libraries" + ) + + find_library(RELEASE_QUICKTIME_LIBRARY qtmlclient + PATHS + ${ARCH_PREBUILT_DIRS_RELEASE} + "${QUICKTIME_SDK_DIR}\\libraries" + ) + + if (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) + set(QUICKTIME_LIBRARY + optimized ${RELEASE_QUICKTIME_LIBRARY} + debug ${DEBUG_QUICKTIME_LIBRARY} + ) + + endif (DEBUG_QUICKTIME_LIBRARY AND RELEASE_QUICKTIME_LIBRARY) + + include_directories( + ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include/quicktime + "${QUICKTIME_SDK_DIR}\\CIncludes" + ) +endif (DARWIN) + +mark_as_advanced(QUICKTIME_LIBRARY) + +if (QUICKTIME_LIBRARY) + set(QUICKTIME ON CACHE BOOL "Build with QuickTime streaming media support.") +endif (QUICKTIME_LIBRARY) + diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index 75b66a85da..6559051b5a 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -23,6 +23,7 @@ set(LIBS_SERVER_PREFIX) set(SCRIPTS_PREFIX ../scripts) set(SERVER_PREFIX) set(VIEWER_PREFIX) +set(INTEGRATION_TESTS_PREFIX) set(LIBS_CLOSED_DIR ${CMAKE_SOURCE_DIR}/${LIBS_CLOSED_PREFIX}) set(LIBS_OPEN_DIR ${CMAKE_SOURCE_DIR}/${LIBS_OPEN_PREFIX}) diff --git a/indra/cmake/WebKitLibPlugin.cmake b/indra/cmake/WebKitLibPlugin.cmake new file mode 100644 index 0000000000..9ec23e80ca --- /dev/null +++ b/indra/cmake/WebKitLibPlugin.cmake @@ -0,0 +1,63 @@ +# -*- cmake -*- +include(Linking) +include(Prebuilt) + +if (STANDALONE) + set(WEBKITLIBPLUGIN OFF CACHE BOOL + "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") +else (STANDALONE) + use_prebuilt_binary(llqtwebkit) + set(WEBKITLIBPLUGIN ON CACHE BOOL + "WEBKITLIBPLUGIN support for the llplugin/llmedia test apps.") +endif (STANDALONE) + +if (WINDOWS) + set(WEBKIT_PLUGIN_LIBRARIES + debug llqtwebkitd + debug QtWebKitd4 + debug QtOpenGLd4 + debug QtNetworkd4 + debug QtGuid4 + debug QtCored4 + debug qtmaind + optimized llqtwebkit + optimized QtWebKit4 + optimized QtOpenGL4 + optimized QtNetwork4 + optimized QtGui4 + optimized QtCore4 + optimized qtmain + ) +elseif (DARWIN) + set(WEBKIT_PLUGIN_LIBRARIES + optimized ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib + debug ${ARCH_PREBUILT_DIRS_RELEASE}/libllqtwebkit.dylib + ) +elseif (LINUX) + set(WEBKIT_PLUGIN_LIBRARIES + llqtwebkit + + qgif +# qico + qjpeg +# qpng +# qtiff +# qsvg + +# QtSvg + QtWebKit + QtOpenGL + QtNetwork + QtGui + QtCore + + fontconfig + X11 + Xrender + GL + +# sqlite3 +# Xi +# SM + ) +endif (WINDOWS) diff --git a/indra/develop.py b/indra/develop.py index 39bb48dfa5..249b6519fc 100755 --- a/indra/develop.py +++ b/indra/develop.py @@ -76,6 +76,7 @@ class PlatformSetup(object): build_type = build_types['relwithdebinfo'] standalone = 'OFF' unattended = 'OFF' + universal = 'OFF' project_name = 'SecondLife' distcc = True cmake_opts = [] @@ -419,7 +420,7 @@ class DarwinSetup(UnixSetup): return 'darwin' def arch(self): - if self.unattended == 'ON': + if self.universal == 'ON': return 'universal' else: return UnixSetup.arch(self) @@ -433,11 +434,12 @@ class DarwinSetup(UnixSetup): word_size=self.word_size, unattended=self.unattended, project_name=self.project_name, - universal='', + universal=self.universal, type=self.build_type.upper(), ) - if self.unattended == 'ON': + if self.universal == 'ON': args['universal'] = '-DCMAKE_OSX_ARCHITECTURES:STRING=\'i386;ppc\'' + pass #if simple: # return 'cmake %(opts)s %(dir)r' % args return ('cmake -G %(generator)r ' @@ -676,6 +678,7 @@ Options: --standalone build standalone, without Linden prebuild libraries --unattended build unattended, do not invoke any tools requiring a human response + --universal build a universal binary on Mac OS X (unsupported) -t | --type=NAME build type ("Debug", "Release", or "RelWithDebInfo") -m32 | -m64 build architecture (32-bit or 64-bit) -N | --no-distcc disable use of distcc @@ -721,7 +724,7 @@ def main(arguments): opts, args = getopt.getopt( arguments, '?hNt:p:G:m:', - ['help', 'standalone', 'no-distcc', 'unattended', 'type=', 'incredibuild', 'generator=', 'project=']) + ['help', 'standalone', 'no-distcc', 'unattended', 'universal', 'type=', 'incredibuild', 'generator=', 'project=']) except getopt.GetoptError, err: print >> sys.stderr, 'Error:', err print >> sys.stderr, """ @@ -738,6 +741,8 @@ For example: develop.py configure -DSERVER:BOOL=OFF""" setup.standalone = 'ON' elif o in ('--unattended',): setup.unattended = 'ON' + elif o in ('--universal',): + setup.universal = 'ON' elif o in ('-m',): if a in ('32', '64'): setup.word_size = int(a) diff --git a/indra/integration_tests/CMakeLists.txt b/indra/integration_tests/CMakeLists.txt new file mode 100644 index 0000000000..67e8fbf1f2 --- /dev/null +++ b/indra/integration_tests/CMakeLists.txt @@ -0,0 +1,3 @@ +# -*- cmake -*- + +add_subdirectory(llui_libtest) diff --git a/indra/integration_tests/llui_libtest/CMakeLists.txt b/indra/integration_tests/llui_libtest/CMakeLists.txt new file mode 100644 index 0000000000..1ccdb0f20b --- /dev/null +++ b/indra/integration_tests/llui_libtest/CMakeLists.txt @@ -0,0 +1,103 @@ +# -*- cmake -*- + +# Only set this up for viewer builds, because the llui library is most closely +# related to the viewer +if (VIEWER) + +project (llui_libtest) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLImageJ2COJ) # ugh, needed for images +include(LLMath) +include(LLRender) +include(LLWindow) +include(LLUI) +include(LLVFS) # ugh, needed for LLDir +include(LLXML) +include(LLXUIXML) +include(Linking) +# include(Tut) + +include_directories( + ${FREETYPE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLUI_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} + ) + +set(llui_libtest_SOURCE_FILES + llui_libtest.cpp + llwidgetreg.cpp + ) + +set(llui_libtest_HEADER_FILES + CMakeLists.txt + llui_libtest.h + llwidgetreg.h + ) + +set_source_files_properties(${llui_libtest_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llui_libtest_SOURCE_FILES ${llui_libtest_HEADER_FILES}) + +add_executable(llui_libtest ${llui_libtest_SOURCE_FILES}) + +# Link with OS-specific libraries for LLWindow dependency +if (DARWIN) + find_library(COCOA_LIBRARY Cocoa) + set(OS_LIBRARIES ${COCOA_LIBRARY}) +elseif (WINDOWS) + set(OS_LIBRARIES ${WINDOWS_LIBRARIES}) +elseif (LINUX) + set(OS_LIBRARIES) +else (DARWIN) + message(FATAL_ERROR "unknown platform") +endif (DARWIN) + +# Libraries on which this library depends, needed for Linux builds +# Sort by high-level to low-level +target_link_libraries(llui_libtest + llui + ${OS_LIBRARIES} + ${GOOGLE_PERFTOOLS_LIBRARIES} + ) + +if (WINDOWS) + set_target_properties(llui_libtest + PROPERTIES + LINK_FLAGS "/NODEFAULTLIB:LIBCMT" + LINK_FLAGS_DEBUG "/NODEFAULTLIB:MSVCRT /NODEFAULTLIB:LIBCMTD" + ) + + # Copy over OpenJPEG.dll + # *NOTE: On Windows with VS2005, only the first comment prints + set(OPENJPEG_RELEASE + "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/release/openjpeg.dll") + add_custom_command( TARGET llui_libtest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${OPENJPEG_RELEASE} ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Copying OpenJPEG DLLs to binary directory" + ) + set(OPENJPEG_DEBUG + "${CMAKE_SOURCE_DIR}/../libraries/i686-win32/lib/debug/openjpegd.dll") + add_custom_command( TARGET llui_libtest POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + ${OPENJPEG_DEBUG} ${CMAKE_CURRENT_BINARY_DIR} + ) +endif (WINDOWS) + +# Ensure people working on the viewer don't break this library +# *NOTE: This could be removed, or only built by Parabuild, if the build +# and link times become too long. JC +add_dependencies(viewer llui_libtest) + +endif (VIEWER) diff --git a/indra/integration_tests/llui_libtest/llui_libtest.cpp b/indra/integration_tests/llui_libtest/llui_libtest.cpp new file mode 100644 index 0000000000..3631761c93 --- /dev/null +++ b/indra/integration_tests/llui_libtest/llui_libtest.cpp @@ -0,0 +1,221 @@ +/** + * @file llui_libtest.cpp + * @brief Integration test for the LLUI library + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llui_libtest.h" + +// project includes +#include "llwidgetreg.h" + +// linden library includes +#include "llcontrol.h" // LLControlGroup +#include "lldir.h" +#include "llerrorcontrol.h" +#include "llfloater.h" +#include "llfontfreetype.h" +#include "llfontgl.h" +#include "lltransutil.h" +#include "llui.h" +#include "lluictrlfactory.h" + +#include + +// *TODO: switch to using TUT +// *TODO: teach Parabuild about this program, run automatically after full builds + +// I believe these must be globals, not stack variables. JC +LLControlGroup gSavedSettings("Global"); // saved at end of session +LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session +LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings + +// We can't create LLImageGL objects because we have no window or rendering +// context. Provide enough of an LLUIImage to test the LLUI library without +// an underlying image. +class TestUIImage : public LLUIImage +{ +public: + TestUIImage() + : LLUIImage( std::string(), NULL ) // NULL ImageGL, don't deref! + { } + + /*virtual*/ S32 getWidth() const + { + return 16; + } + + /*virtual*/ S32 getHeight() const + { + return 16; + } +}; + + +class LLTexture ; +// We need to supply dummy images +class TestImageProvider : public LLImageProviderInterface +{ +public: + /*virtual*/ LLPointer getUIImage(const std::string& name) + { + return makeImage(); + } + + /*virtual*/ LLPointer getUIImageByID(const LLUUID& id) + { + return makeImage(); + } + + /*virtual*/ void cleanUp() + { + } + + LLPointer makeImage() + { + LLPointer image_gl; + LLPointer image = new TestUIImage(); //LLUIImage( std::string(), image_gl); + mImageList.push_back(image); + return image; + } + +public: + // Unclear if we need this, hold on to one copy of each image we make + std::vector > mImageList; +}; +TestImageProvider gTestImageProvider; + +static std::string get_xui_dir() +{ + std::string delim = gDirUtilp->getDirDelimiter(); + return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; +} + +void init_llui() +{ + // Font lookup needs directory support +#if LL_DARWIN + const char* newview_path = "../../../../newview"; +#else + const char* newview_path = "../../../newview"; +#endif + gDirUtilp->initAppDirs("SecondLife", newview_path); + gDirUtilp->setSkinFolder("default"); + + // colors are no longer stored in a LLControlGroup file + LLUIColorTable::instance().loadFromSettings(); + + std::string config_filename = gDirUtilp->getExpandedFilename( + LL_PATH_APP_SETTINGS, "settings.xml"); + gSavedSettings.loadFromFile(config_filename); + + // See LLAppViewer::init() + LLUI::settings_map_t settings; + settings["config"] = &gSavedSettings; + settings["ignores"] = &gWarningSettings; + settings["floater"] = &gSavedSettings; + settings["account"] = &gSavedPerAccountSettings; + + // Don't use real images as we don't have a GL context + LLUI::initClass(settings, &gTestImageProvider); + + const bool no_register_widgets = false; + LLWidgetReg::initClass( no_register_widgets ); + + // Unclear if this is needed + LLUI::setupPaths(); + // Otherwise we get translation warnings when setting up floaters + // (tooltips for buttons) + std::set default_args; + LLTransUtil::parseStrings("strings.xml", default_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); + LLFontManager::initClass(); + + // Creating widgets apparently requires fonts to be initialized, + // otherwise it crashes. + LLFontGL::initClass(96.f, 1.f, 1.f, + gDirUtilp->getAppRODataDir(), + LLUI::getXUIPaths(), + false ); // don't create gl textures + + LLFloaterView::Params fvparams; + fvparams.name("Floater View"); + fvparams.rect( LLRect(0,480,640,0) ); + fvparams.mouse_opaque(false); + fvparams.follows.flags(FOLLOWS_ALL); + fvparams.tab_stop(false); + gFloaterView = LLUICtrlFactory::create (fvparams); +} + +void export_test_floaters() +{ + // Convert all test floaters to new XML format + std::string delim = gDirUtilp->getDirDelimiter(); + std::string xui_dir = get_xui_dir() + "en" + delim; + std::string filename; + while (gDirUtilp->getNextFileInDir(xui_dir, "floater_test_*.xml", filename, false)) + { + if (filename.find("_new.xml") != std::string::npos) + { + // don't re-export other test floaters + continue; + } + llinfos << "Converting " << filename << llendl; + // Build a floater and output new attributes + LLXMLNodePtr output_node = new LLXMLNode(); + LLFloater* floater = new LLFloater(LLSD()); + LLUICtrlFactory::getInstance()->buildFloater(floater, + filename, + // FALSE, // don't open floater + output_node); + std::string out_filename = xui_dir + filename; + std::string::size_type extension_pos = out_filename.rfind(".xml"); + out_filename.resize(extension_pos); + out_filename += "_new.xml"; + + llinfos << "Output: " << out_filename << llendl; + LLFILE* floater_file = LLFile::fopen(out_filename.c_str(), "w"); + LLXMLNode::writeHeaderToFile(floater_file); + output_node->writeToFile(floater_file); + fclose(floater_file); + } +} + +int main(int argc, char** argv) +{ + // Must init LLError for llerrs to actually cause errors. + LLError::initForApplication("."); + + init_llui(); + + export_test_floaters(); + + return 0; +} diff --git a/indra/integration_tests/llui_libtest/llui_libtest.h b/indra/integration_tests/llui_libtest/llui_libtest.h new file mode 100644 index 0000000000..a84d57dba9 --- /dev/null +++ b/indra/integration_tests/llui_libtest/llui_libtest.h @@ -0,0 +1,36 @@ +/** + * @file llui_libtest.h + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLUI_LIBTEST_H +#define LLUI_LIBTEST_H + +// TODO + +#endif diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.cpp b/indra/integration_tests/llui_libtest/llwidgetreg.cpp new file mode 100644 index 0000000000..5a97f2aefd --- /dev/null +++ b/indra/integration_tests/llui_libtest/llwidgetreg.cpp @@ -0,0 +1,108 @@ +/** + * @file llwidgetreg.cpp + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llwidgetreg.h" + +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llcontainerview.h" +#include "lliconctrl.h" +#include "llmenugl.h" +#include "llmultislider.h" +#include "llmultisliderctrl.h" +#include "llprogressbar.h" +#include "llradiogroup.h" +#include "llsearcheditor.h" +#include "llscrollcontainer.h" +#include "llscrollingpanellist.h" +#include "llscrolllistctrl.h" +#include "llslider.h" +#include "llsliderctrl.h" +#include "llspinctrl.h" +#include "llstatview.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "llflyoutbutton.h" +#include "llfiltereditor.h" +#include "lllayoutstack.h" + +void LLWidgetReg::initClass(bool register_widgets) +{ + // Only need to register if the Windows linker has optimized away the + // references to the object files. + if (register_widgets) + { + LLDefaultChildRegistry::Register button("button"); + LLDefaultChildRegistry::Register check_box("check_box"); + LLDefaultChildRegistry::Register combo_box("combo_box"); + LLDefaultChildRegistry::Register filter_editor("filter_editor"); + LLDefaultChildRegistry::Register flyout_button("flyout_button"); + LLDefaultChildRegistry::Register container_view("container_view"); + LLDefaultChildRegistry::Register icon("icon"); + LLDefaultChildRegistry::Register line_editor("line_editor"); + LLDefaultChildRegistry::Register menu_item_separator("menu_item_separator"); + LLDefaultChildRegistry::Register menu_item_call_gl("menu_item_call"); + LLDefaultChildRegistry::Register menu_item_check_gl("menu_item_check"); + LLDefaultChildRegistry::Register menu("menu"); + LLDefaultChildRegistry::Register menu_bar("menu_bar"); + LLDefaultChildRegistry::Register context_menu("context_menu"); + LLDefaultChildRegistry::Register multi_slider_bar("multi_slider_bar"); + LLDefaultChildRegistry::Register multi_slider("multi_slider"); + LLDefaultChildRegistry::Register panel("panel", &LLPanel::fromXML); + LLDefaultChildRegistry::Register layout_stack("layout_stack", &LLLayoutStack::fromXML); + LLDefaultChildRegistry::Register progress_bar("progress_bar"); + LLDefaultChildRegistry::Register radio_group("radio_group"); + LLDefaultChildRegistry::Register radio_item("radio_item"); + LLDefaultChildRegistry::Register search_editor("search_editor"); + LLDefaultChildRegistry::Register scroll_container("scroll_container"); + LLDefaultChildRegistry::Register scrolling_panel_list("scrolling_panel_list"); + LLDefaultChildRegistry::Register scroll_list("scroll_list"); + LLDefaultChildRegistry::Register slider_bar("slider_bar"); + LLDefaultChildRegistry::Register slider("slider"); + LLDefaultChildRegistry::Register spinner("spinner"); + LLDefaultChildRegistry::Register stat_bar("stat_bar"); + //LLDefaultChildRegistry::Register placeholder("placeholder"); + LLDefaultChildRegistry::Register tab_container("tab_container"); + LLDefaultChildRegistry::Register text("text"); + LLDefaultChildRegistry::Register simple_text_editor("simple_text_editor"); + LLDefaultChildRegistry::Register ui_ctrl("ui_ctrl"); + LLDefaultChildRegistry::Register stat_view("stat_view"); + //LLDefaultChildRegistry::Register locate("locate"); + //LLDefaultChildRegistry::Register pad("pad"); + LLDefaultChildRegistry::Register view_border("view_border"); + } + + // *HACK: Usually this is registered as a viewer text editor + LLDefaultChildRegistry::Register text_editor("text_editor"); +} diff --git a/indra/integration_tests/llui_libtest/llwidgetreg.h b/indra/integration_tests/llui_libtest/llwidgetreg.h new file mode 100644 index 0000000000..4e0bc5377a --- /dev/null +++ b/indra/integration_tests/llui_libtest/llwidgetreg.h @@ -0,0 +1,43 @@ +/** + * @file llwidgetreg.h + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLWIDGETREG_H +#define LLWIDGETREG_H + +// Register all widgets with the builder registry. +// Useful on Windows where linker discards all references to the +// static LLDefaultChildRegistry::Register<> calls. +class LLWidgetReg +{ +public: + static void initClass(bool register_widgets); +}; + +#endif diff --git a/indra/linux_updater/CMakeLists.txt b/indra/linux_updater/CMakeLists.txt new file mode 100644 index 0000000000..9fe32ecb46 --- /dev/null +++ b/indra/linux_updater/CMakeLists.txt @@ -0,0 +1,58 @@ +# -*- cmake -*- + +project(linux_updater) + +include(00-Common) +include(CURL) +include(CARes) +include(OpenSSL) +include(UI) +include(LLCommon) +include(LLVFS) +include(LLXML) +include(LLXUIXML) +include(Linking) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLVFS_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} + ${CURL_INCLUDE_DIRS} + ${CARES_INCLUDE_DIRS} + ${OPENSSL_INCLUDE_DIRS} + ${UI_INCLUDE_DIRS} + ) + +set(linux_updater_SOURCE_FILES linux_updater.cpp) + +set(linux_updater_HEADER_FILES CMakeLists.txt) + +set_source_files_properties(${linux_updater_HEADER_FILES} + PROPERTIES HEADER_FILES_ONLY TRUE) + +list(APPEND linux_updater_SOURCE_FILES ${linux_updater_HEADER_FILES}) + +add_executable(linux-updater ${linux_updater_SOURCE_FILES}) + +target_link_libraries(linux-updater + ${CURL_LIBRARIES} + ${CARES_LIBRARIES} + ${OPENSSL_LIBRARIES} + ${CRYPTO_LIBRARIES} + ${UI_LIBRARIES} + ${LLXML_LIBRARIES} + ${LLXUIXML_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ) + +add_custom_command( + OUTPUT linux-updater-stripped + COMMAND strip + ARGS --strip-debug -o linux-updater-stripped linux-updater + DEPENDS linux-updater + ) + +add_custom_target(linux-updater-strip-target ALL + DEPENDS linux-updater-stripped) diff --git a/indra/linux_updater/linux_updater.cpp b/indra/linux_updater/linux_updater.cpp new file mode 100644 index 0000000000..b93890ab32 --- /dev/null +++ b/indra/linux_updater/linux_updater.cpp @@ -0,0 +1,818 @@ +/** + * @file linux_updater.cpp + * @author Kyle Ambroff , Tofu Linden + * @brief Viewer update program for unix platforms that support GTK+ + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include +#include +#include + +#include "linden_common.h" +#include "llerrorcontrol.h" +#include "llfile.h" +#include "lldir.h" +#include "llxmlnode.h" +#include "lltrans.h" + +#include + +extern "C" { +#include +} + +const guint UPDATE_PROGRESS_TIMEOUT = 100; +const guint UPDATE_PROGRESS_TEXT_TIMEOUT = 1000; +const guint ROTATE_IMAGE_TIMEOUT = 8000; + +typedef struct _updater_app_state { + std::string app_name; + std::string url; + std::string image_dir; + std::string dest_dir; + std::string strings_dirs; + std::string strings_file; + + GtkWidget *window; + GtkWidget *progress_bar; + GtkWidget *image; + + double progress_value; + bool activity_mode; + + guint image_rotation_timeout_id; + guint progress_update_timeout_id; + guint update_progress_text_timeout_id; + + bool failure; +} UpdaterAppState; + +// List of entries from strings.xml to always replace +static std::set default_trans_args; +void init_default_trans_args() +{ + default_trans_args.insert("SECOND_LIFE"); // World + default_trans_args.insert("SECOND_LIFE_VIEWER"); + default_trans_args.insert("SECOND_LIFE_GRID"); + default_trans_args.insert("SECOND_LIFE_SUPPORT"); +} + +bool translate_init(std::string comma_delim_path_list, + std::string base_xml_name) +{ + init_default_trans_args(); + + // extract paths string vector from comma-delimited flat string + std::vector paths; + LLStringUtil::getTokens(comma_delim_path_list, paths); // split over ',' + + // suck the translation xml files into memory + LLXMLNodePtr root; + bool success = LLXMLNode::getLayeredXMLNode(base_xml_name, root, paths); + if (!success) + { + // couldn't load string table XML + return false; + } + else + { + // get those strings out of the XML + LLTrans::parseStrings(root, default_trans_args); + return true; + } +} + + +void updater_app_ui_init(void); +void updater_app_quit(UpdaterAppState *app_state); +void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state); +std::string next_image_filename(std::string& image_path); +void display_error(GtkWidget *parent, std::string title, std::string message); +BOOL install_package(std::string package_file, std::string destination); +BOOL spawn_viewer(UpdaterAppState *app_state); + +extern "C" { + void on_window_closed(GtkWidget *sender, gpointer state); + gpointer worker_thread_cb(gpointer *data); + int download_progress_cb(gpointer data, double t, double d, double utotal, double ulnow); + gboolean rotate_image_cb(gpointer data); + gboolean progress_update_timeout(gpointer data); + gboolean update_progress_text_timeout(gpointer data); +} + +void updater_app_ui_init(UpdaterAppState *app_state) +{ + GtkWidget *vbox; + GtkWidget *summary_label; + GtkWidget *description_label; + GtkWidget *frame; + + llassert(app_state != NULL); + + // set up window and main container + std::string window_title = LLTrans::getString("UpdaterWindowTitle"); + app_state->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(app_state->window), + window_title.c_str()); + gtk_window_set_resizable(GTK_WINDOW(app_state->window), FALSE); + gtk_window_set_position(GTK_WINDOW(app_state->window), + GTK_WIN_POS_CENTER_ALWAYS); + + gtk_container_set_border_width(GTK_CONTAINER(app_state->window), 12); + g_signal_connect(G_OBJECT(app_state->window), "delete-event", + G_CALLBACK(on_window_closed), app_state); + + vbox = gtk_vbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(app_state->window), vbox); + + // set top label + std::ostringstream label_ostr; + label_ostr << "" + << LLTrans::getString("UpdaterNowUpdating") + << ""; + + summary_label = gtk_label_new(NULL); + gtk_label_set_use_markup(GTK_LABEL(summary_label), TRUE); + gtk_label_set_markup(GTK_LABEL(summary_label), + label_ostr.str().c_str()); + gtk_misc_set_alignment(GTK_MISC(summary_label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(vbox), summary_label, FALSE, FALSE, 0); + + // create the description label + description_label = gtk_label_new(LLTrans::getString("UpdaterUpdatingDescriptive").c_str()); + gtk_label_set_line_wrap(GTK_LABEL(description_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(description_label), 0, 0.5); + gtk_box_pack_start(GTK_BOX(vbox), description_label, FALSE, FALSE, 0); + + // If an image path has been set, load the background images + if (!app_state->image_dir.empty()) { + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); + gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); + + // load the first image + app_state->image = gtk_image_new_from_file + (next_image_filename(app_state->image_dir).c_str()); + gtk_widget_set_size_request(app_state->image, 340, 310); + gtk_container_add(GTK_CONTAINER(frame), app_state->image); + + // rotate the images every 5 seconds + app_state->image_rotation_timeout_id = g_timeout_add + (ROTATE_IMAGE_TIMEOUT, rotate_image_cb, app_state); + } + + // set up progress bar, and update it roughly every 1/10 of a second + app_state->progress_bar = gtk_progress_bar_new(); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(app_state->progress_bar), + LLTrans::getString("UpdaterProgressBarTextWithEllipses").c_str()); + gtk_box_pack_start(GTK_BOX(vbox), + app_state->progress_bar, FALSE, TRUE, 0); + app_state->progress_update_timeout_id = g_timeout_add + (UPDATE_PROGRESS_TIMEOUT, progress_update_timeout, app_state); + app_state->update_progress_text_timeout_id = g_timeout_add + (UPDATE_PROGRESS_TEXT_TIMEOUT, update_progress_text_timeout, app_state); + + gtk_widget_show_all(app_state->window); +} + +gboolean rotate_image_cb(gpointer data) +{ + UpdaterAppState *app_state; + std::string filename; + + llassert(data != NULL); + app_state = (UpdaterAppState *) data; + + filename = next_image_filename(app_state->image_dir); + + gdk_threads_enter(); + gtk_image_set_from_file(GTK_IMAGE(app_state->image), filename.c_str()); + gdk_threads_leave(); + + return TRUE; +} + +std::string next_image_filename(std::string& image_path) +{ + std::string image_filename; + gDirUtilp->getNextFileInDir(image_path, "/*.jpg", image_filename, true); + return image_path + "/" + image_filename; +} + +void on_window_closed(GtkWidget *sender, gpointer data) +{ + UpdaterAppState *app_state; + + llassert(data != NULL); + app_state = (UpdaterAppState *) data; + + updater_app_quit(app_state); +} + +void updater_app_quit(UpdaterAppState *app_state) +{ + if (app_state != NULL) + { + g_source_remove(app_state->progress_update_timeout_id); + + if (!app_state->image_dir.empty()) + { + g_source_remove(app_state->image_rotation_timeout_id); + } + } + + gtk_main_quit(); +} + +void display_error(GtkWidget *parent, std::string title, std::string message) +{ + GtkWidget *dialog; + + dialog = gtk_message_dialog_new(GTK_WINDOW(parent), + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + "%s", message.c_str()); + gtk_window_set_title(GTK_WINDOW(dialog), title.c_str()); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +gpointer worker_thread_cb(gpointer data) +{ + UpdaterAppState *app_state; + CURL *curl; + CURLcode result; + FILE *package_file; + GError *error = NULL; + char *tmp_filename = NULL; + int fd; + + //g_return_val_if_fail (data != NULL, NULL); + app_state = (UpdaterAppState *) data; + + try { + // create temporary file to store the package. + fd = g_file_open_tmp + ("secondlife-update-XXXXXX", &tmp_filename, &error); + if (error != NULL) + { + llerrs << "Unable to create temporary file: " + << error->message + << llendl; + + g_error_free(error); + throw 0; + } + + package_file = fdopen(fd, "wb"); + if (package_file == NULL) + { + llerrs << "Failed to create temporary file: " + << tmp_filename + << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + throw 0; + } + + // initialize curl and start downloading the package + llinfos << "Downloading package: " << app_state->url << llendl; + + curl = curl_easy_init(); + if (curl == NULL) + { + llerrs << "Failed to initialize libcurl" << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + throw 0; + } + + curl_easy_setopt(curl, CURLOPT_URL, app_state->url.c_str()); + curl_easy_setopt(curl, CURLOPT_NOSIGNAL, TRUE); + curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, TRUE); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, package_file); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, + &download_progress_cb); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, app_state); + + result = curl_easy_perform(curl); + fclose(package_file); + curl_easy_cleanup(curl); + + if (result) + { + llerrs << "Failed to download update: " + << app_state->url + << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailDownloadTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + + throw 0; + } + + // now pulse the progres bar back and forth while the package is + // being unpacked + gdk_threads_enter(); + std::string installing_msg = LLTrans::getString("UpdaterNowInstalling"); + gtk_progress_bar_set_text( + GTK_PROGRESS_BAR(app_state->progress_bar), + installing_msg.c_str()); + app_state->activity_mode = TRUE; + gdk_threads_leave(); + + // *TODO: if the destination is not writable, terminate this + // thread and show file chooser? + if (!install_package(tmp_filename, app_state->dest_dir)) + { + llwarns << "Failed to install package to destination: " + << app_state->dest_dir + << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailInstallTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + //"Failed to update " + app_state->app_name, + gdk_threads_leave(); + throw 0; + } + + // try to spawn the new viewer + if (!spawn_viewer(app_state)) + { + llwarns << "Viewer was not installed properly in : " + << app_state->dest_dir + << llendl; + + gdk_threads_enter(); + display_error(app_state->window, + LLTrans::getString("UpdaterFailStartTitle"), + LLTrans::getString("UpdaterFailUpdateDescriptive")); + gdk_threads_leave(); + throw 0; + } + } + catch (...) + { + app_state->failure = TRUE; + } + + // FIXME: delete package file also if delete-event is raised on window + if (tmp_filename != NULL) + { + if (gDirUtilp->fileExists(tmp_filename)) + { + LLFile::remove(tmp_filename); + } + } + + gdk_threads_enter(); + updater_app_quit(app_state); + gdk_threads_leave(); + + return NULL; +} + + +gboolean less_anal_gspawnsync(gchar **argv, + gchar **stderr_output, + gint *child_exit_status, + GError **spawn_error) +{ + // store current SIGCHLD handler if there is one, replace with default + // handler to make glib happy + struct sigaction sigchld_backup; + struct sigaction sigchld_appease_glib; + sigchld_appease_glib.sa_handler = SIG_DFL; + sigemptyset(&sigchld_appease_glib.sa_mask); + sigchld_appease_glib.sa_flags = 0; + sigaction(SIGCHLD, &sigchld_appease_glib, &sigchld_backup); + + gboolean rtn = g_spawn_sync(NULL, + argv, + NULL, + (GSpawnFlags) (G_SPAWN_STDOUT_TO_DEV_NULL), + NULL, + NULL, + NULL, + stderr_output, + child_exit_status, + spawn_error); + + // restore SIGCHLD handler + sigaction(SIGCHLD, &sigchld_backup, NULL); + + return rtn; +} + + +// perform a rename, or perform a (prompted) root rename if that fails +int +rename_with_sudo_fallback(const std::string& filename, const std::string& newname) +{ + int rtncode = ::rename(filename.c_str(), newname.c_str()); + lldebugs << "rename result is: " << rtncode << " / " << errno << llendl; + if (rtncode && (EACCES == errno || EPERM == errno || EXDEV == errno)) + { + llinfos << "Permission problem in rename, or moving between different mount points. Retrying as a mv under a sudo." << llendl; + // failed due to permissions, try again as a gksudo or kdesu mv wrapper hack + char *sudo_cmd = NULL; + sudo_cmd = g_find_program_in_path("gksudo"); + if (!sudo_cmd) + { + sudo_cmd = g_find_program_in_path("kdesu"); + } + if (sudo_cmd) + { + char *mv_cmd = NULL; + mv_cmd = g_find_program_in_path("mv"); + if (mv_cmd) + { + char *src_string_copy = g_strdup(filename.c_str()); + char *dst_string_copy = g_strdup(newname.c_str()); + char* argv[] = + { + sudo_cmd, + mv_cmd, + src_string_copy, + dst_string_copy, + NULL + }; + + gchar *stderr_output = NULL; + gint child_exit_status = 0; + GError *spawn_error = NULL; + if (!less_anal_gspawnsync(argv, &stderr_output, + &child_exit_status, &spawn_error)) + { + llwarns << "Failed to spawn child process: " + << spawn_error->message + << llendl; + } + else if (child_exit_status) + { + llwarns << "mv command failed: " + << (stderr_output ? stderr_output : "(no reason given)") + << llendl; + } + else + { + // everything looks good, clear the error code + rtncode = 0; + } + + g_free(src_string_copy); + g_free(dst_string_copy); + if (spawn_error) g_error_free(spawn_error); + } + } + } + return rtncode; +} + +gboolean install_package(std::string package_file, std::string destination) +{ + char *tar_cmd = NULL; + std::ostringstream command; + + // Find the absolute path to the 'tar' command. + tar_cmd = g_find_program_in_path("tar"); + if (!tar_cmd) + { + llerrs << "`tar' was not found in $PATH" << llendl; + return FALSE; + } + llinfos << "Found tar command: " << tar_cmd << llendl; + + // Unpack the tarball in a temporary place first, then move it to + // its final destination + std::string tmp_dest_dir = gDirUtilp->getTempFilename(); + if (LLFile::mkdir(tmp_dest_dir, 0744)) + { + llerrs << "Failed to create directory: " + << destination + << llendl; + + return FALSE; + } + + char *package_file_string_copy = g_strdup(package_file.c_str()); + char *tmp_dest_dir_string_copy = g_strdup(tmp_dest_dir.c_str()); + gchar *argv[8] = { + tar_cmd, + const_cast("--strip"), const_cast("1"), + const_cast("-xjf"), + package_file_string_copy, + const_cast("-C"), tmp_dest_dir_string_copy, + NULL, + }; + + llinfos << "Untarring package: " << package_file << llendl; + + // store current SIGCHLD handler if there is one, replace with default + // handler to make glib happy + struct sigaction sigchld_backup; + struct sigaction sigchld_appease_glib; + sigchld_appease_glib.sa_handler = SIG_DFL; + sigemptyset(&sigchld_appease_glib.sa_mask); + sigchld_appease_glib.sa_flags = 0; + sigaction(SIGCHLD, &sigchld_appease_glib, &sigchld_backup); + + gchar *stderr_output = NULL; + gint child_exit_status = 0; + GError *untar_error = NULL; + if (!less_anal_gspawnsync(argv, &stderr_output, + &child_exit_status, &untar_error)) + { + llwarns << "Failed to spawn child process: " + << untar_error->message + << llendl; + return FALSE; + } + + if (child_exit_status) + { + llwarns << "Untar command failed: " + << (stderr_output ? stderr_output : "(no reason given)") + << llendl; + return FALSE; + } + + g_free(tar_cmd); + g_free(package_file_string_copy); + g_free(tmp_dest_dir_string_copy); + g_free(stderr_output); + if (untar_error) g_error_free(untar_error); + + // move the existing package out of the way if it exists + if (gDirUtilp->fileExists(destination)) + { + std::string backup_dir = destination + ".backup"; + int oldcounter = 1; + while (gDirUtilp->fileExists(backup_dir)) + { + // find a foo.backup.N folder name that isn't taken yet + backup_dir = destination + ".backup." + llformat("%d", oldcounter); + ++oldcounter; + } + + if (rename_with_sudo_fallback(destination, backup_dir)) + { + llwarns << "Failed to move directory: '" + << destination << "' -> '" << backup_dir + << llendl; + return FALSE; + } + } + + // The package has been unpacked in a staging directory, now we just + // need to move it to its destination. + if (rename_with_sudo_fallback(tmp_dest_dir, destination)) + { + llwarns << "Failed to move installation to the destination: " + << destination + << llendl; + return FALSE; + } + + // \0/ Success! + return TRUE; +} + +gboolean progress_update_timeout(gpointer data) +{ + UpdaterAppState *app_state; + + llassert(data != NULL); + + app_state = (UpdaterAppState *) data; + + gdk_threads_enter(); + if (app_state->activity_mode) + { + gtk_progress_bar_pulse + (GTK_PROGRESS_BAR(app_state->progress_bar)); + } + else + { + gtk_progress_set_value(GTK_PROGRESS(app_state->progress_bar), + app_state->progress_value); + } + gdk_threads_leave(); + + return TRUE; +} + +gboolean update_progress_text_timeout(gpointer data) +{ + UpdaterAppState *app_state; + + llassert(data != NULL); + app_state = (UpdaterAppState *) data; + + if (app_state->activity_mode == TRUE) + { + // We no longer need this timeout, it will be removed. + return FALSE; + } + + if (!app_state->progress_value) + { + return TRUE; + } + + std::string progress_text = llformat((LLTrans::getString("UpdaterProgressBarText")+" (%.0f%%)").c_str(), app_state->progress_value); + + gdk_threads_enter(); + gtk_progress_bar_set_text(GTK_PROGRESS_BAR(app_state->progress_bar), + progress_text.c_str()); + gdk_threads_leave(); + + return TRUE; +} + +int download_progress_cb(gpointer data, + double t, + double d, + double utotal, + double ulnow) +{ + UpdaterAppState *app_state; + + llassert(data != NULL); + app_state = (UpdaterAppState *) data; + + if (t <= 0.0) + { + app_state->progress_value = 0; + } + else + { + app_state->progress_value = d * 100.0 / t; + } + return 0; +} + +BOOL spawn_viewer(UpdaterAppState *app_state) +{ + llassert(app_state != NULL); + + std::string cmd = app_state->dest_dir + "/secondlife"; + GError *error = NULL; + + // We want to spawn the Viewer on the same display as the updater app + gboolean success = gdk_spawn_command_line_on_screen + (gtk_widget_get_screen(app_state->window), cmd.c_str(), &error); + + if (!success) + { + llwarns << "Failed to launch viewer: " << error->message + << llendl; + } + + if (error) g_error_free(error); + + return success; +} + +void show_usage_and_exit() +{ + std::cout << "Usage: linux-updater --url URL --name NAME --dest PATH --stringsdir PATH1,PATH2 --stringsfile FILE" + << "[--image-dir PATH]" + << std::endl; + exit(1); +} + +void parse_args_and_init(int argc, char **argv, UpdaterAppState *app_state) +{ + int i; + + for (i = 1; i < argc; i++) + { + if ((!strcmp(argv[i], "--url")) && (++i < argc)) + { + app_state->url = argv[i]; + } + else if ((!strcmp(argv[i], "--name")) && (++i < argc)) + { + app_state->app_name = argv[i]; + } + else if ((!strcmp(argv[i], "--image-dir")) && (++i < argc)) + { + app_state->image_dir = argv[i]; + } + else if ((!strcmp(argv[i], "--dest")) && (++i < argc)) + { + app_state->dest_dir = argv[i]; + } + else if ((!strcmp(argv[i], "--stringsdir")) && (++i < argc)) + { + app_state->strings_dirs = argv[i]; + } + else if ((!strcmp(argv[i], "--stringsfile")) && (++i < argc)) + { + app_state->strings_file = argv[i]; + } + else + { + // show usage, an invalid option was given. + show_usage_and_exit(); + } + } + + if (app_state->app_name.empty() + || app_state->url.empty() + || app_state->dest_dir.empty()) + { + show_usage_and_exit(); + } + + app_state->progress_value = 0.0; + app_state->activity_mode = FALSE; + app_state->failure = FALSE; + + translate_init(app_state->strings_dirs, app_state->strings_file); +} + +int main(int argc, char **argv) +{ + UpdaterAppState app_state; + GThread *worker_thread; + + parse_args_and_init(argc, argv, &app_state); + + // Initialize logger, and rename old log file + gDirUtilp->initAppDirs("SecondLife"); + LLError::initForApplication + (gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "")); + std::string old_log_file = gDirUtilp->getExpandedFilename + (LL_PATH_LOGS, "updater.log.old"); + std::string log_file = + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "updater.log"); + LLFile::rename(log_file, old_log_file); + LLError::logToFile(log_file); + + // initialize gthreads and gtk+ + if (!g_thread_supported()) + { + g_thread_init(NULL); + gdk_threads_init(); + } + + gtk_init(&argc, &argv); + + // create UI + updater_app_ui_init(&app_state); + + //llinfos << "SAMPLE TRANSLATION IS: " << LLTrans::getString("LoginInProgress") << llendl; + + // create download thread + worker_thread = g_thread_create + (GThreadFunc(worker_thread_cb), &app_state, FALSE, NULL); + + gdk_threads_enter(); + gtk_main(); + gdk_threads_leave(); + + return (app_state.failure == FALSE) ? 0 : 1; +} diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 235248ee73..80245fd569 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,15 +4,16 @@ project(llaudio) include(00-Common) include(Audio) +include(LLAudio) include(FMOD) include(OPENAL) include(LLCommon) include(LLMath) include(LLMessage) include(LLVFS) -include(LLMedia) include_directories( + ${LLAUDIO_INCLUDE_DIRS} ${FMOD_INCLUDE_DIR} ${LLCOMMON_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} @@ -24,42 +25,43 @@ include_directories( ${VORBIS_INCLUDE_DIRS} ${OPENAL_LIB_INCLUDE_DIRS} ${FREEAULT_LIB_INCLUDE_DIRS} - ${LLMEDIA_INCLUDE_DIRS} ) set(llaudio_SOURCE_FILES - audioengine.cpp - listener.cpp + llaudioengine.cpp + lllistener.cpp llaudiodecodemgr.cpp - vorbisdecode.cpp - vorbisencode.cpp + llvorbisdecode.cpp + llvorbisencode.cpp ) set(llaudio_HEADER_FILES CMakeLists.txt - audioengine.h - listener.h + llaudioengine.h + lllistener.h llaudiodecodemgr.h - vorbisdecode.h - vorbisencode.h - windgen.h + llvorbisdecode.h + llvorbisencode.h + llwindgen.h ) if (FMOD) list(APPEND llaudio_SOURCE_FILES - audioengine_fmod.cpp - listener_fmod.cpp + llaudioengine_fmod.cpp + lllistener_fmod.cpp + llstreamingaudio_fmod.cpp ) list(APPEND llaudio_HEADER_FILES - audioengine_fmod.h - listener_fmod.h + llaudioengine_fmod.h + lllistener_fmod.h + llstreamingaudio_fmod.h ) if (LINUX) if (${CXX_VERSION} MATCHES "4.[23]") - set_source_files_properties(audioengine_fmod.cpp + set_source_files_properties(llaudioengine_fmod.cpp COMPILE_FLAGS -Wno-error=write-strings) endif (${CXX_VERSION} MATCHES "4.[23]") endif (LINUX) @@ -67,13 +69,13 @@ endif (FMOD) if (OPENAL) list(APPEND llaudio_SOURCE_FILES - audioengine_openal.cpp - listener_openal.cpp + llaudioengine_openal.cpp + lllistener_openal.cpp ) list(APPEND llaudio_HEADER_FILES - audioengine_openal.h - listener_openal.h + llaudioengine_openal.h + lllistener_openal.h ) endif (OPENAL) diff --git a/indra/llaudio/llaudiodecodemgr.cpp b/indra/llaudio/llaudiodecodemgr.cpp index 5b6db3bd87..099c4eba40 100644 --- a/indra/llaudio/llaudiodecodemgr.cpp +++ b/indra/llaudio/llaudiodecodemgr.cpp @@ -33,15 +33,15 @@ #include "llaudiodecodemgr.h" -#include "vorbisdecode.h" -#include "audioengine.h" +#include "llvorbisdecode.h" +#include "llaudioengine.h" #include "lllfsthread.h" #include "llvfile.h" #include "llstring.h" #include "lldir.h" #include "llendianswizzle.h" -#include "audioengine.h" #include "llassetstorage.h" +#include "llrefcount.h" #include "vorbis/codec.h" #include "vorbis/vorbisfile.h" diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp new file mode 100644 index 0000000000..a28c94d00d --- /dev/null +++ b/indra/llaudio/llaudioengine.cpp @@ -0,0 +1,1751 @@ + /** + * @file audioengine.cpp + * @brief implementation of LLAudioEngine class abstracting the Open + * AL audio support + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llaudioengine.h" +#include "llstreamingaudio.h" + +#include "llerror.h" +#include "llmath.h" + +#include "sound_ids.h" // temporary hack for min/max distances + +#include "llvfs.h" +#include "lldir.h" +#include "llaudiodecodemgr.h" +#include "llassetstorage.h" + + +// necessary for grabbing sounds from sim (implemented in viewer) +extern void request_sound(const LLUUID &sound_guid); + +LLAudioEngine* gAudiop = NULL; + + +// +// LLAudioEngine implementation +// + + +LLAudioEngine::LLAudioEngine() +{ + setDefaults(); +} + + +LLAudioEngine::~LLAudioEngine() +{ +} + +LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl() +{ + return mStreamingAudioImpl; +} + +void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl) +{ + mStreamingAudioImpl = impl; +} + +void LLAudioEngine::setDefaults() +{ + mMaxWindGain = 1.f; + + mListenerp = NULL; + + mMuted = false; + mUserData = NULL; + + mLastStatus = 0; + + mNumChannels = 0; + mEnableWind = false; + + S32 i; + for (i = 0; i < MAX_CHANNELS; i++) + { + mChannels[i] = NULL; + } + for (i = 0; i < MAX_BUFFERS; i++) + { + mBuffers[i] = NULL; + } + + mMasterGain = 1.f; + mNextWindUpdate = 0.f; + + mStreamingAudioImpl = NULL; + + for (U32 i = 0; i < LLAudioEngine::AUDIO_TYPE_COUNT; i++) + mSecondaryGain[i] = 1.0f; +} + + +bool LLAudioEngine::init(const S32 num_channels, void* userdata) +{ + setDefaults(); + + mNumChannels = num_channels; + mUserData = userdata; + + allocateListener(); + + // Initialize the decode manager + gAudioDecodeMgrp = new LLAudioDecodeMgr; + + llinfos << "LLAudioEngine::init() AudioEngine successfully initialized" << llendl; + + return true; +} + + +void LLAudioEngine::shutdown() +{ + // Clean up decode manager + delete gAudioDecodeMgrp; + gAudioDecodeMgrp = NULL; + + // Clean up wind source + cleanupWind(); + + // Clean up audio sources + source_map::iterator iter_src; + for (iter_src = mAllSources.begin(); iter_src != mAllSources.end(); iter_src++) + { + delete iter_src->second; + } + + + // Clean up audio data + data_map::iterator iter_data; + for (iter_data = mAllData.begin(); iter_data != mAllData.end(); iter_data++) + { + delete iter_data->second; + } + + + // Clean up channels + S32 i; + for (i = 0; i < MAX_CHANNELS; i++) + { + delete mChannels[i]; + mChannels[i] = NULL; + } + + // Clean up buffers + for (i = 0; i < MAX_BUFFERS; i++) + { + delete mBuffers[i]; + mBuffers[i] = NULL; + } +} + + +// virtual +void LLAudioEngine::startInternetStream(const std::string& url) +{ + if (mStreamingAudioImpl) + mStreamingAudioImpl->start(url); +} + + +// virtual +void LLAudioEngine::stopInternetStream() +{ + if (mStreamingAudioImpl) + mStreamingAudioImpl->stop(); +} + +// virtual +void LLAudioEngine::pauseInternetStream(int pause) +{ + if (mStreamingAudioImpl) + mStreamingAudioImpl->pause(pause); +} + +// virtual +void LLAudioEngine::updateInternetStream() +{ + if (mStreamingAudioImpl) + mStreamingAudioImpl->update(); +} + +// virtual +int LLAudioEngine::isInternetStreamPlaying() +{ + if (mStreamingAudioImpl) + return mStreamingAudioImpl->isPlaying(); + + return 0; // Stopped +} + + +// virtual +void LLAudioEngine::setInternetStreamGain(F32 vol) +{ + if (mStreamingAudioImpl) + mStreamingAudioImpl->setGain(vol); +} + +// virtual +std::string LLAudioEngine::getInternetStreamURL() +{ + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getURL(); + else return std::string(); +} + + +void LLAudioEngine::updateChannels() +{ + S32 i; + for (i = 0; i < MAX_CHANNELS; i++) + { + if (mChannels[i]) + { + mChannels[i]->updateBuffer(); + mChannels[i]->update3DPosition(); + mChannels[i]->updateLoop(); + } + } +} + +static const F32 default_max_decode_time = .002f; // 2 ms +void LLAudioEngine::idle(F32 max_decode_time) +{ + if (max_decode_time <= 0.f) + { + max_decode_time = default_max_decode_time; + } + + // "Update" all of our audio sources, clean up dead ones. + // Primarily does position updating, cleanup of unused audio sources. + // Also does regeneration of the current priority of each audio source. + + if (getMuted()) + { + setInternalGain(0.f); + } + else + { + setInternalGain(getMasterGain()); + } + + S32 i; + for (i = 0; i < MAX_BUFFERS; i++) + { + if (mBuffers[i]) + { + mBuffers[i]->mInUse = false; + } + } + + F32 max_priority = -1.f; + LLAudioSource *max_sourcep = NULL; // Maximum priority source without a channel + source_map::iterator iter; + for (iter = mAllSources.begin(); iter != mAllSources.end();) + { + LLAudioSource *sourcep = iter->second; + + // Update this source + sourcep->update(); + sourcep->updatePriority(); + + if (sourcep->isDone()) + { + // The source is done playing, clean it up. + delete sourcep; + mAllSources.erase(iter++); + continue; + } + + if (!sourcep->getChannel() && sourcep->getCurrentBuffer()) + { + // We could potentially play this sound if its priority is high enough. + if (sourcep->getPriority() > max_priority) + { + max_priority = sourcep->getPriority(); + max_sourcep = sourcep; + } + } + + // Move on to the next source + iter++; + } + + // Now, do priority-based organization of audio sources. + // All channels used, check priorities. + // Find channel with lowest priority + if (max_sourcep) + { + LLAudioChannel *channelp = getFreeChannel(max_priority); + if (channelp) + { + //llinfos << "Replacing source in channel due to priority!" << llendl; + max_sourcep->setChannel(channelp); + channelp->setSource(max_sourcep); + if (max_sourcep->isSyncSlave()) + { + // A sync slave, it doesn't start playing until it's synced up with the master. + // Flag this channel as waiting for sync, and return true. + channelp->setWaiting(true); + } + else + { + channelp->setWaiting(false); + channelp->play(); + } + } + } + + + // Do this BEFORE we update the channels + // Update the channels to sync up with any changes that the source made, + // such as changing what sound was playing. + updateChannels(); + + // Update queued sounds (switch to next queued data if the current has finished playing) + for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + { + // This is lame, instead of this I could actually iterate through all the sources + // attached to each channel, since only those with active channels + // can have anything interesting happen with their queue? (Maybe not true) + LLAudioSource *sourcep = iter->second; + if (!sourcep->mQueuedDatap) + { + // Nothing queued, so we don't care. + continue; + } + + LLAudioChannel *channelp = sourcep->getChannel(); + if (!channelp) + { + // This sound isn't playing, so we just process move the queue + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Reset the timer so the source doesn't die. + sourcep->mAgeTimer.reset(); + // Make sure we have the buffer set up if we just decoded the data + if (sourcep->mCurrentDatap) + { + updateBufferForData(sourcep->mCurrentDatap); + } + + // Actually play the associated data. + sourcep->setupChannel(); + channelp = sourcep->getChannel(); + if (channelp) + { + channelp->updateBuffer(); + sourcep->getChannel()->play(); + } + continue; + } + else + { + // Check to see if the current sound is done playing, or looped. + if (!channelp->isPlaying()) + { + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Reset the timer so the source doesn't die. + sourcep->mAgeTimer.reset(); + + // Make sure we have the buffer set up if we just decoded the data + if (sourcep->mCurrentDatap) + { + updateBufferForData(sourcep->mCurrentDatap); + } + + // Actually play the associated data. + sourcep->setupChannel(); + channelp->updateBuffer(); + sourcep->getChannel()->play(); + } + else if (sourcep->isLoop()) + { + // It's a loop, we need to check and see if we're done with it. + if (channelp->mLoopedThisFrame) + { + sourcep->mCurrentDatap = sourcep->mQueuedDatap; + sourcep->mQueuedDatap = NULL; + + // Actually, should do a time sync so if we're a loop master/slave + // we don't drift away. + sourcep->setupChannel(); + sourcep->getChannel()->play(); + } + } + } + } + + // Lame, update the channels AGAIN. + // Update the channels to sync up with any changes that the source made, + // such as changing what sound was playing. + updateChannels(); + + // Hack! For now, just use a global sync master; + LLAudioSource *sync_masterp = NULL; + LLAudioChannel *master_channelp = NULL; + F32 max_sm_priority = -1.f; + for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + { + LLAudioSource *sourcep = iter->second; + if (sourcep->isSyncMaster()) + { + if (sourcep->getPriority() > max_sm_priority) + { + sync_masterp = sourcep; + master_channelp = sync_masterp->getChannel(); + max_sm_priority = sourcep->getPriority(); + } + } + } + + if (master_channelp && master_channelp->mLoopedThisFrame) + { + // Synchronize loop slaves with their masters + // Update queued sounds (switch to next queued data if the current has finished playing) + for (iter = mAllSources.begin(); iter != mAllSources.end(); ++iter) + { + LLAudioSource *sourcep = iter->second; + + if (!sourcep->isSyncSlave()) + { + // Not a loop slave, we don't need to do anything + continue; + } + + LLAudioChannel *channelp = sourcep->getChannel(); + if (!channelp) + { + // Not playing, don't need to bother. + continue; + } + + if (!channelp->isPlaying()) + { + // Now we need to check if our loop master has just looped, and + // start playback if that's the case. + if (sync_masterp->getChannel()) + { + channelp->playSynced(master_channelp); + channelp->setWaiting(false); + } + } + } + } + + // Sync up everything that the audio engine needs done. + commitDeferredChanges(); + + // Flush unused buffers that are stale enough + for (i = 0; i < MAX_BUFFERS; i++) + { + if (mBuffers[i]) + { + if (!mBuffers[i]->mInUse && mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > 30.f) + { + //llinfos << "Flushing unused buffer!" << llendl; + mBuffers[i]->mAudioDatap->mBufferp = NULL; + delete mBuffers[i]; + mBuffers[i] = NULL; + } + } + } + + + // Clear all of the looped flags for the channels + for (i = 0; i < MAX_CHANNELS; i++) + { + if (mChannels[i]) + { + mChannels[i]->mLoopedThisFrame = false; + } + } + + // Decode audio files + gAudioDecodeMgrp->processQueue(max_decode_time); + + // Call this every frame, just in case we somehow + // missed picking it up in all the places that can add + // or request new data. + startNextTransfer(); + + updateInternetStream(); +} + + + +bool LLAudioEngine::updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid) +{ + if (!adp) + { + return false; + } + + // Update the audio buffer first - load a sound if we have it. + // Note that this could potentially cause us to waste time updating buffers + // for sounds that actually aren't playing, although this should be mitigated + // by the fact that we limit the number of buffers, and we flush buffers based + // on priority. + if (!adp->getBuffer()) + { + if (adp->hasDecodedData()) + { + adp->load(); + } + else if (adp->hasLocalData()) + { + if (audio_uuid.notNull()) + { + gAudioDecodeMgrp->addDecodeRequest(audio_uuid); + } + } + else + { + return false; + } + } + return true; +} + + +void LLAudioEngine::enableWind(bool enable) +{ + if (enable && (!mEnableWind)) + { + initWind(); + mEnableWind = enable; + } + else if (mEnableWind && (!enable)) + { + mEnableWind = enable; + cleanupWind(); + } +} + + +LLAudioBuffer * LLAudioEngine::getFreeBuffer() +{ + S32 i; + for (i = 0; i < MAX_BUFFERS; i++) + { + if (!mBuffers[i]) + { + mBuffers[i] = createBuffer(); + return mBuffers[i]; + } + } + + + // Grab the oldest unused buffer + F32 max_age = -1.f; + S32 buffer_id = -1; + for (i = 0; i < MAX_BUFFERS; i++) + { + if (mBuffers[i]) + { + if (!mBuffers[i]->mInUse) + { + if (mBuffers[i]->mLastUseTimer.getElapsedTimeF32() > max_age) + { + max_age = mBuffers[i]->mLastUseTimer.getElapsedTimeF32(); + buffer_id = i; + } + } + } + } + + if (buffer_id >= 0) + { + llinfos << "Taking over unused buffer " << buffer_id << llendl; + //llinfos << "Flushing unused buffer!" << llendl; + mBuffers[buffer_id]->mAudioDatap->mBufferp = NULL; + delete mBuffers[buffer_id]; + mBuffers[buffer_id] = createBuffer(); + return mBuffers[buffer_id]; + } + return NULL; +} + + +LLAudioChannel * LLAudioEngine::getFreeChannel(const F32 priority) +{ + S32 i; + for (i = 0; i < mNumChannels; i++) + { + if (!mChannels[i]) + { + // No channel allocated here, use it. + mChannels[i] = createChannel(); + return mChannels[i]; + } + else + { + // Channel is allocated but not playing right now, use it. + if (!mChannels[i]->isPlaying() && !mChannels[i]->isWaiting()) + { + mChannels[i]->cleanup(); + if (mChannels[i]->getSource()) + { + mChannels[i]->getSource()->setChannel(NULL); + } + return mChannels[i]; + } + } + } + + // All channels used, check priorities. + // Find channel with lowest priority and see if we want to replace it. + F32 min_priority = 10000.f; + LLAudioChannel *min_channelp = NULL; + + for (i = 0; i < mNumChannels; i++) + { + LLAudioChannel *channelp = mChannels[i]; + LLAudioSource *sourcep = channelp->getSource(); + if (sourcep->getPriority() < min_priority) + { + min_channelp = channelp; + min_priority = sourcep->getPriority(); + } + } + + if (min_priority > priority || !min_channelp) + { + // All playing channels have higher priority, return. + return NULL; + } + + // Flush the minimum priority channel, and return it. + min_channelp->cleanup(); + min_channelp->getSource()->setChannel(NULL); + return min_channelp; +} + + +void LLAudioEngine::cleanupBuffer(LLAudioBuffer *bufferp) +{ + S32 i; + for (i = 0; i < MAX_BUFFERS; i++) + { + if (mBuffers[i] == bufferp) + { + delete mBuffers[i]; + mBuffers[i] = NULL; + } + } +} + + +bool LLAudioEngine::preloadSound(const LLUUID &uuid) +{ + gAudiop->getAudioData(uuid); // We don't care about the return value, this is just to make sure + // that we have an entry, which will mean that the audio engine knows about this + + if (gAudioDecodeMgrp->addDecodeRequest(uuid)) + { + // This means that we do have a local copy, and we're working on decoding it. + return true; + } + + // At some point we need to have the audio/asset system check the static VFS + // before it goes off and fetches stuff from the server. + //llwarns << "Used internal preload for non-local sound" << llendl; + return false; +} + + +bool LLAudioEngine::isWindEnabled() +{ + return mEnableWind; +} + + +void LLAudioEngine::setMuted(bool muted) +{ + mMuted = muted; + enableWind(!mMuted); +} + + +void LLAudioEngine::setMasterGain(const F32 gain) +{ + mMasterGain = gain; + setInternalGain(gain); +} + +F32 LLAudioEngine::getMasterGain() +{ + return mMasterGain; +} + +void LLAudioEngine::setSecondaryGain(S32 type, F32 gain) +{ + llassert(type < LLAudioEngine::AUDIO_TYPE_COUNT); + + mSecondaryGain[type] = gain; +} + +F32 LLAudioEngine::getSecondaryGain(S32 type) +{ + return mSecondaryGain[type]; +} + +F32 LLAudioEngine::getInternetStreamGain() +{ + if (mStreamingAudioImpl) + return mStreamingAudioImpl->getGain(); + else + return 1.0f; +} + +void LLAudioEngine::setMaxWindGain(F32 gain) +{ + mMaxWindGain = gain; +} + + +F64 LLAudioEngine::mapWindVecToGain(LLVector3 wind_vec) +{ + F64 gain = 0.0; + + gain = wind_vec.magVec(); + + if (gain) + { + if (gain > 20) + { + gain = 20; + } + gain = gain/20.0; + } + + return (gain); +} + + +F64 LLAudioEngine::mapWindVecToPitch(LLVector3 wind_vec) +{ + LLVector3 listen_right; + F64 theta; + + // Wind frame is in listener-relative coordinates + LLVector3 norm_wind = wind_vec; + norm_wind.normVec(); + listen_right.setVec(1.0,0.0,0.0); + + // measure angle between wind vec and listener right axis (on 0,PI) + theta = acos(norm_wind * listen_right); + + // put it on 0, 1 + theta /= F_PI; + + // put it on [0, 0.5, 0] + if (theta > 0.5) theta = 1.0-theta; + if (theta < 0) theta = 0; + + return (theta); +} + + +F64 LLAudioEngine::mapWindVecToPan(LLVector3 wind_vec) +{ + LLVector3 listen_right; + F64 theta; + + // Wind frame is in listener-relative coordinates + listen_right.setVec(1.0,0.0,0.0); + + LLVector3 norm_wind = wind_vec; + norm_wind.normVec(); + + // measure angle between wind vec and listener right axis (on 0,PI) + theta = acos(norm_wind * listen_right); + + // put it on 0, 1 + theta /= F_PI; + + return (theta); +} + + +void LLAudioEngine::triggerSound(const LLUUID &audio_uuid, const LLUUID& owner_id, const F32 gain, + const S32 type, const LLVector3d &pos_global) +{ + // Create a new source (since this can't be associated with an existing source. + //llinfos << "Localized: " << audio_uuid << llendl; + + if (mMuted) + { + return; + } + + LLUUID source_id; + source_id.generate(); + + LLAudioSource *asp = new LLAudioSource(source_id, owner_id, gain, type); + gAudiop->addAudioSource(asp); + if (pos_global.isExactlyZero()) + { + asp->setAmbient(true); + } + else + { + asp->setPositionGlobal(pos_global); + } + asp->updatePriority(); + asp->play(audio_uuid); +} + + +void LLAudioEngine::setListenerPos(LLVector3 aVec) +{ + mListenerp->setPosition(aVec); +} + + +LLVector3 LLAudioEngine::getListenerPos() +{ + if (mListenerp) + { + return(mListenerp->getPosition()); + } + else + { + return(LLVector3::zero); + } +} + + +void LLAudioEngine::setListenerVelocity(LLVector3 aVec) +{ + mListenerp->setVelocity(aVec); +} + + +void LLAudioEngine::translateListener(LLVector3 aVec) +{ + mListenerp->translate(aVec); +} + + +void LLAudioEngine::orientListener(LLVector3 up, LLVector3 at) +{ + mListenerp->orient(up, at); +} + + +void LLAudioEngine::setListener(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) +{ + mListenerp->set(pos,vel,up,at); +} + + +void LLAudioEngine::setDopplerFactor(F32 factor) +{ + if (mListenerp) + { + mListenerp->setDopplerFactor(factor); + } +} + + +F32 LLAudioEngine::getDopplerFactor() +{ + if (mListenerp) + { + return mListenerp->getDopplerFactor(); + } + else + { + return 0.f; + } +} + + +void LLAudioEngine::setRolloffFactor(F32 factor) +{ + if (mListenerp) + { + mListenerp->setRolloffFactor(factor); + } +} + + +F32 LLAudioEngine::getRolloffFactor() +{ + if (mListenerp) + { + return mListenerp->getRolloffFactor(); + } + else + { + return 0.f; + } +} + + +void LLAudioEngine::commitDeferredChanges() +{ + mListenerp->commitDeferredChanges(); +} + + +LLAudioSource * LLAudioEngine::findAudioSource(const LLUUID &source_id) +{ + source_map::iterator iter; + iter = mAllSources.find(source_id); + + if (iter == mAllSources.end()) + { + return NULL; + } + else + { + return iter->second; + } +} + + +LLAudioData * LLAudioEngine::getAudioData(const LLUUID &audio_uuid) +{ + data_map::iterator iter; + iter = mAllData.find(audio_uuid); + if (iter == mAllData.end()) + { + // Create the new audio data + LLAudioData *adp = new LLAudioData(audio_uuid); + mAllData[audio_uuid] = adp; + return adp; + } + else + { + return iter->second; + } +} + +void LLAudioEngine::addAudioSource(LLAudioSource *asp) +{ + mAllSources[asp->getID()] = asp; +} + + +void LLAudioEngine::cleanupAudioSource(LLAudioSource *asp) +{ + source_map::iterator iter; + iter = mAllSources.find(asp->getID()); + if (iter == mAllSources.end()) + { + llwarns << "Cleaning up unknown audio source!" << llendl; + return; + } + delete asp; + mAllSources.erase(iter); +} + + +bool LLAudioEngine::hasDecodedFile(const LLUUID &uuid) +{ + std::string uuid_str; + uuid.toString(uuid_str); + + std::string wav_path; + wav_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str); + wav_path += ".dsf"; + + if (gDirUtilp->fileExists(wav_path)) + { + return true; + } + else + { + return false; + } +} + + +bool LLAudioEngine::hasLocalFile(const LLUUID &uuid) +{ + // See if it's in the VFS. + return gVFS->getExists(uuid, LLAssetType::AT_SOUND); +} + + +void LLAudioEngine::startNextTransfer() +{ + //llinfos << "LLAudioEngine::startNextTransfer()" << llendl; + if (mCurrentTransfer.notNull() || getMuted()) + { + //llinfos << "Transfer in progress, aborting" << llendl; + return; + } + + // Get the ID for the next asset that we want to transfer. + // Pick one in the following order: + LLUUID asset_id; + S32 i; + LLAudioSource *asp = NULL; + LLAudioData *adp = NULL; + data_map::iterator data_iter; + + // Check all channels for currently playing sounds. + F32 max_pri = -1.f; + for (i = 0; i < MAX_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + if (asp->getPriority() <= max_pri) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getCurrentData(); + if (!adp) + { + continue; + } + + if (!adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + + // Check all channels for currently queued sounds. + if (asset_id.isNull()) + { + max_pri = -1.f; + for (i = 0; i < MAX_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + LLAudioSource *asp; + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getQueuedData(); + if (!adp) + { + continue; + } + + if (!adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + } + + // Check all live channels for other sounds (preloads). + if (asset_id.isNull()) + { + max_pri = -1.f; + for (i = 0; i < MAX_CHANNELS; i++) + { + if (!mChannels[i]) + { + continue; + } + + LLAudioSource *asp; + asp = mChannels[i]->getSource(); + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + + for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) + { + LLAudioData *adp = data_iter->second; + if (!adp) + { + continue; + } + + if (!adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + } + } + } + } + + // Check all sources + if (asset_id.isNull()) + { + max_pri = -1.f; + source_map::iterator source_iter; + for (source_iter = mAllSources.begin(); source_iter != mAllSources.end(); source_iter++) + { + asp = source_iter->second; + if (!asp) + { + continue; + } + + if (asp->getPriority() <= max_pri) + { + continue; + } + + adp = asp->getCurrentData(); + if (adp && !adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + continue; + } + + adp = asp->getQueuedData(); + if (adp && !adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + continue; + } + + for (data_iter = asp->mPreloadMap.begin(); data_iter != asp->mPreloadMap.end(); data_iter++) + { + LLAudioData *adp = data_iter->second; + if (!adp) + { + continue; + } + + if (!adp->hasLocalData() && adp->hasValidData()) + { + asset_id = adp->getID(); + max_pri = asp->getPriority(); + break; + } + } + } + } + + if (asset_id.notNull()) + { + llinfos << "Getting asset data for: " << asset_id << llendl; + gAudiop->mCurrentTransfer = asset_id; + gAudiop->mCurrentTransferTimer.reset(); + gAssetStorage->getAssetData(asset_id, LLAssetType::AT_SOUND, + assetCallback, NULL); + } + else + { + //llinfos << "No pending transfers?" << llendl; + } +} + + +// static +void LLAudioEngine::assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status) +{ + if (result_code) + { + llinfos << "Boom, error in audio file transfer: " << LLAssetStorage::getErrorString( result_code ) << " (" << result_code << ")" << llendl; + // Need to mark data as bad to avoid constant rerequests. + LLAudioData *adp = gAudiop->getAudioData(uuid); + if (adp) + { + adp->setHasValidData(false); + adp->setHasLocalData(false); + adp->setHasDecodedData(false); + } + } + else + { + LLAudioData *adp = gAudiop->getAudioData(uuid); + if (!adp) + { + // Should never happen + llwarns << "Got asset callback without audio data for " << uuid << llendl; + } + else + { + adp->setHasValidData(true); + adp->setHasLocalData(true); + gAudioDecodeMgrp->addDecodeRequest(uuid); + } + } + gAudiop->mCurrentTransfer = LLUUID::null; + gAudiop->startNextTransfer(); +} + + +// +// LLAudioSource implementation +// + + +LLAudioSource::LLAudioSource(const LLUUID& id, const LLUUID& owner_id, const F32 gain, const S32 type) +: mID(id), + mOwnerID(owner_id), + mPriority(0.f), + mGain(gain), + mType(type), + mAmbient(false), + mLoop(false), + mSyncMaster(false), + mSyncSlave(false), + mQueueSounds(false), + mPlayedOnce(false), + mChannelp(NULL), + mCurrentDatap(NULL), + mQueuedDatap(NULL) +{ +} + + +LLAudioSource::~LLAudioSource() +{ + if (mChannelp) + { + // Stop playback of this sound + mChannelp->setSource(NULL); + mChannelp = NULL; + } +} + + +void LLAudioSource::setChannel(LLAudioChannel *channelp) +{ + if (channelp == mChannelp) + { + return; + } + + mChannelp = channelp; +} + + +void LLAudioSource::update() +{ + if (!getCurrentBuffer()) + { + if (getCurrentData()) + { + // Hack - try and load the sound. Will do this as a callback + // on decode later. + if (getCurrentData()->load()) + { + play(getCurrentData()->getID()); + } + } + } +} + +void LLAudioSource::updatePriority() +{ + if (isAmbient()) + { + mPriority = 1.f; + } + else + { + // Priority is based on distance + LLVector3 dist_vec; + dist_vec.setVec(getPositionGlobal()); + dist_vec -= gAudiop->getListenerPos(); + F32 dist_squared = llmax(1.f, dist_vec.magVecSquared()); + + mPriority = mGain / dist_squared; + } +} + +bool LLAudioSource::setupChannel() +{ + LLAudioData *adp = getCurrentData(); + + if (!adp->getBuffer()) + { + // We're not ready to play back the sound yet, so don't try and allocate a channel for it. + //llwarns << "Aborting, no buffer" << llendl; + return false; + } + + + if (!mChannelp) + { + // Update the priority, in case we need to push out another channel. + updatePriority(); + + setChannel(gAudiop->getFreeChannel(getPriority())); + } + + if (!mChannelp) + { + // Ugh, we don't have any free channels. + // Now we have to reprioritize. + // For now, just don't play the sound. + //llwarns << "Aborting, no free channels" << llendl; + return false; + } + + mChannelp->setSource(this); + return true; +} + + +bool LLAudioSource::play(const LLUUID &audio_uuid) +{ + if (audio_uuid.isNull()) + { + if (getChannel()) + { + getChannel()->setSource(NULL); + setChannel(NULL); + addAudioData(NULL, true); + } + } + // Reset our age timeout if someone attempts to play the source. + mAgeTimer.reset(); + + LLAudioData *adp = gAudiop->getAudioData(audio_uuid); + + bool has_buffer = gAudiop->updateBufferForData(adp, audio_uuid); + + + addAudioData(adp); + + if (!has_buffer) + { + // Don't bother trying to set up a channel or anything, we don't have an audio buffer. + return false; + } + + if (!setupChannel()) + { + return false; + } + + if (isSyncSlave()) + { + // A sync slave, it doesn't start playing until it's synced up with the master. + // Flag this channel as waiting for sync, and return true. + getChannel()->setWaiting(true); + return true; + } + + getChannel()->play(); + return true; +} + + +bool LLAudioSource::isDone() +{ + const F32 MAX_AGE = 60.f; + const F32 MAX_UNPLAYED_AGE = 15.f; + + if (isLoop()) + { + // Looped sources never die on their own. + return false; + } + + + if (hasPendingPreloads()) + { + return false; + } + + if (mQueuedDatap) + { + // Don't kill this sound if we've got something queued up to play. + return false; + } + + F32 elapsed = mAgeTimer.getElapsedTimeF32(); + + // This is a single-play source + if (!mChannelp) + { + if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) + { + // We don't have a channel assigned, and it's been + // over 5 seconds since we tried to play it. Don't bother. + //llinfos << "No channel assigned, source is done" << llendl; + return true; + } + else + { + return false; + } + } + + if (mChannelp->isPlaying()) + { + if (elapsed > MAX_AGE) + { + // Arbitarily cut off non-looped sounds when they're old. + return true; + } + else + { + // Sound is still playing and we haven't timed out, don't kill it. + return false; + } + } + + if ((elapsed > MAX_UNPLAYED_AGE) || mPlayedOnce) + { + // The sound isn't playing back after 5 seconds or we're already done playing it, kill it. + return true; + } + + return false; +} + + +void LLAudioSource::addAudioData(LLAudioData *adp, const bool set_current) +{ + // Only handle a single piece of audio data associated with a source right now, + // until I implement prefetch. + if (set_current) + { + if (!mCurrentDatap) + { + mCurrentDatap = adp; + if (mChannelp) + { + mChannelp->updateBuffer(); + mChannelp->play(); + } + + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + return; + } + else if (mQueueSounds) + { + // If we have current data, and we're queuing, put + // the object onto the queue. + if (mQueuedDatap) + { + // We only queue one sound at a time, and it's a FIFO. + // Don't put it onto the queue. + return; + } + + if (adp == mCurrentDatap && isLoop()) + { + // No point in queueing the same sound if + // we're looping. + return; + } + mQueuedDatap = adp; + + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + } + else + { + if (mCurrentDatap != adp) + { + // Right now, if we're currently playing this sound in a channel, we + // update the buffer that the channel's associated with + // and play it. This may not be the correct behavior. + mCurrentDatap = adp; + if (mChannelp) + { + mChannelp->updateBuffer(); + mChannelp->play(); + } + // Make sure the audio engine knows that we want to request this sound. + gAudiop->startNextTransfer(); + } + } + } + else + { + // Add it to the preload list. + mPreloadMap[adp->getID()] = adp; + gAudiop->startNextTransfer(); + } +} + + +bool LLAudioSource::hasPendingPreloads() const +{ + // Check to see if we've got any preloads on deck for this source + data_map::const_iterator iter; + for (iter = mPreloadMap.begin(); iter != mPreloadMap.end(); iter++) + { + LLAudioData *adp = iter->second; + // note: a bad UUID will forever be !hasDecodedData() + // but also !hasValidData(), hence the check for hasValidData() + if (!adp->hasDecodedData() && adp->hasValidData()) + { + // This source is still waiting for a preload + return true; + } + } + + return false; +} + + +LLAudioData * LLAudioSource::getCurrentData() +{ + return mCurrentDatap; +} + +LLAudioData * LLAudioSource::getQueuedData() +{ + return mQueuedDatap; +} + +LLAudioBuffer * LLAudioSource::getCurrentBuffer() +{ + if (!mCurrentDatap) + { + return NULL; + } + + return mCurrentDatap->getBuffer(); +} + + + + +// +// LLAudioChannel implementation +// + + +LLAudioChannel::LLAudioChannel() : + mCurrentSourcep(NULL), + mCurrentBufferp(NULL), + mLoopedThisFrame(false), + mWaiting(false), + mSecondaryGain(1.0f) +{ +} + + +LLAudioChannel::~LLAudioChannel() +{ + // Need to disconnect any sources which are using this channel. + //llinfos << "Cleaning up audio channel" << llendl; + if (mCurrentSourcep) + { + mCurrentSourcep->setChannel(NULL); + } + mCurrentBufferp = NULL; +} + + +void LLAudioChannel::setSource(LLAudioSource *sourcep) +{ + //llinfos << this << ": setSource(" << sourcep << ")" << llendl; + + if (!sourcep) + { + // Clearing the source for this channel, don't need to do anything. + //llinfos << "Clearing source for channel" << llendl; + cleanup(); + mCurrentSourcep = NULL; + mWaiting = false; + return; + } + + if (sourcep == mCurrentSourcep) + { + // Don't reallocate the channel, this will make FMOD goofy. + //llinfos << "Calling setSource with same source!" << llendl; + } + + mCurrentSourcep = sourcep; + + + updateBuffer(); + update3DPosition(); +} + + +bool LLAudioChannel::updateBuffer() +{ + if (!mCurrentSourcep) + { + // This channel isn't associated with any source, nothing + // to be updated + return false; + } + + // Initialize the channel's gain setting for this sound. + if(gAudiop) + { + setSecondaryGain(gAudiop->getSecondaryGain(mCurrentSourcep->getType())); + } + + LLAudioBuffer *bufferp = mCurrentSourcep->getCurrentBuffer(); + if (bufferp == mCurrentBufferp) + { + if (bufferp) + { + // The source hasn't changed what buffer it's playing + bufferp->mLastUseTimer.reset(); + bufferp->mInUse = true; + } + return false; + } + + // + // The source changed what buffer it's playing. We need to clean up + // the existing channel + // + cleanup(); + + mCurrentBufferp = bufferp; + if (bufferp) + { + bufferp->mLastUseTimer.reset(); + bufferp->mInUse = true; + } + + if (!mCurrentBufferp) + { + // There's no new buffer to be played, so we just abort. + return false; + } + + return true; +} + + + + +// +// LLAudioData implementation +// + + +LLAudioData::LLAudioData(const LLUUID &uuid) : + mID(uuid), + mBufferp(NULL), + mHasLocalData(false), + mHasDecodedData(false), + mHasValidData(true) +{ + if (uuid.isNull()) + { + // This is a null sound. + return; + } + + if (gAudiop && gAudiop->hasDecodedFile(uuid)) + { + // Already have a decoded version, don't need to decode it. + mHasLocalData = true; + mHasDecodedData = true; + } + else if (gAssetStorage && gAssetStorage->hasLocalAsset(uuid, LLAssetType::AT_SOUND)) + { + mHasLocalData = true; + } +} + + +bool LLAudioData::load() +{ + // For now, just assume we're going to use one buffer per audiodata. + if (mBufferp) + { + // We already have this sound in a buffer, don't do anything. + llinfos << "Already have a buffer for this sound, don't bother loading!" << llendl; + return true; + } + + mBufferp = gAudiop->getFreeBuffer(); + if (!mBufferp) + { + // No free buffers, abort. + llinfos << "Not able to allocate a new audio buffer, aborting." << llendl; + return false; + } + + std::string uuid_str; + std::string wav_path; + mID.toString(uuid_str); + wav_path= gDirUtilp->getExpandedFilename(LL_PATH_CACHE,uuid_str) + ".dsf"; + + if (!mBufferp->loadWAV(wav_path)) + { + // Hrm. Right now, let's unset the buffer, since it's empty. + gAudiop->cleanupBuffer(mBufferp); + mBufferp = NULL; + + return false; + } + mBufferp->mAudioDatap = this; + return true; +} + + diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h new file mode 100644 index 0000000000..457fd93abe --- /dev/null +++ b/indra/llaudio/llaudioengine.h @@ -0,0 +1,452 @@ +/** + * @file audioengine.h + * @brief Definition of LLAudioEngine base class abstracting the audio support + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_AUDIOENGINE_H +#define LL_AUDIOENGINE_H + +#include +#include + +#include "v3math.h" +#include "v3dmath.h" +#include "lltimer.h" +#include "lluuid.h" +#include "llframetimer.h" +#include "llassettype.h" + +#include "lllistener.h" + +const F32 LL_WIND_UPDATE_INTERVAL = 0.1f; +const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water +const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f; + +const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f; +const F32 DEFAULT_MIN_DISTANCE = 2.0f; + +#define MAX_CHANNELS 30 +#define MAX_BUFFERS 40 // Some extra for preloading, maybe? + +// This define is intended to allow us to switch from os based wav +// file loading to vfs based wav file loading. The problem is that I +// am unconvinced that the LLWaveFile works for loading sounds from +// memory. So, until that is fixed up, changed, whatever, this remains +// undefined. +//#define USE_WAV_VFILE + +class LLVFS; + +class LLAudioSource; +class LLAudioData; +class LLAudioChannel; +class LLAudioChannelOpenAL; +class LLAudioBuffer; +class LLStreamingAudioInterface; + + +// +// LLAudioEngine definition +// + +class LLAudioEngine +{ + friend class LLAudioChannelOpenAL; // bleh. channel needs some listener methods. + +public: + enum LLAudioType + { + AUDIO_TYPE_NONE = 0, + AUDIO_TYPE_SFX = 1, + AUDIO_TYPE_UI = 2, + AUDIO_TYPE_AMBIENT = 3, + AUDIO_TYPE_COUNT = 4 // last + }; + + LLAudioEngine(); + virtual ~LLAudioEngine(); + + // initialization/startup/shutdown + virtual bool init(const S32 num_channels, void *userdata); + virtual std::string getDriverName(bool verbose) = 0; + virtual void shutdown(); + + // Used by the mechanics of the engine + //virtual void processQueue(const LLUUID &sound_guid); + virtual void setListener(LLVector3 pos,LLVector3 vel,LLVector3 up,LLVector3 at); + virtual void updateWind(LLVector3 direction, F32 camera_height_above_water) = 0; + virtual void idle(F32 max_decode_time = 0.f); + virtual void updateChannels(); + + // + // "End user" functionality + // + virtual bool isWindEnabled(); + virtual void enableWind(bool state_b); + + // Use these for temporarily muting the audio system. + // Does not change buffers, initialization, etc. but + // stops playing new sounds. + virtual void setMuted(bool muted); + virtual bool getMuted() const { return mMuted; } +#ifdef USE_PLUGIN_MEDIA + LLPluginClassMedia* initializeMedia(const std::string& media_type); +#endif + F32 getMasterGain(); + void setMasterGain(F32 gain); + + F32 getSecondaryGain(S32 type); + void setSecondaryGain(S32 type, F32 gain); + + F32 getInternetStreamGain(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + virtual void setMaxWindGain(F32 gain); + + + // Methods actually related to setting up and removing sounds + // Owner ID is the owner of the object making the request + void triggerSound(const LLUUID &sound_id, const LLUUID& owner_id, const F32 gain, + const S32 type = LLAudioEngine::AUDIO_TYPE_NONE, + const LLVector3d &pos_global = LLVector3d::zero); + bool preloadSound(const LLUUID &id); + + void addAudioSource(LLAudioSource *asp); + void cleanupAudioSource(LLAudioSource *asp); + + LLAudioSource *findAudioSource(const LLUUID &source_id); + LLAudioData *getAudioData(const LLUUID &audio_uuid); + + // Internet stream implementation manipulation + LLStreamingAudioInterface *getStreamingAudioImpl(); + void setStreamingAudioImpl(LLStreamingAudioInterface *impl); + // Internet stream methods - these will call down into the *mStreamingAudioImpl if it exists + void startInternetStream(const std::string& url); + void stopInternetStream(); + void pauseInternetStream(int pause); + void updateInternetStream(); // expected to be called often + int isInternetStreamPlaying(); + // use a value from 0.0 to 1.0, inclusive + void setInternetStreamGain(F32 vol); + std::string getInternetStreamURL(); + + // For debugging usage + virtual LLVector3 getListenerPos(); + + LLAudioBuffer *getFreeBuffer(); // Get a free buffer, or flush an existing one if you have to. + LLAudioChannel *getFreeChannel(const F32 priority); // Get a free channel or flush an existing one if your priority is higher + void cleanupBuffer(LLAudioBuffer *bufferp); + + bool hasDecodedFile(const LLUUID &uuid); + bool hasLocalFile(const LLUUID &uuid); + + bool updateBufferForData(LLAudioData *adp, const LLUUID &audio_uuid = LLUUID::null); + + + // Asset callback when we're retrieved a sound from the asset server. + void startNextTransfer(); + static void assetCallback(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, void *user_data, S32 result_code, LLExtStat ext_status); + + friend class LLPipeline; // For debugging +public: + F32 mMaxWindGain; // Hack. Public to set before fade in? + +protected: + virtual LLAudioBuffer *createBuffer() = 0; + virtual LLAudioChannel *createChannel() = 0; + + virtual void initWind() = 0; + virtual void cleanupWind() = 0; + virtual void setInternalGain(F32 gain) = 0; + + void commitDeferredChanges(); + + virtual void allocateListener() = 0; + + + // listener methods + virtual void setListenerPos(LLVector3 vec); + virtual void setListenerVelocity(LLVector3 vec); + virtual void orientListener(LLVector3 up, LLVector3 at); + virtual void translateListener(LLVector3 vec); + + + F64 mapWindVecToGain(LLVector3 wind_vec); + F64 mapWindVecToPitch(LLVector3 wind_vec); + F64 mapWindVecToPan(LLVector3 wind_vec); + +protected: + LLListener *mListenerp; + + bool mMuted; + void* mUserData; + + S32 mLastStatus; + + S32 mNumChannels; + bool mEnableWind; + + LLUUID mCurrentTransfer; // Audio file currently being transferred by the system + LLFrameTimer mCurrentTransferTimer; + + // A list of all audio sources that are known to the viewer at this time. + // This is most likely a superset of the ones that we actually have audio + // data for, or are playing back. + typedef std::map source_map; + typedef std::map data_map; + + source_map mAllSources; + data_map mAllData; + + LLAudioChannel *mChannels[MAX_CHANNELS]; + + // Buffers needs to change into a different data structure, as the number of buffers + // that we have active should be limited by RAM usage, not count. + LLAudioBuffer *mBuffers[MAX_BUFFERS]; + + F32 mMasterGain; + F32 mSecondaryGain[AUDIO_TYPE_COUNT]; + + F32 mNextWindUpdate; + + LLFrameTimer mWindUpdateTimer; + +private: + void setDefaults(); + LLStreamingAudioInterface *mStreamingAudioImpl; +}; + + + + +// +// Standard audio source. Can be derived from for special sources, such as those attached to objects. +// + + +class LLAudioSource +{ +public: + // owner_id is the id of the agent responsible for making this sound + // play, for example, the owner of the object currently playing it + LLAudioSource(const LLUUID &id, const LLUUID& owner_id, const F32 gain, const S32 type = LLAudioEngine::AUDIO_TYPE_NONE); + virtual ~LLAudioSource(); + + virtual void update(); // Update this audio source + void updatePriority(); + + void preload(const LLUUID &audio_id); // Only used for preloading UI sounds, now. + + void addAudioData(LLAudioData *adp, bool set_current = TRUE); + + void setAmbient(const bool ambient) { mAmbient = ambient; } + bool isAmbient() const { return mAmbient; } + + void setLoop(const bool loop) { mLoop = loop; } + bool isLoop() const { return mLoop; } + + void setSyncMaster(const bool master) { mSyncMaster = master; } + bool isSyncMaster() const { return mSyncMaster; } + + void setSyncSlave(const bool slave) { mSyncSlave = slave; } + bool isSyncSlave() const { return mSyncSlave; } + + void setQueueSounds(const bool queue) { mQueueSounds = queue; } + bool isQueueSounds() const { return mQueueSounds; } + + void setPlayedOnce(const bool played_once) { mPlayedOnce = played_once; } + + void setType(S32 type) { mType = type; } + S32 getType() { return mType; } + + void setPositionGlobal(const LLVector3d &position_global) { mPositionGlobal = position_global; } + LLVector3d getPositionGlobal() const { return mPositionGlobal; } + LLVector3 getVelocity() const { return mVelocity; } + F32 getPriority() const { return mPriority; } + + // Gain should always be clamped between 0 and 1. + F32 getGain() const { return mGain; } + virtual void setGain(const F32 gain) { mGain = llclamp(gain, 0.f, 1.f); } + + const LLUUID &getID() const { return mID; } + bool isDone(); + + LLAudioData *getCurrentData(); + LLAudioData *getQueuedData(); + LLAudioBuffer *getCurrentBuffer(); + + bool setupChannel(); + bool play(const LLUUID &audio_id); // Start the audio source playing + + bool hasPendingPreloads() const; // Has preloads that haven't been done yet + + friend class LLAudioEngine; + friend class LLAudioChannel; +protected: + void setChannel(LLAudioChannel *channelp); + LLAudioChannel *getChannel() const { return mChannelp; } + +protected: + LLUUID mID; // The ID of the source is that of the object if it's attached to an object. + LLUUID mOwnerID; // owner of the object playing the sound + F32 mPriority; + F32 mGain; + bool mAmbient; + bool mLoop; + bool mSyncMaster; + bool mSyncSlave; + bool mQueueSounds; + bool mPlayedOnce; + S32 mType; + LLVector3d mPositionGlobal; + LLVector3 mVelocity; + + //LLAudioSource *mSyncMasterp; // If we're a slave, the source that we're synced to. + LLAudioChannel *mChannelp; // If we're currently playing back, this is the channel that we're assigned to. + LLAudioData *mCurrentDatap; + LLAudioData *mQueuedDatap; + + typedef std::map data_map; + data_map mPreloadMap; + + LLFrameTimer mAgeTimer; +}; + + + + +// +// Generic metadata about a particular piece of audio data. +// The actual data is handled by the derived LLAudioBuffer classes which are +// derived for each audio engine. +// + + +class LLAudioData +{ +public: + LLAudioData(const LLUUID &uuid); + bool load(); + + LLUUID getID() const { return mID; } + LLAudioBuffer *getBuffer() const { return mBufferp; } + + bool hasLocalData() const { return mHasLocalData; } + bool hasDecodedData() const { return mHasDecodedData; } + bool hasValidData() const { return mHasValidData; } + + void setHasLocalData(const bool hld) { mHasLocalData = hld; } + void setHasDecodedData(const bool hdd) { mHasDecodedData = hdd; } + void setHasValidData(const bool hvd) { mHasValidData = hvd; } + + friend class LLAudioEngine; // Severe laziness, bad. + +protected: + LLUUID mID; + LLAudioBuffer *mBufferp; // If this data is being used by the audio system, a pointer to the buffer will be set here. + bool mHasLocalData; + bool mHasDecodedData; + bool mHasValidData; +}; + + +// +// Base class for an audio channel, i.e. a channel which is capable of playing back a sound. +// Management of channels is done generically, methods for actually manipulating the channel +// are derived for each audio engine. +// + + +class LLAudioChannel +{ +public: + LLAudioChannel(); + virtual ~LLAudioChannel(); + + virtual void setSource(LLAudioSource *sourcep); + LLAudioSource *getSource() const { return mCurrentSourcep; } + + void setSecondaryGain(F32 gain) { mSecondaryGain = gain; } + F32 getSecondaryGain() { return mSecondaryGain; } + + friend class LLAudioEngine; + friend class LLAudioSource; +protected: + virtual void play() = 0; + virtual void playSynced(LLAudioChannel *channelp) = 0; + virtual void cleanup() = 0; + virtual bool isPlaying() = 0; + void setWaiting(const bool waiting) { mWaiting = waiting; } + bool isWaiting() const { return mWaiting; } + + virtual bool updateBuffer(); // Check to see if the buffer associated with the source changed, and update if necessary. + virtual void update3DPosition() = 0; + virtual void updateLoop() = 0; // Update your loop/completion status, for use by queueing/syncing. +protected: + LLAudioSource *mCurrentSourcep; + LLAudioBuffer *mCurrentBufferp; + bool mLoopedThisFrame; + bool mWaiting; // Waiting for sync. + F32 mSecondaryGain; +}; + + + + +// Basically an interface class to the engine-specific implementation +// of audio data that's ready for playback. +// Will likely get more complex as we decide to do stuff like real streaming audio. + + +class LLAudioBuffer +{ +public: + virtual ~LLAudioBuffer() {}; + virtual bool loadWAV(const std::string& filename) = 0; + virtual U32 getLength() = 0; + + friend class LLAudioEngine; + friend class LLAudioChannel; + friend class LLAudioData; +protected: + bool mInUse; + LLAudioData *mAudioDatap; + LLFrameTimer mLastUseTimer; +}; + + + +extern LLAudioEngine* gAudiop; + +#endif diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp new file mode 100644 index 0000000000..7b12b62d53 --- /dev/null +++ b/indra/llaudio/llaudioengine_fmod.cpp @@ -0,0 +1,766 @@ +/** + * @file audioengine_fmod.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmod.h" + +#include "llaudioengine_fmod.h" +#include "lllistener_fmod.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmod.h" +#include "fmod_errors.h" +#include "lldir.h" +#include "llapr.h" + +#include "sound_ids.h" + + +extern "C" { + void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata); +} + +FSOUND_DSPUNIT *gWindDSP = NULL; + + +LLAudioEngine_FMOD::LLAudioEngine_FMOD() +{ + mInited = false; + mWindGen = NULL; +} + + +LLAudioEngine_FMOD::~LLAudioEngine_FMOD() +{ +} + + +bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata) +{ + LLAudioEngine::init(num_channels, userdata); + + // Reserve one extra channel for the http stream. + if (!FSOUND_SetMinHardwareChannels(num_channels + 1)) + { + LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + } + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL; + + F32 version = FSOUND_GetVersion(); + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version + << ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL; + //return false; + } + + U32 fmod_flags = 0x0; + +#if LL_WINDOWS + // Windows needs to know which window is frontmost. + // This must be called before FSOUND_Init() per the FMOD docs. + // This could be used to let FMOD handle muting when we lose focus, + // but we don't actually want to do that because we want to distinguish + // between minimized and not-focused states. + if (!FSOUND_SetHWND(userdata)) + { + LL_WARNS("AppInit") << "Error setting FMOD window: " + << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + return false; + } + // Play audio when we don't have focus. + // (For example, IM client on top of us.) + // This means we also try to play audio when minimized, + // so we manually handle muting in that case. JC + fmod_flags |= FSOUND_INIT_GLOBALFOCUS; +#endif + +#if LL_LINUX + // initialize the FMOD engine + + // This is a hack to use only FMOD's basic FPU mixer + // when the LL_VALGRIND environmental variable is set, + // otherwise valgrind will fall over on FMOD's MMX detection + if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/ + { + LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL; + FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU); + } + + // If we don't set an output method, Linux FMOD always + // decides on OSS and fails otherwise. So we'll manually + // try ESD, then OSS, then ALSA. + // Why this order? See SL-13250, but in short, OSS emulated + // on top of ALSA is ironically more reliable than raw ALSA. + // Ack, and ESD has more reliable failure modes - but has worse + // latency - than all of them, so wins for now. + bool audio_ok = false; + + if (!audio_ok) + if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL; + if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) && + FSOUND_Init(44100, num_channels, fmod_flags)) + { + LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY" + << LL_ENDL; + audio_ok = true; + } else { + LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: " + << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + } + } else { + LL_DEBUGS("AppInit") << "ESD audio output SKIPPED" << LL_ENDL; + } + + if (!audio_ok) + if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; + if(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) && + FSOUND_Init(44100, num_channels, fmod_flags)) + { + LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } else { + LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: " + << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + } + } else { + LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; + } + + if (!audio_ok) + if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; + if(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) && + FSOUND_Init(44100, num_channels, fmod_flags)) + { + LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } else { + LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: " + << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + } + } else { + LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; + } + + if (!audio_ok) + { + LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; + return false; + } + + // On Linux, FMOD causes a SIGPIPE for some netstream error + // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us. + // NOW FIXED in FMOD 3.x since 2006-10-01. + //signal(SIGPIPE, SIG_IGN); + + // We're interested in logging which output method we + // ended up with, for QA purposes. + switch (FSOUND_GetOutput()) + { + case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break; + case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break; + case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; + +#else // LL_LINUX + + // initialize the FMOD engine + if (!FSOUND_Init(44100, num_channels, fmod_flags)) + { + LL_WARNS("AppInit") << "Error initializing FMOD: " + << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + return false; + } + +#endif + + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMOD()); + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL; + + mInited = true; + + return true; +} + + +std::string LLAudioEngine_FMOD::getDriverName(bool verbose) +{ + if (verbose) + { + F32 version = FSOUND_GetVersion(); + return llformat("FMOD version %f", version); + } + else + { + return "FMOD"; + } +} + + +void LLAudioEngine_FMOD::allocateListener(void) +{ + mListenerp = (LLListener *) new LLListener_FMOD(); + if (!mListenerp) + { + llwarns << "Listener creation failed" << llendl; + } +} + + +void LLAudioEngine_FMOD::shutdown() +{ + if (gWindDSP) + { + FSOUND_DSP_SetActive(gWindDSP,false); + FSOUND_DSP_Free(gWindDSP); + } + + stopInternetStream(); + + LLAudioEngine::shutdown(); + + llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl; + FSOUND_Close(); + llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl; + + delete mListenerp; + mListenerp = NULL; +} + + +LLAudioBuffer * LLAudioEngine_FMOD::createBuffer() +{ + return new LLAudioBufferFMOD(); +} + + +LLAudioChannel * LLAudioEngine_FMOD::createChannel() +{ + return new LLAudioChannelFMOD(); +} + + +void LLAudioEngine_FMOD::initWind() +{ + mWindGen = new LLWindGen; + + if (!gWindDSP) + { + gWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen); + } + if (gWindDSP) + { + FSOUND_DSP_SetActive(gWindDSP, true); + } + mNextWindUpdate = 0.0; +} + + +void LLAudioEngine_FMOD::cleanupWind() +{ + if (gWindDSP) + { + FSOUND_DSP_SetActive(gWindDSP, false); + FSOUND_DSP_Free(gWindDSP); + gWindDSP = NULL; + } + + delete mWindGen; + mWindGen = NULL; +} + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMOD::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + + if (!mEnableWind) + { + return; + } + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + // cerr << "Wind update" << endl; + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + } +} + +/* +//----------------------------------------------------------------------- +void LLAudioEngine_FMOD::setSourceMinDistance(U16 source_num, F64 distance) +{ + if (!mInited) + { + return; + } + if (mBuffer[source_num]) + { + mMinDistance[source_num] = (F32) distance; + if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) + { + llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance) +{ + if (!mInited) + { + return; + } + if (mBuffer[source_num]) + { + mMaxDistance[source_num] = (F32) distance; + if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num])) + { + llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist) +{ + *volume = 0; + *freq = 0; + *inside = 0; + *outside = 0; + *orient = LLVector3::zero; + *out_volume = 0; + *min_dist = 0.f; + *max_dist = 0.f; +} + +*/ + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMOD::setInternalGain(F32 gain) +{ + if (!mInited) + { + return; + } + + gain = llclamp( gain, 0.0f, 1.0f ); + FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) ); + + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } +} + +// +// LLAudioChannelFMOD implementation +// + +LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMOD::~LLAudioChannelFMOD() +{ + cleanup(); +} + + +bool LLAudioChannelFMOD::updateBuffer() +{ + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the channel for a different buffer. + + LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer(); + + // Grab the FMOD sample associated with the buffer + FSOUND_SAMPLE *samplep = bufferp->getSample(); + if (!samplep) + { + // This is bad, there should ALWAYS be a sample associated with a legit + // buffer. + llerrs << "No FMOD sample!" << llendl; + return false; + } + + + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true); + + //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl; + } + + // If we have a source for the channel, we need to update its gain. + if (mCurrentSourcep) + { + // SJB: warnings can spam and hurt framerate, disabling + if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f))) + { +// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + + if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF)) + { +// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID() +// << " at " << mCurrentSourcep->getPositionGlobal() << llendl; +// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + } + + return true; +} + + +void LLAudioChannelFMOD::update3DPosition() +{ + if (!mChannelID) + { + // We're not actually a live channel (i.e., we're not playing back anything) + return; + } + + LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentBufferp; + if (!bufferp) + { + // We don't have a buffer associated with us (should really have been picked up + // by the above if. + return; + } + + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, don't need to do any positional updates. + bufferp->set3DMode(false); + } + else + { + // Localized sound. Update the position and velocity of the sound. + bufferp->set3DMode(true); + + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV)) + { + LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL; + } + } +} + + +void LLAudioChannelFMOD::updateLoop() +{ + if (!mChannelID) + { + // May want to clear up the loop/sample counters. + return; + } + + // + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + U32 cur_pos = FSOUND_GetCurrentPosition(mChannelID); + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMOD::cleanup() +{ + if (!mChannelID) + { + //llinfos << "Aborting cleanup with no channelID." << llendl; + return; + } + + //llinfos << "Cleaning up channel: " << mChannelID << llendl; + if (!FSOUND_StopSound(mChannelID)) + { + LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + + mCurrentBufferp = NULL; + mChannelID = 0; +} + + +void LLAudioChannelFMOD::play() +{ + if (!mChannelID) + { + llwarns << "Playing without a channelID, aborting" << llendl; + return; + } + + if (!FSOUND_SetPaused(mChannelID, false)) + { + llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + getSource()->setPlayedOnce(true); +} + + +void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp) +{ + LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp; + if (!(fmod_channelp->mChannelID && mChannelID)) + { + // Don't have channels allocated to both the master and the slave + return; + } + + U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength(); + // Try to match the position of our sync master + if (!FSOUND_SetCurrentPosition(mChannelID, position)) + { + llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl; + } + + // Start us playing + play(); +} + + +bool LLAudioChannelFMOD::isPlaying() +{ + if (!mChannelID) + { + return false; + } + + return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID)); +} + + + +// +// LLAudioBufferFMOD implementation +// + + +LLAudioBufferFMOD::LLAudioBufferFMOD() +{ + mSamplep = NULL; +} + + +LLAudioBufferFMOD::~LLAudioBufferFMOD() +{ + if (mSamplep) + { + // Clean up the associated FMOD sample if it exists. + FSOUND_Sample_Free(mSamplep); + mSamplep = NULL; + } +} + + +bool LLAudioBufferFMOD::loadWAV(const std::string& filename) +{ + // Try to open a wav file from disk. This will eventually go away, as we don't + // really want to block doing this. + if (filename.empty()) + { + // invalid filename, abort. + return false; + } + + if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + { + // File not found, abort. + return false; + } + + if (mSamplep) + { + // If there's already something loaded in this buffer, clean it up. + FSOUND_Sample_Free(mSamplep); + mSamplep = NULL; + } + + // Load up the wav file into an fmod sample +#if LL_WINDOWS + // MikeS. - Loading the sound file manually and then handing it over to FMOD, + // since FMOD uses posix IO internally, + // which doesn't work with unicode file paths. + LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */ + if (sound_file) + { + fseek(sound_file,0,SEEK_END); + U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset + size_t read_count; + fseek(sound_file,0,SEEK_SET); //Seek back to the beginning + char* buffer = new char[file_length]; + llassert(buffer); + read_count = fread((void*)buffer,file_length,1,sound_file);//Load it.. + if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size... + unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY; + //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL; + mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length); + } + delete[] buffer; + fclose(sound_file); + } +#else + mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0); +#endif + + if (!mSamplep) + { + // We failed to load the file for some reason. + llwarns << "Could not load data '" << filename << "': " + << FMOD_ErrorString(FSOUND_GetError()) << llendl; + + // + // If we EVER want to load wav files provided by end users, we need + // to rethink this! + // + // file is probably corrupt - remove it. + LLFile::remove(filename); + return false; + } + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMOD::getLength() +{ + if (!mSamplep) + { + return 0; + } + + return FSOUND_Sample_GetLength(mSamplep); +} + + +void LLAudioBufferFMOD::set3DMode(bool use3d) +{ + U16 current_mode = FSOUND_Sample_GetMode(mSamplep); + + if (use3d) + { + if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D)))) + { + llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + } + else + { + if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D)) + { + llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl; + } + } +} + + +void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata) +{ + // originalbuffer = fmod's original mixbuffer. + // newbuffer = the buffer passed from the previous DSP unit. + // length = length in samples at this mix time. + // param = user parameter passed through in FSOUND_DSP_Create. + // + // modify the buffer in some fashion + + LLWindGen *windgen = + (LLWindGen *)userdata; + U8 stride; + +#if LL_DARWIN + stride = sizeof(LLAudioEngine_FMOD::MIXBUFFERFORMAT); +#else + int mixertype = FSOUND_GetMixer(); + if (mixertype == FSOUND_MIXER_BLENDMODE || + mixertype == FSOUND_MIXER_QUALITY_FPU) + { + stride = 4; + } + else + { + stride = 2; + } +#endif + + newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length, stride); + + return newbuffer; +} diff --git a/indra/llaudio/llaudioengine_fmod.h b/indra/llaudio/llaudioengine_fmod.h new file mode 100644 index 0000000000..3968657cba --- /dev/null +++ b/indra/llaudio/llaudioengine_fmod.h @@ -0,0 +1,129 @@ +/** + * @file audioengine_fmod.h + * @brief Definition of LLAudioEngine class abstracting the audio + * support as a FMOD 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_AUDIOENGINE_FMOD_H +#define LL_AUDIOENGINE_FMOD_H + +#include "llaudioengine.h" +#include "lllistener_fmod.h" +#include "llwindgen.h" + +#include "fmod.h" + +class LLAudioStreamManagerFMOD; + +class LLAudioEngine_FMOD : public LLAudioEngine +{ +public: + LLAudioEngine_FMOD(); + virtual ~LLAudioEngine_FMOD(); + + // initialization/startup/shutdown + virtual bool init(const S32 num_channels, void *user_data); + virtual std::string getDriverName(bool verbose); + virtual void allocateListener(); + + virtual void shutdown(); + + /*virtual*/ void initWind(); + /*virtual*/ void cleanupWind(); + + /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); + +#if LL_DARWIN + typedef S32 MIXBUFFERFORMAT; +#else + typedef S16 MIXBUFFERFORMAT; +#endif + +protected: + /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. + /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. + + /*virtual*/ void setInternalGain(F32 gain); +protected: + static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata); + + //F32 mMinDistance[MAX_BUFFERS]; + //F32 mMaxDistance[MAX_BUFFERS]; + + bool mInited; + + // On Windows, userdata is the HWND of the application window. + void* mUserData; + + LLWindGen *mWindGen; +}; + + +class LLAudioChannelFMOD : public LLAudioChannel +{ +public: + LLAudioChannelFMOD(); + virtual ~LLAudioChannelFMOD(); + +protected: + /*virtual*/ void play(); + /*virtual*/ void playSynced(LLAudioChannel *channelp); + /*virtual*/ void cleanup(); + /*virtual*/ bool isPlaying(); + + /*virtual*/ bool updateBuffer(); + /*virtual*/ void update3DPosition(); + /*virtual*/ void updateLoop(); + +protected: + int mChannelID; + S32 mLastSamplePos; +}; + + +class LLAudioBufferFMOD : public LLAudioBuffer +{ +public: + LLAudioBufferFMOD(); + virtual ~LLAudioBufferFMOD(); + + /*virtual*/ bool loadWAV(const std::string& filename); + /*virtual*/ U32 getLength(); + friend class LLAudioChannelFMOD; + + void set3DMode(bool use3d); +protected: + FSOUND_SAMPLE *getSample() { return mSamplep; } +protected: + FSOUND_SAMPLE *mSamplep; +}; + + +#endif // LL_AUDIOENGINE_FMOD_H diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp new file mode 100644 index 0000000000..a5982ccbd6 --- /dev/null +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -0,0 +1,546 @@ +/** + * @file audioengine_openal.cpp + * @brief implementation of audio engine using OpenAL + * support as a OpenAL 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "lldir.h" + +#include "llaudioengine_openal.h" +#include "lllistener_openal.h" + + +LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() + : + mWindGen(NULL), + mWindBuf(NULL), + mWindBufFreq(0), + mWindBufSamples(0), + mWindBufBytes(0), + mWindSource(AL_NONE), + mNumEmptyWindALBuffers(MAX_NUM_WIND_BUFFERS) +{ +} + +// virtual +LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() +{ +} + +// virtual +bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) +{ + mWindGen = NULL; + LLAudioEngine::init(num_channels, userdata); + + if(!alutInit(NULL, NULL)) + { + llwarns << "LLAudioEngine_OpenAL::init() ALUT initialization failed: " << alutGetErrorString (alutGetError ()) << llendl; + return false; + } + + llinfos << "LLAudioEngine_OpenAL::init() OpenAL successfully initialized" << llendl; + + llinfos << "OpenAL version: " + << ll_safe_string(alGetString(AL_VERSION)) << llendl; + llinfos << "OpenAL vendor: " + << ll_safe_string(alGetString(AL_VENDOR)) << llendl; + llinfos << "OpenAL renderer: " + << ll_safe_string(alGetString(AL_RENDERER)) << llendl; + + ALint major = alutGetMajorVersion (); + ALint minor = alutGetMinorVersion (); + llinfos << "ALUT version: " << major << "." << minor << llendl; + + ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); + + alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major); + alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &minor); + llinfos << "ALC version: " << major << "." << minor << llendl; + + llinfos << "ALC default device: " + << ll_safe_string(alcGetString(device, + ALC_DEFAULT_DEVICE_SPECIFIER)) + << llendl; + + return true; +} + +// virtual +std::string LLAudioEngine_OpenAL::getDriverName(bool verbose) +{ + ALCdevice *device = alcGetContextsDevice(alcGetCurrentContext()); + std::ostringstream version; + + version << + "OpenAL"; + + if (verbose) + { + version << + ", version " << + ll_safe_string(alGetString(AL_VERSION)) << + " / " << + ll_safe_string(alGetString(AL_VENDOR)) << + " / " << + ll_safe_string(alGetString(AL_RENDERER)); + + if (device) + version << + ": " << + ll_safe_string(alcGetString(device, + ALC_DEFAULT_DEVICE_SPECIFIER)); + } + + return version.str(); +} + +// virtual +void LLAudioEngine_OpenAL::allocateListener() +{ + mListenerp = (LLListener *) new LLListener_OpenAL(); + if(!mListenerp) + { + llwarns << "LLAudioEngine_OpenAL::allocateListener() Listener creation failed" << llendl; + } +} + +// virtual +void LLAudioEngine_OpenAL::shutdown() +{ + llinfos << "About to LLAudioEngine::shutdown()" << llendl; + LLAudioEngine::shutdown(); + + llinfos << "About to alutExit()" << llendl; + if(!alutExit()) + { + llwarns << "Nuts." << llendl; + llwarns << "LLAudioEngine_OpenAL::shutdown() ALUT shutdown failed: " << alutGetErrorString (alutGetError ()) << llendl; + } + + llinfos << "LLAudioEngine_OpenAL::shutdown() OpenAL successfully shut down" << llendl; + + delete mListenerp; + mListenerp = NULL; +} + +LLAudioBuffer *LLAudioEngine_OpenAL::createBuffer() +{ + return new LLAudioBufferOpenAL(); +} + +LLAudioChannel *LLAudioEngine_OpenAL::createChannel() +{ + return new LLAudioChannelOpenAL(); +} + +void LLAudioEngine_OpenAL::setInternalGain(F32 gain) +{ + //llinfos << "LLAudioEngine_OpenAL::setInternalGain() Gain: " << gain << llendl; + alListenerf(AL_GAIN, gain); +} + +LLAudioChannelOpenAL::LLAudioChannelOpenAL() + : + mALSource(AL_NONE), + mLastSamplePos(0) +{ + alGenSources(1, &mALSource); +} + +LLAudioChannelOpenAL::~LLAudioChannelOpenAL() +{ + cleanup(); + alDeleteSources(1, &mALSource); +} + +void LLAudioChannelOpenAL::cleanup() +{ + alSourceStop(mALSource); + mCurrentBufferp = NULL; +} + +void LLAudioChannelOpenAL::play() +{ + if (mALSource == AL_NONE) + { + llwarns << "Playing without a mALSource, aborting" << llendl; + return; + } + + if(!isPlaying()) + { + alSourcePlay(mALSource); + getSource()->setPlayedOnce(true); + } +} + +void LLAudioChannelOpenAL::playSynced(LLAudioChannel *channelp) +{ + if (channelp) + { + LLAudioChannelOpenAL *masterchannelp = + (LLAudioChannelOpenAL*)channelp; + if (mALSource != AL_NONE && + masterchannelp->mALSource != AL_NONE) + { + // we have channels allocated to master and slave + ALfloat master_offset; + alGetSourcef(masterchannelp->mALSource, AL_SEC_OFFSET, + &master_offset); + + llinfos << "Syncing with master at " << master_offset + << "sec" << llendl; + // *TODO: detect when this fails, maybe use AL_SAMPLE_ + alSourcef(mALSource, AL_SEC_OFFSET, master_offset); + } + } + play(); +} + +bool LLAudioChannelOpenAL::isPlaying() +{ + if (mALSource != AL_NONE) + { + ALint state; + alGetSourcei(mALSource, AL_SOURCE_STATE, &state); + if(state == AL_PLAYING) + { + return true; + } + } + + return false; +} + +bool LLAudioChannelOpenAL::updateBuffer() +{ + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the source for a different buffer. + LLAudioBufferOpenAL *bufferp = (LLAudioBufferOpenAL *)mCurrentSourcep->getCurrentBuffer(); + ALuint buffer = bufferp->getBuffer(); + alSourcei(mALSource, AL_BUFFER, buffer); + mLastSamplePos = 0; + } + + if (mCurrentSourcep) + { + alSourcef(mALSource, AL_GAIN, + mCurrentSourcep->getGain() * getSecondaryGain()); + alSourcei(mALSource, AL_LOOPING, + mCurrentSourcep->isLoop() ? AL_TRUE : AL_FALSE); + alSourcef(mALSource, AL_ROLLOFF_FACTOR, + gAudiop->mListenerp->getRolloffFactor()); + } + + return true; +} + + +void LLAudioChannelOpenAL::updateLoop() +{ + if (mALSource == AL_NONE) + { + return; + } + + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + ALint cur_pos; + alGetSourcei(mALSource, AL_SAMPLE_OFFSET, &cur_pos); + if (cur_pos < mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelOpenAL::update3DPosition() +{ + if(!mCurrentSourcep) + { + return; + } + if (mCurrentSourcep->isAmbient()) + { + alSource3f(mALSource, AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(mALSource, AL_VELOCITY, 0.0, 0.0, 0.0); + alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_TRUE); + } else { + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + alSourcefv(mALSource, AL_POSITION, float_pos.mV); + alSourcefv(mALSource, AL_VELOCITY, mCurrentSourcep->getVelocity().mV); + alSourcei (mALSource, AL_SOURCE_RELATIVE, AL_FALSE); + } + + alSourcef(mALSource, AL_GAIN, mCurrentSourcep->getGain() * getSecondaryGain()); +} + +LLAudioBufferOpenAL::LLAudioBufferOpenAL() +{ + mALBuffer = AL_NONE; +} + +LLAudioBufferOpenAL::~LLAudioBufferOpenAL() +{ + cleanup(); +} + +void LLAudioBufferOpenAL::cleanup() +{ + if(mALBuffer != AL_NONE) + { + alDeleteBuffers(1, &mALBuffer); + mALBuffer = AL_NONE; + } +} + +bool LLAudioBufferOpenAL::loadWAV(const std::string& filename) +{ + cleanup(); + mALBuffer = alutCreateBufferFromFile(filename.c_str()); + if(mALBuffer == AL_NONE) + { + ALenum error = alutGetError(); + if (gDirUtilp->fileExists(filename)) + { + llwarns << + "LLAudioBufferOpenAL::loadWAV() Error loading " + << filename + << " " << alutGetErrorString(error) << llendl; + } + else + { + // It's common for the file to not actually exist. + lldebugs << + "LLAudioBufferOpenAL::loadWAV() Error loading " + << filename + << " " << alutGetErrorString(error) << llendl; + } + return false; + } + + return true; +} + +U32 LLAudioBufferOpenAL::getLength() +{ + if(mALBuffer == AL_NONE) + { + return 0; + } + ALint length; + alGetBufferi(mALBuffer, AL_SIZE, &length); + return length / 2; // convert size in bytes to size in (16-bit) samples +} + +// ------------ + +void LLAudioEngine_OpenAL::initWind() +{ + ALenum error; + llinfos << "LLAudioEngine_OpenAL::initWind() start" << llendl; + + mNumEmptyWindALBuffers = MAX_NUM_WIND_BUFFERS; + + alGetError(); /* clear error */ + + alGenSources(1,&mWindSource); + + if((error=alGetError()) != AL_NO_ERROR) + { + llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind sources: "<; + + mWindBufFreq = mWindGen->getInputSamplingRate(); + mWindBufSamples = llceil(mWindBufFreq * WIND_BUFFER_SIZE_SEC); + mWindBufBytes = mWindBufSamples * 2 /*stereo*/ * sizeof(WIND_SAMPLE_T); + + mWindBuf = new WIND_SAMPLE_T [mWindBufSamples * 2 /*stereo*/]; + + if(mWindBuf==NULL) + { + llerrs << "LLAudioEngine_OpenAL::initWind() Error creating wind memory buffer" << llendl; + mEnableWind=false; + } + + llinfos << "LLAudioEngine_OpenAL::initWind() done" << llendl; +} + +void LLAudioEngine_OpenAL::cleanupWind() +{ + llinfos << "LLAudioEngine_OpenAL::cleanupWind()" << llendl; + + if (mWindSource != AL_NONE) + { + // detach and delete all outstanding buffers on the wind source + alSourceStop(mWindSource); + ALint processed; + alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); + while (processed--) + { + ALuint buffer = AL_NONE; + alSourceUnqueueBuffers(mWindSource, 1, &buffer); + alDeleteBuffers(1, &buffer); + } + + // delete the wind source itself + alDeleteSources(1, &mWindSource); + + mWindSource = AL_NONE; + } + + delete[] mWindBuf; + mWindBuf = NULL; + + delete mWindGen; + mWindGen = NULL; +} + +void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + ALenum error; + + if (!mEnableWind) + return; + + if(!mWindBuf) + return; + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + + alSourcei(mWindSource, AL_LOOPING, AL_FALSE); + alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0); + alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0); + alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE); + } + + // ok lets make a wind buffer now + + ALint processed, queued, unprocessed; + alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed); + alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued); + unprocessed = queued - processed; + + // ensure that there are always at least 3x as many filled buffers + // queued as we managed to empty since last time. + mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed); + mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0); + + //llinfos << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers <<" (" << unprocessed << ":" << processed << ")" << llendl; + + while(processed--) // unqueue old buffers + { + ALuint buffer; + ALenum error; + alGetError(); /* clear error */ + alSourceUnqueueBuffers(mWindSource, 1, &buffer); + error = alGetError(); + if(error != AL_NO_ERROR) + { + llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << llendl; + } + else + { + alDeleteBuffers(1, &buffer); + } + } + + unprocessed += mNumEmptyWindALBuffers; + while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers + { + ALuint buffer; + alGetError(); /* clear error */ + alGenBuffers(1,&buffer); + if((error=alGetError()) != AL_NO_ERROR) + { + llwarns << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << llendl; + break; + } + + alBufferData(buffer, + AL_FORMAT_STEREO16, + mWindGen->windGenerate(mWindBuf, + mWindBufSamples, 2), + mWindBufBytes, + mWindBufFreq); + error = alGetError(); + if(error != AL_NO_ERROR) + { + llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << llendl; + } + + alSourceQueueBuffers(mWindSource, 1, &buffer); + error = alGetError(); + if(error != AL_NO_ERROR) + { + llwarns << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << llendl; + } + + --mNumEmptyWindALBuffers; + } + + ALint playing; + alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing); + if(playing != AL_PLAYING) + { + alSourcePlay(mWindSource); + + lldebugs << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << llendl; + } +} + diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h new file mode 100644 index 0000000000..5aca03e195 --- /dev/null +++ b/indra/llaudio/llaudioengine_openal.h @@ -0,0 +1,114 @@ +/** + * @file audioengine_openal.cpp + * @brief implementation of audio engine using OpenAL + * support as a OpenAL 3D implementation + * + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_AUDIOENGINE_OPENAL_H +#define LL_AUDIOENGINE_OPENAL_H + +#include "llaudioengine.h" +#include "lllistener_openal.h" +#include "llwindgen.h" + +class LLAudioEngine_OpenAL : public LLAudioEngine +{ + public: + LLAudioEngine_OpenAL(); + virtual ~LLAudioEngine_OpenAL(); + + virtual bool init(const S32 num_channels, void *user_data); + virtual std::string getDriverName(bool verbose); + virtual void allocateListener(); + + virtual void shutdown(); + + void setInternalGain(F32 gain); + + LLAudioBuffer* createBuffer(); + LLAudioChannel* createChannel(); + + /*virtual*/ void initWind(); + /*virtual*/ void cleanupWind(); + /*virtual*/ void updateWind(LLVector3 direction, F32 camera_altitude); + + private: + void * windDSP(void *newbuffer, int length); + typedef S16 WIND_SAMPLE_T; + LLWindGen *mWindGen; + S16 *mWindBuf; + U32 mWindBufFreq; + U32 mWindBufSamples; + U32 mWindBufBytes; + ALuint mWindSource; + int mNumEmptyWindALBuffers; + + static const int MAX_NUM_WIND_BUFFERS = 80; + static const float WIND_BUFFER_SIZE_SEC = 0.05f; // 1/20th sec +}; + +class LLAudioChannelOpenAL : public LLAudioChannel +{ + public: + LLAudioChannelOpenAL(); + virtual ~LLAudioChannelOpenAL(); + protected: + /*virtual*/ void play(); + /*virtual*/ void playSynced(LLAudioChannel *channelp); + /*virtual*/ void cleanup(); + /*virtual*/ bool isPlaying(); + + /*virtual*/ bool updateBuffer(); + /*virtual*/ void update3DPosition(); + /*virtual*/ void updateLoop(); + + ALuint mALSource; + ALint mLastSamplePos; +}; + +class LLAudioBufferOpenAL : public LLAudioBuffer{ + public: + LLAudioBufferOpenAL(); + virtual ~LLAudioBufferOpenAL(); + + bool loadWAV(const std::string& filename); + U32 getLength(); + + friend class LLAudioChannelOpenAL; + protected: + void cleanup(); + ALuint getBuffer() {return mALBuffer;} + + ALuint mALBuffer; +}; + +#endif diff --git a/indra/llaudio/lllistener.cpp b/indra/llaudio/lllistener.cpp new file mode 100644 index 0000000000..846c6bccb5 --- /dev/null +++ b/indra/llaudio/lllistener.cpp @@ -0,0 +1,142 @@ +/** + * @file listener.cpp + * @brief Implementation of LISTENER class abstracting the audio support + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lllistener.h" + +#define DEFAULT_AT 0.0f,0.0f,-1.0f +#define DEFAULT_UP 0.0f,1.0f,0.0f + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener::LLListener() +{ + init(); +} + +//----------------------------------------------------------------------- +LLListener::~LLListener() +{ +} + +//----------------------------------------------------------------------- +void LLListener::init(void) +{ + mPosition.zeroVec(); + mListenAt.setVec(DEFAULT_AT); + mListenUp.setVec(DEFAULT_UP); + mVelocity.zeroVec(); +} + +//----------------------------------------------------------------------- +void LLListener::translate(LLVector3 offset) +{ + mPosition += offset; +} + +//----------------------------------------------------------------------- +void LLListener::setPosition(LLVector3 pos) +{ + mPosition = pos; +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getPosition(void) +{ + return(mPosition); +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getAt(void) +{ + return(mListenAt); +} + +//----------------------------------------------------------------------- +LLVector3 LLListener::getUp(void) +{ + return(mListenUp); +} + +//----------------------------------------------------------------------- +void LLListener::setVelocity(LLVector3 vel) +{ + mVelocity = vel; +} + +//----------------------------------------------------------------------- +void LLListener::orient(LLVector3 up, LLVector3 at) +{ + mListenUp = up; + mListenAt = at; +} + +//----------------------------------------------------------------------- +void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) +{ + mPosition = pos; + mVelocity = vel; + + setPosition(pos); + setVelocity(vel); + orient(up,at); +} + +//----------------------------------------------------------------------- +void LLListener::setDopplerFactor(F32 factor) +{ +} + +//----------------------------------------------------------------------- +F32 LLListener::getDopplerFactor() +{ + return (1.f); +} + +//----------------------------------------------------------------------- +void LLListener::setRolloffFactor(F32 factor) +{ +} + +//----------------------------------------------------------------------- +F32 LLListener::getRolloffFactor() +{ + return (1.f); +} + +//----------------------------------------------------------------------- +void LLListener::commitDeferredChanges() +{ +} + diff --git a/indra/llaudio/lllistener.h b/indra/llaudio/lllistener.h new file mode 100644 index 0000000000..e94fbe853f --- /dev/null +++ b/indra/llaudio/lllistener.h @@ -0,0 +1,78 @@ +/** + * @file listener.h + * @brief Description of LISTENER base class abstracting the audio support. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_H +#define LL_LISTENER_H + +#include "v3math.h" + +class LLListener +{ + private: + protected: + LLVector3 mPosition; + LLVector3 mVelocity; + LLVector3 mListenAt; + LLVector3 mListenUp; + + public: + + private: + protected: + public: + LLListener(); + virtual ~LLListener(); + virtual void init(); + + virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); + + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + + virtual void orient(LLVector3 up, LLVector3 at); + virtual void translate(LLVector3 offset); + + virtual void setDopplerFactor(F32 factor); + virtual void setRolloffFactor(F32 factor); + + virtual LLVector3 getPosition(); + virtual LLVector3 getAt(); + virtual LLVector3 getUp(); + + virtual F32 getDopplerFactor(); + virtual F32 getRolloffFactor(); + + virtual void commitDeferredChanges(); +}; + +#endif + diff --git a/indra/llaudio/lllistener_ds3d.h b/indra/llaudio/lllistener_ds3d.h new file mode 100644 index 0000000000..1ff9c170c4 --- /dev/null +++ b/indra/llaudio/lllistener_ds3d.h @@ -0,0 +1,74 @@ +/** + * @file listener_ds3d.h + * @brief Description of LISTENER class abstracting the audio support + * as a DirectSound 3D implementation (windows only) + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_DS3D_H +#define LL_LISTENER_DS3D_H + +#include "lllistener.h" + +#include +#include +#include + +class LLListener_DS3D : public LLListener +{ + private: + protected: + IDirectSound3DListener8 *m3DListener; + public: + + private: + protected: + public: + LLListener_DS3D(); + virtual ~LLListener_DS3D(); + virtual void init(); + + virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + + virtual void commitDeferredChanges(); +}; + +#endif + + diff --git a/indra/llaudio/lllistener_fmod.cpp b/indra/llaudio/lllistener_fmod.cpp new file mode 100644 index 0000000000..57ad461b02 --- /dev/null +++ b/indra/llaudio/lllistener_fmod.cpp @@ -0,0 +1,131 @@ +/** + * @file listener_fmod.cpp + * @brief implementation of LISTENER class abstracting the audio + * support as a FMOD 3D implementation (windows only) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llaudioengine.h" +#include "lllistener_fmod.h" +#include "fmod.h" + +//----------------------------------------------------------------------- +// constructor +//----------------------------------------------------------------------- +LLListener_FMOD::LLListener_FMOD() +{ + init(); +} + +//----------------------------------------------------------------------- +LLListener_FMOD::~LLListener_FMOD() +{ +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::init(void) +{ + // do inherited + LLListener::init(); + mDopplerFactor = 1.0f; + mRolloffFactor = 1.0f; +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::translate(LLVector3 offset) +{ + LLListener::translate(offset); + + FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::setPosition(LLVector3 pos) +{ + LLListener::setPosition(pos); + + FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); + + FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::orient(LLVector3 up, LLVector3 at) +{ + LLListener::orient(up, at); + + // Welcome to the transition between right and left + // (coordinate systems, that is) + // Leaving the at vector alone results in a L/R reversal + // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed + at = -at; + + FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]); +} + +//----------------------------------------------------------------------- +void LLListener_FMOD::commitDeferredChanges() +{ + FSOUND_Update(); +} + + +void LLListener_FMOD::setRolloffFactor(F32 factor) +{ + mRolloffFactor = factor; + FSOUND_3D_SetRolloffFactor(factor); +} + + +F32 LLListener_FMOD::getRolloffFactor() +{ + return mRolloffFactor; +} + + +void LLListener_FMOD::setDopplerFactor(F32 factor) +{ + mDopplerFactor = factor; + FSOUND_3D_SetDopplerFactor(factor); +} + + +F32 LLListener_FMOD::getDopplerFactor() +{ + return mDopplerFactor; +} + + diff --git a/indra/llaudio/lllistener_fmod.h b/indra/llaudio/lllistener_fmod.h new file mode 100644 index 0000000000..5a48ec8b68 --- /dev/null +++ b/indra/llaudio/lllistener_fmod.h @@ -0,0 +1,64 @@ +/** + * @file listener_fmod.h + * @brief Description of LISTENER class abstracting the audio support + * as an FMOD 3D implementation (windows and Linux) + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_FMOD_H +#define LL_LISTENER_FMOD_H + +#include "lllistener.h" + +class LLListener_FMOD : public LLListener +{ + public: + LLListener_FMOD(); + virtual ~LLListener_FMOD(); + virtual void init(); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void commitDeferredChanges(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + + protected: + F32 mDopplerFactor; + F32 mRolloffFactor; +}; + +#endif + + diff --git a/indra/llaudio/lllistener_openal.cpp b/indra/llaudio/lllistener_openal.cpp new file mode 100644 index 0000000000..a96ebd5dba --- /dev/null +++ b/indra/llaudio/lllistener_openal.cpp @@ -0,0 +1,116 @@ +/** + * @file audioengine_openal.cpp + * @brief implementation of audio engine using OpenAL + * support as a OpenAL 3D implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llaudioengine.h" + +#include "lllistener_openal.h" + +LLListener_OpenAL::LLListener_OpenAL() +{ + init(); +} + +LLListener_OpenAL::~LLListener_OpenAL() +{ +} + +void LLListener_OpenAL::translate(LLVector3 offset) +{ + //llinfos << "LLListener_OpenAL::translate() : " << offset << llendl; + LLListener::translate(offset); +} + +void LLListener_OpenAL::setPosition(LLVector3 pos) +{ + //llinfos << "LLListener_OpenAL::setPosition() : " << pos << llendl; + LLListener::setPosition(pos); +} + +void LLListener_OpenAL::setVelocity(LLVector3 vel) +{ + LLListener::setVelocity(vel); +} + +void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at) +{ + //llinfos << "LLListener_OpenAL::orient() up: " << up << " at: " << at << llendl; + LLListener::orient(up, at); +} + +void LLListener_OpenAL::commitDeferredChanges() +{ + ALfloat orientation[6]; + orientation[0] = mListenAt.mV[0]; + orientation[1] = mListenAt.mV[1]; + orientation[2] = mListenAt.mV[2]; + orientation[3] = mListenUp.mV[0]; + orientation[4] = mListenUp.mV[1]; + orientation[5] = mListenUp.mV[2]; + + ALfloat velocity[3]; + velocity[0] = mVelocity.mV[0]; + velocity[1] = mVelocity.mV[1]; + velocity[2] = mVelocity.mV[2]; + + alListenerfv(AL_ORIENTATION, orientation); + alListenerfv(AL_POSITION, mPosition.mV); + alListenerfv(AL_VELOCITY, velocity); +} + +void LLListener_OpenAL::setDopplerFactor(F32 factor) +{ + //llinfos << "LLListener_OpenAL::setDopplerFactor() : " << factor << llendl; + alDopplerFactor(factor); +} + +F32 LLListener_OpenAL::getDopplerFactor() +{ + ALfloat factor; + factor = alGetFloat(AL_DOPPLER_FACTOR); + //llinfos << "LLListener_OpenAL::getDopplerFactor() : " << factor << llendl; + return factor; +} + + +void LLListener_OpenAL::setRolloffFactor(F32 factor) +{ + mRolloffFactor = factor; +} + +F32 LLListener_OpenAL::getRolloffFactor() +{ + return mRolloffFactor; +} + + diff --git a/indra/llaudio/lllistener_openal.h b/indra/llaudio/lllistener_openal.h new file mode 100644 index 0000000000..0dfeea5c90 --- /dev/null +++ b/indra/llaudio/lllistener_openal.h @@ -0,0 +1,64 @@ +/** + * @file listener_openal.h + * @brief Description of LISTENER class abstracting the audio support + * as an OpenAL implementation + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LISTENER_OPENAL_H +#define LL_LISTENER_OPENAL_H + +#include "lllistener.h" + +#include "AL/al.h" +#include "AL/alut.h" + +class LLListener_OpenAL : public LLListener +{ + public: + LLListener_OpenAL(); + virtual ~LLListener_OpenAL(); + + virtual void translate(LLVector3 offset); + virtual void setPosition(LLVector3 pos); + virtual void setVelocity(LLVector3 vel); + virtual void orient(LLVector3 up, LLVector3 at); + virtual void commitDeferredChanges(); + + virtual void setDopplerFactor(F32 factor); + virtual F32 getDopplerFactor(); + virtual void setRolloffFactor(F32 factor); + virtual F32 getRolloffFactor(); + + protected: + F32 mRolloffFactor; +}; + +#endif + diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h new file mode 100644 index 0000000000..aa89e6a177 --- /dev/null +++ b/indra/llaudio/llstreamingaudio.h @@ -0,0 +1,56 @@ +/** + * @file streamingaudio.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudioInterface base class abstracting the streaming audio interface + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_H +#define LL_STREAMINGAUDIO_H + +#include "stdtypes.h" // from llcommon + +// Entirely abstract. Based exactly on the historic API. +class LLStreamingAudioInterface +{ + public: + virtual ~LLStreamingAudioInterface() {} + + virtual void start(const std::string& url) = 0; + virtual void stop() = 0; + virtual void pause(int pause) = 0; + virtual void update() = 0; + virtual int isPlaying() = 0; + // use a value from 0.0 to 1.0, inclusive + virtual void setGain(F32 vol) = 0; + virtual F32 getGain() = 0; + virtual std::string getURL() = 0; +}; + +#endif // LL_STREAMINGAUDIO_H diff --git a/indra/llaudio/llstreamingaudio_fmod.cpp b/indra/llaudio/llstreamingaudio_fmod.cpp new file mode 100644 index 0000000000..a71a87203c --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmod.cpp @@ -0,0 +1,362 @@ +/** + * @file streamingaudio_fmod.cpp + * @brief LLStreamingAudio_FMOD implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llmath.h" + +#include "fmod.h" +#include "fmod_errors.h" + +#include "llstreamingaudio_fmod.h" + + +class LLAudioStreamManagerFMOD +{ +public: + LLAudioStreamManagerFMOD(const std::string& url); + int startStream(); + bool stopStream(); // Returns true if the stream was successfully stopped. + bool ready(); + + const std::string& getURL() { return mInternetStreamURL; } + + int getOpenState(); +protected: + FSOUND_STREAM* mInternetStream; + bool mReady; + + std::string mInternetStreamURL; +}; + + + +//--------------------------------------------------------------------------- +// Internet Streaming +//--------------------------------------------------------------------------- +LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() : + mCurrentInternetStreamp(NULL), + mFMODInternetStreamChannel(-1), + mGain(1.0f) +{ + // Number of milliseconds of audio to buffer for the audio card. + // Must be larger than the usual Second Life frame stutter time. + FSOUND_Stream_SetBufferSize(200); + + // Here's where we set the size of the network buffer and some buffering + // parameters. In this case we want a network buffer of 16k, we want it + // to prebuffer 40% of that when we first connect, and we want it + // to rebuffer 80% of that whenever we encounter a buffer underrun. + + // Leave the net buffer properties at the default. + //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); +} + + +LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD() +{ + // nothing interesting/safe to do. +} + + +void LLStreamingAudio_FMOD::start(const std::string& url) +{ + //if (!mInited) + //{ + // llwarns << "startInternetStream before audio initialized" << llendl; + // return; + //} + + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); + + if (!url.empty()) + { + llinfos << "Starting internet stream: " << url << llendl; + mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url); + mURL = url; + } + else + { + llinfos << "Set internet stream to null" << llendl; + mURL.clear(); + } +} + + +void LLStreamingAudio_FMOD::update() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMOD *streamp = *iter; + if (streamp->stopStream()) + { + llinfos << "Closed dead stream" << llendl; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } + + int open_state = mCurrentInternetStreamp->getOpenState(); + + if (!open_state) + { + // Stream is live + + // start the stream if it's ready + if (mFMODInternetStreamChannel < 0) + { + mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream(); + + if (mFMODInternetStreamChannel != -1) + { + // Reset volume to previously set volume + setGain(getGain()); + FSOUND_SetPaused(mFMODInternetStreamChannel, false); + } + } + } + + switch(open_state) + { + default: + case 0: + // success + break; + case -1: + // stream handle is invalid + llwarns << "InternetStream - invalid handle" << llendl; + stop(); + return; + case -2: + // opening + break; + case -3: + // failed to open, file not found, perhaps + llwarns << "InternetSteam - failed to open" << llendl; + stop(); + return; + case -4: + // connecting + break; + case -5: + // buffering + break; + } + +} + +void LLStreamingAudio_FMOD::stop() +{ + if (mFMODInternetStreamChannel != -1) + { + FSOUND_SetPaused(mFMODInternetStreamChannel, true); + FSOUND_SetPriority(mFMODInternetStreamChannel, 0); + mFMODInternetStreamChannel = -1; + } + + if (mCurrentInternetStreamp) + { + llinfos << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << llendl; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + llwarns << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << llendl; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = NULL; + //mURL.clear(); + } +} + +void LLStreamingAudio_FMOD::pause(int pauseopt) +{ + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } + + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } +} + + +// A stream is "playing" if it has been requested to start. That +// doesn't necessarily mean audio is coming out of the speakers. +int LLStreamingAudio_FMOD::isPlaying() +{ + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } +} + + +F32 LLStreamingAudio_FMOD::getGain() +{ + return mGain; +} + + +std::string LLStreamingAudio_FMOD::getURL() +{ + return mURL; +} + + +void LLStreamingAudio_FMOD::setGain(F32 vol) +{ + mGain = vol; + + if (mFMODInternetStreamChannel != -1) + { + vol = llclamp(vol, 0.f, 1.f); + int vol_int = llround(vol * 255.f); + FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int); + } +} + + +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) : + mInternetStream(NULL), + mReady(false) +{ + mInternetStreamURL = url; + mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0); + if (!mInternetStream) + { + llwarns << "Couldn't open fmod stream, error " + << FMOD_ErrorString(FSOUND_GetError()) + << llendl; + mReady = false; + return; + } + + mReady = true; +} + +int LLAudioStreamManagerFMOD::startStream() +{ + // We need a live and opened stream before we try and play it. + if (!mInternetStream || getOpenState()) + { + llwarns << "No internet stream to start playing!" << llendl; + return -1; + } + + // Make sure the stream is set to 2D mode. + FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D); + + return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true); +} + +bool LLAudioStreamManagerFMOD::stopStream() +{ + if (mInternetStream) + { + int read_percent = 0; + int status = 0; + int bitrate = 0; + unsigned int flags = 0x0; + FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags); + + bool close = true; + switch (status) + { + case FSOUND_STREAM_NET_CONNECTING: + close = false; + break; + case FSOUND_STREAM_NET_NOTCONNECTED: + case FSOUND_STREAM_NET_BUFFERING: + case FSOUND_STREAM_NET_READY: + case FSOUND_STREAM_NET_ERROR: + default: + close = true; + } + + if (close) + { + FSOUND_Stream_Close(mInternetStream); + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +int LLAudioStreamManagerFMOD::getOpenState() +{ + int open_state = FSOUND_Stream_GetOpenState(mInternetStream); + return open_state; +} diff --git a/indra/llaudio/llstreamingaudio_fmod.h b/indra/llaudio/llstreamingaudio_fmod.h new file mode 100644 index 0000000000..968ab53a0b --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmod.h @@ -0,0 +1,68 @@ +/** + * @file streamingaudio_fmod.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudio_FMOD implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_FMOD_H +#define LL_STREAMINGAUDIO_FMOD_H + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" + +class LLAudioStreamManagerFMOD; + +class LLStreamingAudio_FMOD : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_FMOD(); + /*virtual*/ ~LLStreamingAudio_FMOD(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(int pause); + /*virtual*/ void update(); + /*virtual*/ int isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + +private: + LLAudioStreamManagerFMOD *mCurrentInternetStreamp; + int mFMODInternetStreamChannel; + std::list mDeadStreams; + + std::string mURL; + F32 mGain; +}; + + +#endif // LL_STREAMINGAUDIO_FMOD_H diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp new file mode 100644 index 0000000000..8ee082a245 --- /dev/null +++ b/indra/llaudio/llvorbisencode.cpp @@ -0,0 +1,505 @@ +/** + * @file vorbisencode.cpp + * @brief Vorbis encoding routine routine for Indra. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "vorbis/vorbisenc.h" + +#include "llvorbisencode.h" +#include "llerror.h" +#include "llrand.h" +#include "llmath.h" +#include "llapr.h" + +//#if LL_DARWIN +// MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions. +#if 0 +#include "VorbisFramework.h" + +#define vorbis_analysis mac_vorbis_analysis +#define vorbis_analysis_headerout mac_vorbis_analysis_headerout +#define vorbis_analysis_init mac_vorbis_analysis_init +#define vorbis_encode_ctl mac_vorbis_encode_ctl +#define vorbis_encode_setup_init mac_vorbis_encode_setup_init +#define vorbis_encode_setup_managed mac_vorbis_encode_setup_managed + +#define vorbis_info_init mac_vorbis_info_init +#define vorbis_info_clear mac_vorbis_info_clear +#define vorbis_comment_init mac_vorbis_comment_init +#define vorbis_comment_clear mac_vorbis_comment_clear +#define vorbis_block_init mac_vorbis_block_init +#define vorbis_block_clear mac_vorbis_block_clear +#define vorbis_dsp_clear mac_vorbis_dsp_clear +#define vorbis_analysis_buffer mac_vorbis_analysis_buffer +#define vorbis_analysis_wrote mac_vorbis_analysis_wrote +#define vorbis_analysis_blockout mac_vorbis_analysis_blockout + +#define ogg_stream_packetin mac_ogg_stream_packetin +#define ogg_stream_init mac_ogg_stream_init +#define ogg_stream_flush mac_ogg_stream_flush +#define ogg_stream_pageout mac_ogg_stream_pageout +#define ogg_page_eos mac_ogg_page_eos +#define ogg_stream_clear mac_ogg_stream_clear + +#endif + +S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& error_msg) +{ + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + U32 physical_file_size = 0; + U32 chunk_length = 0; + U32 raw_data_length = 0; + U32 bytes_per_sec = 0; + BOOL uncompressed_pcm = FALSE; + + unsigned char wav_header[44]; /*Flawfinder: ignore*/ + + error_msg.clear(); + + //******************************** + LLAPRFile infile ; + infile.open(in_fname,LL_APR_RB); + //******************************** + if (!infile.getFileHandle()) + { + error_msg = "CannotUploadSoundFile"; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + infile.read(wav_header, 44); + physical_file_size = infile.seek(APR_END,0); + + if (strncmp((char *)&(wav_header[0]),"RIFF",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + if (strncmp((char *)&(wav_header[8]),"WAVE",4)) + { + error_msg = "SoundFileNotRIFF"; + return(LLVORBISENC_WAV_FORMAT_ERR); + } + + // parse the chunks + + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while ((file_pos + 8)< physical_file_size) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + +// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + if ((wav_header[8] == 0x01) && (wav_header[9] == 0x00)) + { + uncompressed_pcm = TRUE; + } + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + bytes_per_sec = ((U32) wav_header[19] << 24) + + ((U32) wav_header[18] << 16) + + ((U32) wav_header[17] << 8) + + wav_header[16]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + raw_data_length = chunk_length; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + //**************** + infile.close(); + //**************** + + if (!uncompressed_pcm) + { + error_msg = "SoundFileNotPCM"; + return(LLVORBISENC_PCM_FORMAT_ERR); + } + + if ((num_channels < 1) || (num_channels > 2)) + { + error_msg = "SoundFileInvalidChannelCount"; + return(LLVORBISENC_MULTICHANNEL_ERR); + } + + if (sample_rate != 44100) + { + error_msg = "SoundFileInvalidSampleRate"; + return(LLVORBISENC_UNSUPPORTED_SAMPLE_RATE); + } + + if ((bits_per_sample != 16) && (bits_per_sample != 8)) + { + error_msg = "SoundFileInvalidWordSize"; + return(LLVORBISENC_UNSUPPORTED_WORD_SIZE); + } + + if (!raw_data_length) + { + error_msg = "SoundFileInvalidHeader"; + return(LLVORBISENC_CLIP_TOO_LONG); + } + + F32 clip_length = (F32)raw_data_length/(F32)bytes_per_sec; + + if (clip_length > 10.0f) + { + error_msg = "SoundFileInvalidTooLong"; + return(LLVORBISENC_CLIP_TOO_LONG); + } + + return(LLVORBISENC_NOERR); +} + +S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname) +{ +#define READ_BUFFER 1024 + unsigned char readbuffer[READ_BUFFER*4+44]; /* out of the data segment, not the stack */ /*Flawfinder: ignore*/ + + ogg_stream_state os; /* take physical pages, weld into a logical stream of packets */ + ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */ + ogg_packet op; /* one raw packet of data for decode */ + + vorbis_info vi; /* struct that stores all the static vorbis bitstream settings */ + vorbis_comment vc; /* struct that stores all the user comments */ + + vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ + vorbis_block vb; /* local working space for packet->PCM decode */ + + int eos=0; + int result; + + U16 num_channels = 0; + U32 sample_rate = 0; + U32 bits_per_sample = 0; + + S32 format_error = 0; + std::string error_msg; + if ((format_error = check_for_invalid_wav_formats(in_fname, error_msg))) + { + llwarns << error_msg << ": " << in_fname << llendl; + return(format_error); + } + +#if 1 + unsigned char wav_header[44]; /*Flawfinder: ignore*/ + + S32 data_left = 0; + + LLAPRFile infile ; + infile.open(in_fname,LL_APR_RB); + if (!infile.getFileHandle()) + { + llwarns << "Couldn't open temporary ogg file for writing: " << in_fname + << llendl; + return(LLVORBISENC_SOURCE_OPEN_ERR); + } + + LLAPRFile outfile ; + outfile.open(out_fname,LL_APR_WPB); + if (!outfile.getFileHandle()) + { + llwarns << "Couldn't open upload sound file for reading: " << in_fname + << llendl; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + // parse the chunks + U32 chunk_length = 0; + U32 file_pos = 12; // start at the first chunk (usually fmt but not always) + + while (infile.eof() != APR_EOF) + { + infile.seek(APR_SET,file_pos); + infile.read(wav_header, 44); + + chunk_length = ((U32) wav_header[7] << 24) + + ((U32) wav_header[6] << 16) + + ((U32) wav_header[5] << 8) + + wav_header[4]; + +// llinfos << "chunk found: '" << wav_header[0] << wav_header[1] << wav_header[2] << wav_header[3] << "'" << llendl; + + if (!(strncmp((char *)&(wav_header[0]),"fmt ",4))) + { + num_channels = ((U16) wav_header[11] << 8) + wav_header[10]; + sample_rate = ((U32) wav_header[15] << 24) + + ((U32) wav_header[14] << 16) + + ((U32) wav_header[13] << 8) + + wav_header[12]; + bits_per_sample = ((U16) wav_header[23] << 8) + wav_header[22]; + } + else if (!(strncmp((char *)&(wav_header[0]),"data",4))) + { + infile.seek(APR_SET,file_pos+8); + // leave the file pointer at the beginning of the data chunk data + data_left = chunk_length; + break; + } + file_pos += (chunk_length + 8); + chunk_length = 0; + } + + + /********** Encode setup ************/ + + /* choose an encoding mode */ + /* (mode 0: 44kHz stereo uncoupled, roughly 128kbps VBR) */ + vorbis_info_init(&vi); + + // always encode to mono + + // SL-52913 & SL-53779 determined this quality level to be our 'good + // enough' general-purpose quality level with a nice low bitrate. + // Equivalent to oggenc -q0.5 + F32 quality = 0.05f; +// quality = (bitrate==128000 ? 0.4f : 0.1); + +// if (vorbis_encode_init(&vi, /* num_channels */ 1 ,sample_rate, -1, bitrate, -1)) + if (vorbis_encode_init_vbr(&vi, /* num_channels */ 1 ,sample_rate, quality)) +// if (vorbis_encode_setup_managed(&vi,1,sample_rate,-1,bitrate,-1) || +// vorbis_encode_ctl(&vi,OV_ECTL_RATEMANAGE_AVG,NULL) || +// vorbis_encode_setup_init(&vi)) + { + llwarns << "unable to initialize vorbis codec at quality " << quality << llendl; + // llwarns << "unable to initialize vorbis codec at bitrate " << bitrate << llendl; + return(LLVORBISENC_DEST_OPEN_ERR); + } + + /* add a comment */ + vorbis_comment_init(&vc); +// vorbis_comment_add(&vc,"Linden"); + + /* set up the analysis state and auxiliary encoding storage */ + vorbis_analysis_init(&vd,&vi); + vorbis_block_init(&vd,&vb); + + /* set up our packet->stream encoder */ + /* pick a random serial number; that way we can more likely build + chained streams just by concatenation */ + ogg_stream_init(&os, ll_rand()); + + /* Vorbis streams begin with three headers; the initial header (with + most of the codec setup parameters) which is mandated by the Ogg + bitstream spec. The second header holds any comment fields. The + third header holds the bitstream codebook. We merely need to + make the headers, then pass them to libvorbis one at a time; + libvorbis handles the additional Ogg bitstream constraints */ + + { + ogg_packet header; + ogg_packet header_comm; + ogg_packet header_code; + + vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code); + ogg_stream_packetin(&os,&header); /* automatically placed in its own + page */ + ogg_stream_packetin(&os,&header_comm); + ogg_stream_packetin(&os,&header_code); + + /* We don't have to write out here, but doing so makes streaming + * much easier, so we do, flushing ALL pages. This ensures the actual + * audio data will start on a new page + */ + while(!eos){ + int result=ogg_stream_flush(&os,&og); + if(result==0)break; + outfile.write(og.header, og.header_len); + outfile.write(og.body, og.body_len); + } + + } + + + while(!eos) + { + long bytes_per_sample = bits_per_sample/8; + + long bytes=(long)infile.read(readbuffer,llclamp((S32)(READ_BUFFER*num_channels*bytes_per_sample),0,data_left)); /* stereo hardwired here */ + + if (bytes==0) + { + /* end of file. this can be done implicitly in the mainline, + but it's easier to see here in non-clever fashion. + Tell the library we're at end of stream so that it can handle + the last frame and mark end of stream in the output properly */ + + vorbis_analysis_wrote(&vd,0); +// eos = 1; + + } + else + { + long i; + long samples; + int temp; + + data_left -= bytes; + /* data to encode */ + + /* expose the buffer to submit data */ + float **buffer=vorbis_analysis_buffer(&vd,READ_BUFFER); + + i = 0; + samples = bytes / (num_channels * bytes_per_sample); + + if (num_channels == 2) + { + if (bytes_per_sample == 2) + { + /* uninterleave samples */ + for(i=0; i +class LLWindGen +{ +public: + LLWindGen() : + mTargetGain(0.f), + mTargetFreq(100.f), + mTargetPanGainR(0.5f), + mbuf0(0.0), + mbuf1(0.0), + mbuf2(0.0), + mbuf3(0.0), + mbuf4(0.0), + mbuf5(0.0), + mY0(0.0), + mY1(0.0), + mCurrentGain(0.f), + mCurrentFreq(100.f), + mCurrentPanGainR(0.5f) {}; + + static const U32 getInputSamplingRate() {return mInputSamplingRate;} + + // newbuffer = the buffer passed from the previous DSP unit. + // numsamples = length in samples-per-channel at this mix time. + // stride = number of bytes between start of each sample. + // NOTE: generates L/R interleaved stereo + MIXBUFFERFORMAT_T* windGenerate(MIXBUFFERFORMAT_T *newbuffer, int numsamples, int stride) + { + U8 *cursamplep = (U8*)newbuffer; + + double bandwidth = 50.0F; + double a0,b1,b2; + + // calculate resonant filter coeffs + b2 = exp(-(F_TWO_PI) * (bandwidth / mInputSamplingRate)); + + while (numsamples--) + { + mCurrentFreq = (float)((0.999 * mCurrentFreq) + (0.001 * mTargetFreq)); + mCurrentGain = (float)((0.999 * mCurrentGain) + (0.001 * mTargetGain)); + mCurrentPanGainR = (float)((0.999 * mCurrentPanGainR) + (0.001 * mTargetPanGainR)); + b1 = (-4.0 * b2) / (1.0 + b2) * cos(F_TWO_PI * (mCurrentFreq / mInputSamplingRate)); + a0 = (1.0 - b2) * sqrt(1.0 - (b1 * b1) / (4.0 * b2)); + double nextSample; + + // start with white noise + nextSample = ll_frand(2.0f) - 1.0f; + + // apply pinking filter + mbuf0 = 0.997f * mbuf0 + 0.0126502f * nextSample; + mbuf1 = 0.985f * mbuf1 + 0.0139083f * nextSample; + mbuf2 = 0.950f * mbuf2 + 0.0205439f * nextSample; + mbuf3 = 0.850f * mbuf3 + 0.0387225f * nextSample; + mbuf4 = 0.620f * mbuf4 + 0.0465932f * nextSample; + mbuf5 = 0.250f * mbuf5 + 0.1093477f * nextSample; + + nextSample = mbuf0 + mbuf1 + mbuf2 + mbuf3 + mbuf4 + mbuf5; + + // do a resonant filter on the noise + nextSample = (double)( a0 * nextSample - b1 * mY0 - b2 * mY1 ); + mY1 = mY0; + mY0 = nextSample; + + nextSample *= mCurrentGain; + + MIXBUFFERFORMAT_T sample; + + sample = llfloor(((F32)nextSample*32768.f*(1.0f - mCurrentPanGainR))+0.5f); + *(MIXBUFFERFORMAT_T*)cursamplep = llclamp(sample, (MIXBUFFERFORMAT_T)-32768, (MIXBUFFERFORMAT_T)32767); + cursamplep += stride; + + sample = llfloor(((F32)nextSample*32768.f*mCurrentPanGainR)+0.5f); + *(MIXBUFFERFORMAT_T*)cursamplep = llclamp(sample, (MIXBUFFERFORMAT_T)-32768, (MIXBUFFERFORMAT_T)32767); + cursamplep += stride; + } + + return newbuffer; + } + + F32 mTargetGain; + F32 mTargetFreq; + F32 mTargetPanGainR; + +private: + static const U32 mInputSamplingRate = 44100; + F64 mbuf0; + F64 mbuf1; + F64 mbuf2; + F64 mbuf3; + F64 mbuf4; + F64 mbuf5; + F64 mY0; + F64 mY1; + F32 mCurrentGain; + F32 mCurrentFreq; + F32 mCurrentPanGainR; +}; + +#endif diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index e1f8ce53fb..24391eb8f3 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -56,7 +56,7 @@ const F32 ROTATION_MOTION_THRESHOLD = 0.001f; char gInFile[1024]; /* Flawfinder: ignore */ char gOutFile[1024]; /* Flawfinder: ignore */ - +/* //------------------------------------------------------------------------ // Status Codes //------------------------------------------------------------------------ @@ -91,7 +91,7 @@ const char *LLBVHLoader::ST_NO_XLT_EASEIN = "Can't get easeIn values."; const char *LLBVHLoader::ST_NO_XLT_EASEOUT = "Can't get easeOut values."; const char *LLBVHLoader::ST_NO_XLT_HAND = "Can't get hand morph value."; const char *LLBVHLoader::ST_NO_XLT_EMOTE = "Can't read emote name."; - +*/ //------------------------------------------------------------------------ // find_next_whitespace() //------------------------------------------------------------------------ @@ -124,7 +124,9 @@ LLQuaternion::Order bvhStringToOrder( char *str ) //----------------------------------------------------------------------------- // LLBVHLoader() //----------------------------------------------------------------------------- -LLBVHLoader::LLBVHLoader(const char* buffer) + +/* + LLBVHLoader::LLBVHLoader(const char* buffer) { reset(); @@ -144,7 +146,7 @@ LLBVHLoader::LLBVHLoader(const char* buffer) } } - char error_text[128]; /* Flawfinder: ignore */ + char error_text[128]; // Flawfinder: ignore S32 error_line; mStatus = loadBVHFile(buffer, error_text, error_line); if (mStatus != LLBVHLoader::ST_OK) @@ -158,6 +160,49 @@ LLBVHLoader::LLBVHLoader(const char* buffer) mInitialized = TRUE; } +*/ +LLBVHLoader::LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine) +{ + reset(); + errorLine = 0; + mStatus = loadTranslationTable("anim.ini"); + loadStatus = mStatus; + llinfos<<"Load Status 00 : "<< loadStatus << llendl; + if (mStatus == E_ST_NO_XLT_FILE) + { + //llwarns << "NOTE: No translation table found." << llendl; + loadStatus = mStatus; + return; + } + else + { + if (mStatus != E_ST_OK) + { + //llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + errorLine = getLineNumber(); + loadStatus = mStatus; + return; + } + } + + char error_text[128]; /* Flawfinder: ignore */ + S32 error_line; + mStatus = loadBVHFile(buffer, error_text, error_line); + + if (mStatus != E_ST_OK) + { + //llwarns << "ERROR: [line: " << getLineNumber() << "] " << mStatus << llendl; + loadStatus = mStatus; + errorLine = getLineNumber(); + return; + } + + applyTranslations(); + optimize(); + + mInitialized = TRUE; +} + LLBVHLoader::~LLBVHLoader() { @@ -167,7 +212,7 @@ LLBVHLoader::~LLBVHLoader() //------------------------------------------------------------------------ // LLBVHLoader::loadTranslationTable() //------------------------------------------------------------------------ -LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) +ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName) { mLineNumber = 0; mTranslations.clear(); @@ -182,7 +227,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) infile.open(path, LL_APR_R); apr_file_t *fp = infile.getFileHandle(); if (!fp) - return ST_NO_XLT_FILE; + return E_ST_NO_XLT_FILE; llinfos << "NOTE: Loading translation table: " << fileName << llendl; @@ -194,9 +239,9 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) // load header //-------------------------------------------------------------------- if ( ! getLine(fp) ) - return ST_EOF; + return E_ST_EOF; if ( strncmp(mLine, "Translations 1.0", 16) ) - return ST_NO_XLT_HEADER; + return E_ST_NO_XLT_HEADER; //-------------------------------------------------------------------- // load data one line at a time @@ -222,7 +267,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char name[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " [%127[^]]", name) != 1 ) - return ST_NO_XLT_NAME; + return E_ST_NO_XLT_NAME; if (strcmp(name, "GLOBALS")==0) { @@ -245,7 +290,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char emote_str[1024]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %1023s", emote_str) != 1 ) /* Flawfinder: ignore */ - return ST_NO_XLT_EMOTE; + return E_ST_NO_XLT_EMOTE; mEmoteName.assign( emote_str ); // llinfos << "NOTE: Emote: " << mEmoteName.c_str() << llendl; @@ -260,7 +305,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { S32 priority; if ( sscanf(mLine, " %*s = %d", &priority) != 1 ) - return ST_NO_XLT_PRIORITY; + return E_ST_NO_XLT_PRIORITY; mPriority = priority; // llinfos << "NOTE: Priority: " << mPriority << llendl; @@ -288,7 +333,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) } else { - return ST_NO_XLT_LOOP; + return E_ST_NO_XLT_LOOP; } mLoopInPoint = loop_in * mDuration; @@ -305,7 +350,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) F32 duration; char type[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */ - return ST_NO_XLT_EASEIN; + return E_ST_NO_XLT_EASEIN; mEaseIn = duration; continue; @@ -319,7 +364,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) F32 duration; char type[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %f %127s", &duration, type) != 2 ) /* Flawfinder: ignore */ - return ST_NO_XLT_EASEOUT; + return E_ST_NO_XLT_EASEOUT; mEaseOut = duration; continue; @@ -332,7 +377,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { S32 handMorph; if (sscanf(mLine, " %*s = %d", &handMorph) != 1) - return ST_NO_XLT_HAND; + return E_ST_NO_XLT_HAND; mHand = handMorph; continue; @@ -380,7 +425,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) &constraint.mTargetOffset.mV[VY], &constraint.mTargetOffset.mV[VZ]) != 13) { - return ST_NO_CONSTRAINT; + return E_ST_NO_CONSTRAINT; } } else @@ -440,7 +485,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) &constraint.mTargetOffset.mV[VY], &constraint.mTargetOffset.mV[VZ]) != 13) { - return ST_NO_CONSTRAINT; + return E_ST_NO_CONSTRAINT; } } else @@ -463,7 +508,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) // at this point there must be a valid trans pointer //---------------------------------------------------------------- if ( ! trans ) - return ST_NO_XLT_NAME; + return E_ST_NO_XLT_NAME; //---------------------------------------------------------------- // check for ignore flag @@ -472,7 +517,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char trueFalse[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %127s", trueFalse) != 1 ) /* Flawfinder: ignore */ - return ST_NO_XLT_IGNORE; + return E_ST_NO_XLT_IGNORE; trans->mIgnore = (LLStringUtil::compareInsensitive(trueFalse, "true")==0); continue; @@ -497,12 +542,12 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) } else { - return ST_NO_XLT_RELATIVE; + return E_ST_NO_XLT_RELATIVE; } } else { - return ST_NO_XLT_RELATIVE; + return E_ST_NO_XLT_RELATIVE; } continue; @@ -523,12 +568,12 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) } else { - return ST_NO_XLT_RELATIVE; + return E_ST_NO_XLT_RELATIVE; } } else { - return ST_NO_XLT_RELATIVE; + return E_ST_NO_XLT_RELATIVE; } continue; @@ -541,7 +586,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char outName[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %127s", outName) != 1 ) /* Flawfinder: ignore */ - return ST_NO_XLT_OUTNAME; + return E_ST_NO_XLT_OUTNAME; trans->mOutName = outName; continue; @@ -557,7 +602,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) &fm.mMatrix[0][0], &fm.mMatrix[0][1], &fm.mMatrix[0][2], &fm.mMatrix[1][0], &fm.mMatrix[1][1], &fm.mMatrix[1][2], &fm.mMatrix[2][0], &fm.mMatrix[2][1], &fm.mMatrix[2][2] ) != 9 ) - return ST_NO_XLT_MATRIX; + return E_ST_NO_XLT_MATRIX; trans->mFrameMatrix = fm; continue; @@ -573,7 +618,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) &om.mMatrix[0][0], &om.mMatrix[0][1], &om.mMatrix[0][2], &om.mMatrix[1][0], &om.mMatrix[1][1], &om.mMatrix[1][2], &om.mMatrix[2][0], &om.mMatrix[2][1], &om.mMatrix[2][2] ) != 9 ) - return ST_NO_XLT_MATRIX; + return E_ST_NO_XLT_MATRIX; trans->mOffsetMatrix = om; continue; @@ -586,7 +631,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char mergeParentName[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %127s", mergeParentName) != 1 ) /* Flawfinder: ignore */ - return ST_NO_XLT_MERGEPARENT; + return E_ST_NO_XLT_MERGEPARENT; trans->mMergeParentName = mergeParentName; continue; @@ -599,7 +644,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { char mergeChildName[128]; /* Flawfinder: ignore */ if ( sscanf(mLine, " %*s = %127s", mergeChildName) != 1 ) /* Flawfinder: ignore */ - return ST_NO_XLT_MERGECHILD; + return E_ST_NO_XLT_MERGECHILD; trans->mMergeChildName = mergeChildName; continue; @@ -612,7 +657,7 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) { S32 priority; if ( sscanf(mLine, " %*s = %d", &priority) != 1 ) - return ST_NO_XLT_PRIORITY; + return E_ST_NO_XLT_PRIORITY; trans->mPriorityModifier = priority; continue; @@ -621,14 +666,14 @@ LLBVHLoader::Status LLBVHLoader::loadTranslationTable(const char *fileName) } infile.close() ; - return ST_OK; + return E_ST_OK; } //------------------------------------------------------------------------ // LLBVHLoader::loadBVHFile() //------------------------------------------------------------------------ -LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line) +ELoadStatus LLBVHLoader::loadBVHFile(const char *buffer, char* error_text, S32 &err_line) { std::string line; @@ -650,14 +695,14 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex // consume hierarchy //-------------------------------------------------------------------- if (iter == tokens.end()) - return ST_EOF; + return E_ST_EOF; line = (*(iter++)); err_line++; if ( !strstr(line.c_str(), "HIERARCHY") ) { // llinfos << line << llendl; - return ST_NO_HIER; + return E_ST_NO_HIER; } //-------------------------------------------------------------------- @@ -669,7 +714,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex // get next line //---------------------------------------------------------------- if (iter == tokens.end()) - return ST_EOF; + return E_ST_EOF; line = (*(iter++)); err_line++; @@ -719,7 +764,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex else { strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ - return ST_NO_JOINT; + return E_ST_NO_JOINT; } //---------------------------------------------------------------- @@ -729,7 +774,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( sscanf(line.c_str(), "%*s %79s", jointName) != 1 ) /* Flawfinder: ignore */ { strncpy(error_text, line.c_str(), 127); /* Flawfinder: ignore */ - return ST_NO_NAME; + return E_ST_NO_NAME; } //---------------------------------------------------------------- @@ -754,7 +799,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex //---------------------------------------------------------------- if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -765,7 +810,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "{") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_OFFSET; + return E_ST_NO_OFFSET; } else { @@ -777,7 +822,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex //---------------------------------------------------------------- if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -788,7 +833,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "OFFSET") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_OFFSET; + return E_ST_NO_OFFSET; } //---------------------------------------------------------------- @@ -796,7 +841,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex //---------------------------------------------------------------- if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -807,7 +852,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "CHANNELS") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_CHANNELS; + return E_ST_NO_CHANNELS; } //---------------------------------------------------------------- @@ -820,14 +865,14 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if (!p) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_ROTATION; + return E_ST_NO_ROTATION; } const char axis = *(p - 1); if ((axis != 'X') && (axis != 'Y') && (axis != 'Z')) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_AXIS; + return E_ST_NO_AXIS; } joint->mOrder[i] = axis; @@ -842,7 +887,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "MOTION") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_MOTION; + return E_ST_NO_MOTION; } //-------------------------------------------------------------------- @@ -850,7 +895,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex //-------------------------------------------------------------------- if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -858,13 +903,13 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "Frames:") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_FRAMES; + return E_ST_NO_FRAMES; } if ( sscanf(line.c_str(), "Frames: %d", &mNumFrames) != 1 ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_FRAMES; + return E_ST_NO_FRAMES; } //-------------------------------------------------------------------- @@ -872,7 +917,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex //-------------------------------------------------------------------- if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -880,13 +925,13 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( !strstr(line.c_str(), "Frame Time:") ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_FRAME_TIME; + return E_ST_NO_FRAME_TIME; } if ( sscanf(line.c_str(), "Frame Time: %f", &mFrameTime) != 1 ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_FRAME_TIME; + return E_ST_NO_FRAME_TIME; } mDuration = (F32)mNumFrames * mFrameTime; @@ -903,7 +948,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex // get next line if (iter == tokens.end()) { - return ST_EOF; + return E_ST_EOF; } line = (*(iter++)); err_line++; @@ -922,7 +967,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( sscanf(p, "%f %f %f", key.mPos, key.mPos+1, key.mPos+2) != 3 ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_POS; + return E_ST_NO_POS; } } @@ -931,19 +976,19 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if (!p) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_ROT; + return E_ST_NO_ROT; } p = find_next_whitespace(++p); if (!p) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_ROT; + return E_ST_NO_ROT; } p = find_next_whitespace(++p); if (!p) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_ROT; + return E_ST_NO_ROT; } // get 3 rot values for joint @@ -951,7 +996,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex if ( sscanf(p, " %f %f %f", rot, rot+1, rot+2) != 3 ) { strncpy(error_text, line.c_str(), 127); /*Flawfinder: ignore*/ - return ST_NO_ROT; + return E_ST_NO_ROT; } p++; @@ -962,7 +1007,7 @@ LLBVHLoader::Status LLBVHLoader::loadBVHFile(const char *buffer, char* error_tex } } - return ST_OK; + return E_ST_OK; } diff --git a/indra/llcharacter/llbvhloader.h b/indra/llcharacter/llbvhloader.h index 6937b9d835..ecdfc95478 100644 --- a/indra/llcharacter/llbvhloader.h +++ b/indra/llcharacter/llbvhloader.h @@ -184,6 +184,41 @@ public: S32 mPriorityModifier; }; +typedef enum e_load_status + { + E_ST_OK, + E_ST_EOF, + E_ST_NO_CONSTRAINT, + E_ST_NO_FILE, + E_ST_NO_HIER, + E_ST_NO_JOINT, + E_ST_NO_NAME, + E_ST_NO_OFFSET, + E_ST_NO_CHANNELS, + E_ST_NO_ROTATION, + E_ST_NO_AXIS, + E_ST_NO_MOTION, + E_ST_NO_FRAMES, + E_ST_NO_FRAME_TIME, + E_ST_NO_POS, + E_ST_NO_ROT, + E_ST_NO_XLT_FILE, + E_ST_NO_XLT_HEADER, + E_ST_NO_XLT_NAME, + E_ST_NO_XLT_IGNORE, + E_ST_NO_XLT_RELATIVE, + E_ST_NO_XLT_OUTNAME, + E_ST_NO_XLT_MATRIX, + E_ST_NO_XLT_MERGECHILD, + E_ST_NO_XLT_MERGEPARENT, + E_ST_NO_XLT_PRIORITY, + E_ST_NO_XLT_LOOP, + E_ST_NO_XLT_EASEIN, + E_ST_NO_XLT_EASEOUT, + E_ST_NO_XLT_HAND, + E_ST_NO_XLT_EMOTE + } ELoadStatus; + //------------------------------------------------------------------------ // TranslationMap //------------------------------------------------------------------------ @@ -194,9 +229,11 @@ class LLBVHLoader friend class LLKeyframeMotion; public: // Constructor - LLBVHLoader(const char* buffer); +// LLBVHLoader(const char* buffer); + LLBVHLoader(const char* buffer, ELoadStatus &loadStatus, S32 &errorLine); ~LLBVHLoader(); - + +/* // Status Codes typedef const char *Status; static const char *ST_OK; @@ -230,13 +267,13 @@ public: static const char *ST_NO_XLT_EASEOUT; static const char *ST_NO_XLT_HAND; static const char *ST_NO_XLT_EMOTE; - +*/ // Loads the specified translation table. - Status loadTranslationTable(const char *fileName); + ELoadStatus loadTranslationTable(const char *fileName); // Load the specified BVH file. // Returns status code. - Status loadBVHFile(const char *buffer, char *error_text, S32 &error_line); + ELoadStatus loadBVHFile(const char *buffer, char *error_text, S32 &error_line); // Applies translations to BVH data loaded. void applyTranslations(); @@ -260,7 +297,7 @@ public: BOOL isInitialized() { return mInitialized; } - Status getStatus() { return mStatus; } + ELoadStatus getStatus() { return mStatus; } protected: // Consumes one line of input from file. @@ -287,7 +324,7 @@ protected: std::string mEmoteName; BOOL mInitialized; - Status mStatus; + ELoadStatus mStatus; // computed values F32 mDuration; }; diff --git a/indra/llcharacter/llcharacter.cpp b/indra/llcharacter/llcharacter.cpp index 6633c65317..20ff7bab34 100644 --- a/indra/llcharacter/llcharacter.cpp +++ b/indra/llcharacter/llcharacter.cpp @@ -180,9 +180,11 @@ void LLCharacter::requestStopMotion( LLMotion* motion) //----------------------------------------------------------------------------- // updateMotions() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_ANIMATION("Update Animation"); + void LLCharacter::updateMotions(e_update_t update_type) { - LLFastTimer t(LLFastTimer::FTM_UPDATE_ANIMATION); + LLFastTimer t(FTM_UPDATE_ANIMATION); if (update_type == HIDDEN_UPDATE) { mMotionController.updateMotionsMinimal(); diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 0112788884..cd8f9e63fb 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -42,7 +42,7 @@ #include "llmotioncontroller.h" #include "llvisualparam.h" #include "string_table.h" -#include "llmemory.h" +#include "llpointer.h" #include "llthread.h" class LLPolyMesh; @@ -169,7 +169,7 @@ public: void updateMotions(e_update_t update_type); LLAnimPauseRequest requestPause(); - BOOL areAnimationsPaused() { return mMotionController.isPaused(); } + BOOL areAnimationsPaused() const { return mMotionController.isPaused(); } void setAnimTimeFactor(F32 factor) { mMotionController.setTimeFactor(factor); } void setTimeStep(F32 time_step) { mMotionController.setTimeStep(time_step); } @@ -231,9 +231,9 @@ public: return (mCurIterator++)->second; } - LLVisualParam* getVisualParam(S32 id) + LLVisualParam* getVisualParam(S32 id) const { - VisualParamIndexMap_t::iterator iter = mVisualParamIndexMap.find(id); + VisualParamIndexMap_t::const_iterator iter = mVisualParamIndexMap.find(id); return (iter == mVisualParamIndexMap.end()) ? 0 : iter->second; } S32 getVisualParamID(LLVisualParam *id) @@ -246,11 +246,11 @@ public: } return 0; } - S32 getVisualParamCount() { return (S32)mVisualParamIndexMap.size(); } + S32 getVisualParamCount() const { return (S32)mVisualParamIndexMap.size(); } LLVisualParam* getVisualParam(const char *name); - ESex getSex() { return mSex; } + ESex getSex() const { return mSex; } void setSex( ESex sex ) { mSex = sex; } U32 getAppearanceSerialNum() const { return mAppearanceSerialNum; } diff --git a/indra/llcharacter/lljoint.h b/indra/llcharacter/lljoint.h index b1a0b74f85..0473d1599a 100644 --- a/indra/llcharacter/lljoint.h +++ b/indra/llcharacter/lljoint.h @@ -174,7 +174,7 @@ public: void clampRotation(LLQuaternion old_rot, LLQuaternion new_rot); - virtual BOOL isAnimatable() { return TRUE; } + virtual BOOL isAnimatable() const { return TRUE; } S32 getJointNum() const { return mJointNum; } void setJointNum(S32 joint_num) { mJointNum = joint_num; } diff --git a/indra/llcharacter/lljointstate.h b/indra/llcharacter/lljointstate.h index 16ad0e1200..e40cf2673f 100644 --- a/indra/llcharacter/lljointstate.h +++ b/indra/llcharacter/lljointstate.h @@ -37,7 +37,7 @@ // Header Files //----------------------------------------------------------------------------- #include "lljoint.h" -#include "llmemory.h" +#include "llrefcount.h" //----------------------------------------------------------------------------- // class LLJointState diff --git a/indra/llcharacter/llkeyframemotionparam.cpp b/indra/llcharacter/llkeyframemotionparam.cpp index 622405a5e1..c4333fc0fd 100644 --- a/indra/llcharacter/llkeyframemotionparam.cpp +++ b/indra/llcharacter/llkeyframemotionparam.cpp @@ -347,8 +347,11 @@ BOOL LLKeyframeMotionParam::loadMotions() // Load named file by concatenating the character prefix with the motion name. // Load data into a buffer to be parsed. //------------------------------------------------------------------------- - std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) - + "_" + getName() + ".llp"; + //std::string path = gDirUtilp->getExpandedFilename(LL_PATH_MOTIONS,mCharacter->getAnimationPrefix()) + // + "_" + getName() + ".llp"; + //RN: deprecated unused reference to "motion" directory + std::string path; + //------------------------------------------------------------------------- // open the file diff --git a/indra/llcharacter/llmotioncontroller.cpp b/indra/llcharacter/llmotioncontroller.cpp index 006d2b5f62..bb9625b2bd 100644 --- a/indra/llcharacter/llmotioncontroller.cpp +++ b/indra/llcharacter/llmotioncontroller.cpp @@ -1019,9 +1019,9 @@ bool LLMotionController::isMotionLoading(LLMotion* motion) //----------------------------------------------------------------------------- // findMotion() //----------------------------------------------------------------------------- -LLMotion* LLMotionController::findMotion(const LLUUID& id) +LLMotion* LLMotionController::findMotion(const LLUUID& id) const { - motion_map_t::iterator iter = mAllMotions.find(id); + motion_map_t::const_iterator iter = mAllMotions.find(id); if(iter == mAllMotions.end()) { return NULL; diff --git a/indra/llcharacter/llmotioncontroller.h b/indra/llcharacter/llmotioncontroller.h index 9271483a25..5c3ec223cb 100644 --- a/indra/llcharacter/llmotioncontroller.h +++ b/indra/llcharacter/llmotioncontroller.h @@ -153,12 +153,12 @@ public: // pause and continue all motions void pauseAllMotions(); void unpauseAllMotions(); - BOOL isPaused() { return mPaused; } + BOOL isPaused() const { return mPaused; } void setTimeStep(F32 step); void setTimeFactor(F32 time_factor); - F32 getTimeFactor() { return mTimeFactor; } + F32 getTimeFactor() const { return mTimeFactor; } motion_list_t& getActiveMotions() { return mActiveMotions; } @@ -167,7 +167,7 @@ public: //protected: bool isMotionActive( LLMotion *motion ); bool isMotionLoading( LLMotion *motion ); - LLMotion *findMotion( const LLUUID& id ); + LLMotion *findMotion( const LLUUID& id ) const; protected: // internal operations act on motion instances directly diff --git a/indra/llcharacter/llmultigesture.cpp b/indra/llcharacter/llmultigesture.cpp index 7fe21dbc93..05d1bc0cd9 100644 --- a/indra/llcharacter/llmultigesture.cpp +++ b/indra/llcharacter/llmultigesture.cpp @@ -50,6 +50,7 @@ const S32 GESTURE_VERSION = 2; LLMultiGesture::LLMultiGesture() : mKey(), mMask(), + mName(), mTrigger(), mReplaceText(), mSteps(), @@ -243,7 +244,7 @@ void LLMultiGesture::dump() //--------------------------------------------------------------------------- LLGestureStepAnimation::LLGestureStepAnimation() : LLGestureStep(), - mAnimName("None"), + mAnimName("None"), mAnimAssetID(), mFlags(0x0) { } @@ -292,20 +293,27 @@ BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp) dp.unpackU32(mFlags, "flags"); return TRUE; } - -std::string LLGestureStepAnimation::getLabel() const +// *TODO: Translate +std::vector LLGestureStepAnimation::getLabel() const { - std::string label; + std::vector strings; + +// std::string label; if (mFlags & ANIM_FLAG_STOP) { - label = "Stop Animation: "; + strings.push_back( "AnimFlagStop"); + +// label = "Stop Animation: "; } else { - label = "Start Animation: "; + strings.push_back( "AnimFlagStart"); + +// label = "Start Animation: "; } - label += mAnimName; - return label; + strings.push_back( mAnimName); +// label += mAnimName; + return strings; } void LLGestureStepAnimation::dump() @@ -359,12 +367,15 @@ BOOL LLGestureStepSound::deserialize(LLDataPacker& dp) dp.unpackU32(mFlags, "flags"); return TRUE; } - -std::string LLGestureStepSound::getLabel() const +// *TODO: Translate +std::vector LLGestureStepSound::getLabel() const { - std::string label("Sound: "); - label += mSoundName; - return label; + std::vector strings; + strings.push_back( "Sound"); + strings.push_back( mSoundName); +// std::string label("Sound: "); +// label += mSoundName; + return strings; } void LLGestureStepSound::dump() @@ -414,12 +425,13 @@ BOOL LLGestureStepChat::deserialize(LLDataPacker& dp) dp.unpackU32(mFlags, "flags"); return TRUE; } - -std::string LLGestureStepChat::getLabel() const +// *TODO: Translate +std::vector LLGestureStepChat::getLabel() const { - std::string label("Chat: "); - label += mChatText; - return label; + std::vector strings; + strings.push_back("Chat"); + strings.push_back(mChatText); + return strings; } void LLGestureStepChat::dump() @@ -467,22 +479,27 @@ BOOL LLGestureStepWait::deserialize(LLDataPacker& dp) dp.unpackU32(mFlags, "flags"); return TRUE; } - -std::string LLGestureStepWait::getLabel() const +// *TODO: Translate +std::vector LLGestureStepWait::getLabel() const { - std::string label("--- Wait: "); + std::vector strings; + strings.push_back( "Wait" ); + +// std::string label("--- Wait: "); if (mFlags & WAIT_FLAG_TIME) { char buffer[64]; /* Flawfinder: ignore */ snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */ - label += buffer; + strings.push_back(buffer); +// label += buffer; } else if (mFlags & WAIT_FLAG_ALL_ANIM) { - label += "until animations are done"; + strings.push_back("until animations are done"); + // label += "until animations are done"; } - return label; + return strings; } diff --git a/indra/llcharacter/llmultigesture.h b/indra/llcharacter/llmultigesture.h index eb15f600ca..fdcf32dc67 100644 --- a/indra/llcharacter/llmultigesture.h +++ b/indra/llcharacter/llmultigesture.h @@ -65,11 +65,13 @@ protected: const LLMultiGesture& operator=(const LLMultiGesture& rhs); public: - // name is stored at asset level - // desc is stored at asset level KEY mKey; MASK mMask; + // This name can be empty if the inventory item is not around and + // the gesture manager has not yet set the name + std::string mName; + // String, like "/foo" or "hello" that makes it play std::string mTrigger; @@ -130,7 +132,7 @@ public: virtual EStepType getType() = 0; // Return a user-readable label for this step - virtual std::string getLabel() const = 0; + virtual std::vector getLabel() const = 0; virtual S32 getMaxSerialSize() const = 0; virtual BOOL serialize(LLDataPacker& dp) const = 0; @@ -152,7 +154,7 @@ public: virtual EStepType getType() { return STEP_ANIMATION; } - virtual std::string getLabel() const; + virtual std::vector getLabel() const; virtual S32 getMaxSerialSize() const; virtual BOOL serialize(LLDataPacker& dp) const; @@ -175,7 +177,7 @@ public: virtual EStepType getType() { return STEP_SOUND; } - virtual std::string getLabel() const; + virtual std::vector getLabel() const; virtual S32 getMaxSerialSize() const; virtual BOOL serialize(LLDataPacker& dp) const; @@ -198,7 +200,7 @@ public: virtual EStepType getType() { return STEP_CHAT; } - virtual std::string getLabel() const; + virtual std::vector getLabel() const; virtual S32 getMaxSerialSize() const; virtual BOOL serialize(LLDataPacker& dp) const; @@ -223,7 +225,7 @@ public: virtual EStepType getType() { return STEP_WAIT; } - virtual std::string getLabel() const; + virtual std::vector getLabel() const; virtual S32 getMaxSerialSize() const; virtual BOOL serialize(LLDataPacker& dp) const; diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp index 93255d702c..dd4880dbb9 100644 --- a/indra/llcharacter/llpose.cpp +++ b/indra/llcharacter/llpose.cpp @@ -516,9 +516,9 @@ BOOL LLPoseBlender::addMotion(LLMotion* motion) void LLPoseBlender::blendAndApply() { for (blender_list_t::iterator iter = mActiveBlenders.begin(); - iter != mActiveBlenders.end(); ++iter) + iter != mActiveBlenders.end(); ) { - LLJointStateBlender* jsbp = *iter; + LLJointStateBlender* jsbp = *iter++; jsbp->blendJointStates(); } diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h index 5698f21614..2b976b219d 100644 --- a/indra/llcharacter/llpose.h +++ b/indra/llcharacter/llpose.h @@ -36,12 +36,14 @@ //----------------------------------------------------------------------------- // Header Files //----------------------------------------------------------------------------- -#include -#include "llmap.h" #include "lljointstate.h" #include "lljoint.h" +#include "llmap.h" +#include "llpointer.h" + #include +#include //----------------------------------------------------------------------------- diff --git a/indra/llcharacter/llvisualparam.h b/indra/llcharacter/llvisualparam.h index 3a0c1bbc77..25c41e8509 100644 --- a/indra/llcharacter/llvisualparam.h +++ b/indra/llcharacter/llvisualparam.h @@ -112,7 +112,7 @@ public: virtual void stopAnimating(BOOL set_by_user); // Interface methods - S32 getID() { return mID; } + S32 getID() const { return mID; } void setID(S32 id) { llassert(!mInfo); mID = id; } const std::string& getName() const { return mInfo->mName; } @@ -124,22 +124,22 @@ public: void setMaxDisplayName(const std::string& s) { mInfo->mMaxName = s; } void setMinDisplayName(const std::string& s) { mInfo->mMinName = s; } - EVisualParamGroup getGroup() { return mInfo->mGroup; } - F32 getMinWeight() { return mInfo->mMinWeight; } - F32 getMaxWeight() { return mInfo->mMaxWeight; } - F32 getDefaultWeight() { return mInfo->mDefaultWeight; } - ESex getSex() { return mInfo->mSex; } + EVisualParamGroup getGroup() const { return mInfo->mGroup; } + F32 getMinWeight() const { return mInfo->mMinWeight; } + F32 getMaxWeight() const { return mInfo->mMaxWeight; } + F32 getDefaultWeight() const { return mInfo->mDefaultWeight; } + ESex getSex() const { return mInfo->mSex; } - F32 getWeight() { return mIsAnimating ? mTargetWeight : mCurWeight; } - F32 getCurrentWeight() { return mCurWeight; } - F32 getLastWeight() { return mLastWeight; } - BOOL isAnimating() { return mIsAnimating; } + F32 getWeight() const { return mIsAnimating ? mTargetWeight : mCurWeight; } + F32 getCurrentWeight() const { return mCurWeight; } + F32 getLastWeight() const { return mLastWeight; } + BOOL isAnimating() const { return mIsAnimating; } LLVisualParam* getNextParam() { return mNext; } void setNextParam( LLVisualParam *next ); virtual void setAnimating(BOOL is_animating) { mIsAnimating = is_animating; } - BOOL getAnimating() { return mIsAnimating; } + BOOL getAnimating() const { return mIsAnimating; } protected: F32 mCurWeight; // current weight diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 7bfcd43684..a93623d24e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,7 +3,9 @@ project(llcommon) include(00-Common) +include(LLAddBuildTest) include(LLCommon) +include(Boost) include_directories( ${EXPAT_INCLUDE_DIRS} @@ -11,7 +13,14 @@ include_directories( ${ZLIB_INCLUDE_DIRS} ) +# add_executable(lltreeiterators lltreeiterators.cpp) +# +# target_link_libraries(lltreeiterators +# ${LLCOMMON_LIBRARIES}) + set(llcommon_SOURCE_FILES + llallocator.cpp + llallocator_heap_profile.cpp llapp.cpp llapr.cpp llassettype.cpp @@ -40,11 +49,16 @@ set(llcommon_SOURCE_FILES llmd5.cpp llmemory.cpp llmemorystream.cpp + llmemtype.cpp llmetrics.cpp llmortician.cpp + lloptioninterface.cpp + llptrto.cpp + llprocesslauncher.cpp llprocessor.cpp llqueuedthread.cpp llrand.cpp + llrefcount.cpp llrun.cpp llsd.cpp llsdserialize.cpp @@ -52,6 +66,7 @@ set(llcommon_SOURCE_FILES llsdutil.cpp llsecondlifeurls.cpp llstat.cpp + llstacktrace.cpp llstreamtools.cpp llstring.cpp llstringtable.cpp @@ -78,6 +93,8 @@ set(llcommon_HEADER_FILES indra_constants.h linden_common.h linked_lists.h + llallocator.h + llallocator_heap_profile.h llagentconstants.h llapp.h llapr.h @@ -98,9 +115,11 @@ set(llcommon_HEADER_FILES lldate.h lldefs.h lldependencies.h + lldeleteutils.h lldepthstack.h lldictionary.h lldlinked.h + lldoubledispatch.h lldqueueptr.h llendianswizzle.h llenum.h @@ -122,6 +141,7 @@ set(llcommon_HEADER_FILES llheartbeat.h llhttpstatuscodes.h llindexedqueue.h + llinstancetracker.h llkeythrottle.h lllazy.h lllinkedqueue.h @@ -138,23 +158,32 @@ set(llcommon_HEADER_FILES llmetrics.h llmortician.h llnametable.h + lloptioninterface.h + llpointer.h llpreprocessor.h llpriqueuemap.h + llprocesslauncher.h llprocessor.h llptrskiplist.h llptrskipmap.h + llptrto.h llqueuedthread.h llrand.h + llrefcount.h llrun.h + llrefcount.h + llsafehandle.h llsd.h llsdserialize.h llsdserialize_xml.h llsdutil.h llsecondlifeurls.h llsimplehash.h + llsingleton.h llskiplist.h llskipmap.h llstack.h + llstacktrace.h llstat.h llstatenums.h llstl.h @@ -165,6 +194,7 @@ set(llcommon_HEADER_FILES llsys.h llthread.h lltimer.h + lltreeiterators.h lluri.h lluuid.h lluuidhashmap.h @@ -200,6 +230,8 @@ target_link_libraries( ${APR_LIBRARIES} ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} + ${BOOST_PROGRAM_OPTIONS_LIBRARY} + ${BOOST_REGEX_LIBRARY} ) include(LLAddBuildTest) @@ -209,3 +241,11 @@ SET(llcommon_TEST_SOURCE_FILES ) LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}") +#set(TEST_DEBUG on) +set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) +LL_ADD_INTEGRATION_TEST(lllazy lllazy.cpp "${test_libs}") + +# *TODO - reenable these once tcmalloc libs no longer break the build. +#ADD_BUILD_TEST(llallocator llcommon) +#ADD_BUILD_TEST(llallocator_heap_profile llcommon) +#ADD_BUILD_TEST(llmemtype llcommon) diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h index f95b148590..d369fbc5b3 100644 --- a/indra/llcommon/is_approx_equal_fraction.h +++ b/indra/llcommon/is_approx_equal_fraction.h @@ -7,7 +7,30 @@ * making llcommon depend on llmath. * * $LicenseInfo:firstyear=2009&license=viewergpl$ + * * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index f9d5877ab2..9adf24a492 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -33,6 +33,11 @@ #ifndef LL_LINDEN_COMMON_H #define LL_LINDEN_COMMON_H +// *NOTE: Please keep includes here to a minimum! +// +// Files included here are included in every library .cpp file and +// are not precompiled. + #if defined(LL_WINDOWS) && defined(_DEBUG) # if _MSC_VER >= 1400 // Visual C++ 2005 or later # define _CRTDBG_MAP_ALLOC @@ -51,23 +56,22 @@ #include #include #include -#include -#include +#include -// Work Microsoft compiler warnings +// Work around Microsoft compiler warnings in STL headers #ifdef LL_WINDOWS #pragma warning (disable : 4702) // unreachable code #pragma warning (disable : 4244) // conversion from time_t to S32 #endif // LL_WINDOWS -#include #include #include #include #include #ifdef LL_WINDOWS -#pragma warning (3 : 4702) // we like level 3, not 4 +// Reenable warnings we disabled above +#pragma warning (3 : 4702) // unreachable code, we like level 3, not 4 // level 4 warnings that we need to disable: #pragma warning (disable : 4100) // unreferenced formal parameter #pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) @@ -78,6 +82,7 @@ #endif // LL_WINDOWS // Linden only libs in alpha-order other than stdtypes.h +// *NOTE: Please keep includes here to a minimum, see above. #include "stdtypes.h" #include "lldefs.h" #include "llerror.h" @@ -85,8 +90,5 @@ #include "llfasttimer.h" #include "llfile.h" #include "llformat.h" -#include "llstring.h" -#include "llsys.h" -#include "lltimer.h" #endif diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp new file mode 100644 index 0000000000..eed9d1e7db --- /dev/null +++ b/indra/llcommon/llallocator.cpp @@ -0,0 +1,140 @@ +/** + * @file llallocator.cpp + * @brief Implementation of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llallocator.h" + +#if LL_USE_TCMALLOC + +#include "google/heap-profiler.h" +#include "google/commandlineflags_public.h" + +DECLARE_bool(heap_profile_use_stack_trace); +//DECLARE_double(tcmalloc_release_rate); + +// static +void LLAllocator::pushMemType(S32 type) +{ + if(isProfiling()) + { + PushMemType(type); + } +} + +// static +S32 LLAllocator::popMemType() +{ + if (isProfiling()) + { + return PopMemType(); + } + else + { + return -1; + } +} + +void LLAllocator::setProfilingEnabled(bool should_enable) +{ + // NULL disables dumping to disk + static char const * const PREFIX = NULL; + if(should_enable) + { + HeapProfilerSetUseStackTrace(false); + HeapProfilerStart(PREFIX); + } + else + { + HeapProfilerStop(); + } +} + +// static +bool LLAllocator::isProfiling() +{ + return IsHeapProfilerRunning(); +} + +std::string LLAllocator::getRawProfile() +{ + // *TODO - fix google-perftools to accept an buffer to avoid this + // malloc-copy-free cycle. + char * buffer = GetHeapProfile(); + std::string ret = buffer; + free(buffer); + return ret; +} + +#else // LL_USE_TCMALLOC + +// +// stub implementations for when tcmalloc is disabled +// + +// static +void LLAllocator::pushMemType(S32 type) +{ +} + +// static +S32 LLAllocator::popMemType() +{ + return -1; +} + +void LLAllocator::setProfilingEnabled(bool should_enable) +{ +} + +// static +bool LLAllocator::isProfiling() +{ + return false; +} + +std::string LLAllocator::getRawProfile() +{ + return std::string(); +} + +#endif // LL_USE_TCMALLOC + +LLAllocatorHeapProfile const & LLAllocator::getProfile() +{ + mProf.mLines.clear(); + + // *TODO - avoid making all these extra copies of things... + std::string prof_text = getRawProfile(); + //std::cout << prof_text << std::endl; + mProf.parse(prof_text); + return mProf; +} diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h new file mode 100644 index 0000000000..2b70fee0b8 --- /dev/null +++ b/indra/llcommon/llallocator.h @@ -0,0 +1,63 @@ +/** + * @file llallocator.h + * @brief Declaration of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_H +#define LL_LLALLOCATOR_H + +#include + +#include "llmemtype.h" +#include "llallocator_heap_profile.h" + +class LLAllocator { + friend class LLMemoryView; + friend class LLMemType; + +private: + static void pushMemType(S32 type); + static S32 popMemType(); + +public: + void setProfilingEnabled(bool should_enable); + + static bool isProfiling(); + + LLAllocatorHeapProfile const & getProfile(); + +private: + std::string getRawProfile(); + +private: + LLAllocatorHeapProfile mProf; +}; + +#endif // LL_LLALLOCATOR_H diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp new file mode 100644 index 0000000000..d82ee9ed81 --- /dev/null +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -0,0 +1,149 @@ +/** + * @file llallocator_heap_profile.cpp + * @brief Implementation of the parser for tcmalloc heap profile data. + * @author Brad Kittenbrink + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llallocator_heap_profile.h" + +#if LL_MSVC +// disable warning about boost::lexical_cast returning uninitialized data +// when it fails to parse the string +#pragma warning (disable:4701) +#endif + +#include +#include +#include +#include + +static const std::string HEAP_PROFILE_MAGIC_STR = "heap profile:"; + +static bool is_separator(char c) +{ + return isspace(c) || c == '[' || c == ']' || c == ':'; +} + +void LLAllocatorHeapProfile::parse(std::string const & prof_text) +{ + // a typedef for handling a token in the string buffer + // it's a begin/end pair of string::const_iterators + typedef boost::iterator_range range_t; + + mLines.clear(); + + if(prof_text.compare(0, HEAP_PROFILE_MAGIC_STR.length(), HEAP_PROFILE_MAGIC_STR) != 0) + { + // *TODO - determine if there should be some better error state than + // mLines being empty. -brad + llwarns << "invalid heap profile data passed into parser." << llendl; + return; + } + + std::vector< range_t > prof_lines; + + std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length(); + + range_t prof_range(prof_begin, prof_text.end()); + boost::algorithm::split(prof_lines, + prof_range, + boost::bind(std::equal_to(), '\n', _1)); + + std::vector< range_t >::const_iterator i; + for(i = prof_lines.begin(); i != prof_lines.end() && !i->empty(); ++i) + { + range_t const & line_text = *i; + + std::vector line_elems; + + boost::algorithm::split(line_elems, + line_text, + is_separator); + + std::vector< range_t >::iterator j; + j = line_elems.begin(); + + while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens + llassert_always(j != line_elems.end()); + U32 live_count = boost::lexical_cast(*j); + ++j; + + while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens + llassert_always(j != line_elems.end()); + U64 live_size = boost::lexical_cast(*j); + ++j; + + while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens + llassert_always(j != line_elems.end()); + U32 tot_count = boost::lexical_cast(*j); + ++j; + + while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens + llassert_always(j != line_elems.end()); + U64 tot_size = boost::lexical_cast(*j); + ++j; + + while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens + llassert_always(j != line_elems.end()); + ++j; // skip the '@' + + mLines.push_back(line(live_count, live_size, tot_count, tot_size)); + line & current_line = mLines.back(); + + for(; j != line_elems.end(); ++j) + { + if(!j->empty()) { + U32 marker = boost::lexical_cast(*j); + current_line.mTrace.push_back(marker); + } + } + } + + // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it +} + +void LLAllocatorHeapProfile::dump(std::ostream & out) const +{ + lines_t::const_iterator i; + for(i = mLines.begin(); i != mLines.end(); ++i) + { + out << i->mLiveCount << ": " << i->mLiveSize << '[' << i->mTotalCount << ": " << i->mTotalSize << "] @"; + + stack_trace::const_iterator j; + for(j = i->mTrace.begin(); j != i->mTrace.end(); ++j) + { + out << ' ' << *j; + } + out << '\n'; + } + out.flush(); +} + diff --git a/indra/llcommon/llallocator_heap_profile.h b/indra/llcommon/llallocator_heap_profile.h new file mode 100644 index 0000000000..19758df544 --- /dev/null +++ b/indra/llcommon/llallocator_heap_profile.h @@ -0,0 +1,77 @@ +/** + * @file llallocator_heap_profile.h + * @brief Declaration of the parser for tcmalloc heap profile data. + * @author Brad Kittenbrink + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_HEAP_PROFILE_H +#define LL_LLALLOCATOR_HEAP_PROFILE_H + +#include "stdtypes.h" + +#include +#include + +class LLAllocatorHeapProfile +{ +public: + typedef int stack_marker; + + typedef std::vector stack_trace; + + struct line { + line(U32 live_count, U64 live_size, U32 tot_count, U64 tot_size) : + mLiveSize(live_size), + mTotalSize(tot_size), + mLiveCount(live_count), + mTotalCount(tot_count) + { + } + U64 mLiveSize, mTotalSize; + U32 mLiveCount, mTotalCount; + stack_trace mTrace; + }; + + typedef std::vector lines_t; + + LLAllocatorHeapProfile() + { + } + + void parse(std::string const & prof_text); + + void dump(std::ostream & out) const; + +public: + lines_t mLines; +}; + + +#endif // LL_LLALLOCATOR_HEAP_PROFILE_H diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index cc60ba0b80..e32a293f1c 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -37,6 +37,7 @@ #include "llapr.h" #include "llrun.h" #include "llsd.h" +#include "lloptioninterface.h" // Forward declarations class LLErrorThread; @@ -61,7 +62,7 @@ public: }; #endif -class LLApp +class LLApp : public LLOptionInterface { friend class LLErrorThread; public: @@ -110,7 +111,7 @@ public: * @param name The name of the option. * @return Returns the option data. */ - LLSD getOption(const std::string& name) const; + virtual LLSD getOption(const std::string& name) const; /** * @brief Parse command line options and insert them into diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index b852e4c00f..6d4043b8e0 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -35,6 +35,7 @@ #include "llassettype.h" #include "lldictionary.h" #include "llmemory.h" +#include "llsingleton.h" ///---------------------------------------------------------------------------- /// Class LLAssetType @@ -100,7 +101,7 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, FALSE, TRUE)); + addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE)); addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE)); @@ -115,7 +116,7 @@ LLAssetDictionary::LLAssetDictionary() } addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("CURRENT", "current", "current outfit", "Current Outfit", DAD_CATEGORY, FALSE, TRUE)); - addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "Outfit", DAD_CATEGORY, TRUE, FALSE)); + addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", "New Outfit", DAD_CATEGORY, TRUE, FALSE)); addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", "My Outfits", DAD_CATEGORY, FALSE, TRUE)); addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, "New Folder", DAD_NONE, FALSE, FALSE)); @@ -281,6 +282,15 @@ bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type) return true; } +// static +bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type) +{ + return (asset_type >= AT_FOLDER_ENSEMBLE_START && + asset_type <= AT_FOLDER_ENSEMBLE_END); + } + return true; +} + // static. Generate a good default description void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 5c30c8354f..880b7a19b5 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -187,6 +187,7 @@ public: static const char* lookupCategoryName(EType asset_type); static bool lookupIsProtectedCategoryType(EType asset_type); + static bool lookupIsEnsembleCategoryType(EType asset_type); /* TODO: Change return types from "const char *" to "const std::string &". This is fairly straightforward, but requires changing some calls to use .c_str(). diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h index 4df9dbf3bd..c2bde3a097 100644 --- a/indra/llcommon/llboost.h +++ b/indra/llcommon/llboost.h @@ -46,4 +46,19 @@ */ typedef boost::tokenizer > boost_tokenizer; +// Useful combiner for boost signals that return a bool (e.g. validation) +// returns false if any of the callbacks return false +struct boost_boolean_combiner +{ + typedef bool result_type; + template + bool operator()(InputIterator first, InputIterator last) const + { + bool res = true; + while (first != last) + res &= *first++; + return res; + } +}; + #endif // LL_LLBOOST_H diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 2cbb71855f..36a0018995 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -32,6 +32,8 @@ #include "linden_common.h" #include "llcommon.h" + +#include "llmemory.h" #include "llthread.h" //static diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index 5f77988336..a1808e8a6c 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -32,9 +32,8 @@ #ifndef LL_COMMON_H #define LL_COMMON_H -#include "llmemory.h" +// *TODO: remove these? #include "llapr.h" -// #include "llframecallbackmanager.h" #include "lltimer.h" #include "llfile.h" diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 41a3af398f..7bc9e16bc9 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -38,10 +38,13 @@ #include "apr_time.h" #include +#include +#include #include #include #include "lltimer.h" +#include "llstring.h" static const F64 DATE_EPOCH = 0.0; @@ -88,45 +91,36 @@ std::string LLDate::asString() const // is one of the standards used and the prefered format std::string LLDate::asRFC1123() const { - std::ostringstream stream; - toHTTPDateStream(stream); - return stream.str(); + return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } -void LLDate::toHTTPDateStream(std::ostream& s) const +std::string LLDate::toHTTPDateString (std::string fmt) const { - // http://apr.apache.org/docs/apr/0.9/group__apr__time.html - apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + std::ostringstream stream; + time_t locSeconds = (time_t) mSecondsSinceEpoch; + struct tm * gmt = gmtime (&locSeconds); - apr_time_exp_t exp_time ; //Apache time module + stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); + toHTTPDateStream (stream, gmt, fmt); + return stream.str(); +} - if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) - { - // Return Epoch UTC date - s << "Thursday, 01 Jan 1970 00:00:00 GMT" ; - return; - } +std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) +{ + std::ostringstream stream; + stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); + toHTTPDateStream (stream, gmt, fmt); + return stream.str(); +} - s << std::dec << std::setfill('0'); -#if( LL_WINDOWS || __GNUC__ > 2) - s << std::right ; -#else - s.setf(ios::right); -#endif - std::string day = weekdays[exp_time.tm_wday]; - std::string month = months[exp_time.tm_mon]; +void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt) +{ + using namespace std; - s << std::setw(day.length()) << (day) - << ", " << std::setw(2) << (exp_time.tm_mday) - << ' ' << std::setw(month.length()) << (month) - << ' ' << std::setw(4) << (exp_time.tm_year + 1900) - << ' ' << std::setw(2) << (exp_time.tm_hour) - << ':' << std::setw(2) << (exp_time.tm_min) - << ':' << std::setw(2) << (exp_time.tm_sec) - << " GMT"; - - // RFC 1123 date does not use microseconds - //llinfos << "Date in RFC 1123 format is " << s << llendl; + const char * pBeg = fmt.c_str(); + const char * pEnd = pBeg + fmt.length(); + const time_put& tp = use_facet >(s.getloc()); + tp.put (s, s, s.fill(), gmt, pBeg, pEnd); } void LLDate::toStream(std::ostream& s) const diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 7cc9c8aceb..23d3b900f8 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -84,7 +84,9 @@ public: std::string asString() const; std::string asRFC1123() const; void toStream(std::ostream&) const; - void toHTTPDateStream(std::ostream&) const; + std::string toHTTPDateString (std::string fmt) const; + static std::string toHTTPDateString (tm * gmt, std::string fmt); + static void toHTTPDateStream(std::ostream&, tm *, std::string); /** * @brief Set the date from an ISO-8601 string. * diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h new file mode 100644 index 0000000000..d6a0945e46 --- /dev/null +++ b/indra/llcommon/lldeleteutils.h @@ -0,0 +1,53 @@ +/** + * @file lldeleteutils.h + * @brief Utility functions to simplify some common pointer-munging idioms. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LL_DELETE_UTILS_H +#define LL_DELETE_UTILS_H + +// Simple utility functions to eventually replace the common 2-line +// idiom scattered throughout the viewer codebase. Note that where +// possible we would rather be using smart pointers of some sort. + +template +inline void deleteAndClear(T*& ptr) +{ + delete ptr; + ptr = NULL; +} + +template +inline void deleteAndClearArray(T*& array_ptr) +{ + delete[] array_ptr; + array_ptr = NULL; +} + +#endif diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index bd4bd7c96a..82f53c6e17 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -581,6 +581,8 @@ public: return sorted_range(begin, end); } + using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; + /// Override base-class describe() with actual implementation virtual std::ostream& describe(std::ostream& out, bool full=true) const { @@ -597,6 +599,7 @@ public: return out; } + /// describe() helper: report a DepNodeEntry static std::ostream& describe(std::ostream& out, std::string& sep, const DepNodeMapEntry& entry, bool full) diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h new file mode 100755 index 0000000000..60678d44fb --- /dev/null +++ b/indra/llcommon/lldoubledispatch.h @@ -0,0 +1,332 @@ +/** + * @file lldoubledispatch.h + * @author Nat Goodspeed + * @date 2008-11-11 + * @brief function calls virtual on more than one parameter + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLDOUBLEDISPATCH_H) +#define LL_LLDOUBLEDISPATCH_H + +#include +#include +#include +#include +#include + +/** + * This class supports function calls which are virtual on the dynamic type of + * more than one parameter. Specifically, we address a limited but useful + * subset of that problem: function calls which accept two parameters, and + * select which particular function to call depending on the dynamic type of + * both. + * + * Scott Meyers, in More Effective C++ (Item 31), talks about some of the perils + * and pitfalls lurking down this pathway. He discusses and dismisses the + * straightforward approaches of using single-dispatch virtual functions twice, + * and of using a family of single-dispatch virtual functions which each examine + * RTTI for their other parameter. He advocates using a registry in which you + * look up the actual types of both parameters (he uses the classes' string names, + * via typeid(param).name()) to obtain a pointer to a free (non-member) function + * that will accept this pair of parameters. + * + * He does point out that his approach doesn't handle inheritance. If you have a + * registry entry for SpaceShip, and you have in hand a MilitaryShip (subclass of + * SpaceShip) and an Asteroid, you'd like to call the function appropriate for + * SpaceShips and Asteroids -- but alas, his lookup fails because the class name + * for your MilitaryShip subclass isn't in the registry. + * + * This class extends his idea to build a registry whose entries can examine the + * dynamic type of the parameter in a more flexible way -- using dynamic_cast<> + * -- thereby supporting inheritance relationships. + * + * Of course we must allow for the ambiguity this permits. We choose to use a + * sequence container rather than a map, and require that the client code + * specify the order in which dispatch-table entries should be searched. The + * result resembles the semantics of the catch clauses for a try/catch block: + * you must code catch clauses in decreasing order of specificity, because if + * you catch ErrorBaseClass before you catch ErrorSubclass, then any + * ErrorSubclass exceptions thrown by the protected code will always match + * ErrorBaseClass, and you will never reach your catch(ErrorSubclass) clause. + * + * So, in a similar way, if you have a specific routine to process + * MilitaryShip and Asteroid, you'd better place that in the table @em before + * your more general routine that processes SpaceShip and Asteroid, or else + * the MilitaryShip variant will never be called. + * + * @todo This implementation doesn't attempt to deal with + * const-correctness of arguments. Our container stores templated + * objects into which the specific parameter types have been "frozen." But to + * store all these in the same container, they are all instances of a base + * class with a virtual invocation method. Naturally the base-class virtual + * method definition cannot know the const-ness of the particular + * types with which its template subclass is instantiated. + * + * One is tempted to suggest four different virtual methods, one for each + * combination of @c const and non-const arguments. Then the client + * will select the particular virtual method that best fits the + * const-ness of the arguments in hand. The trouble with that idea is + * that in order to instantiate the subclass instance, we must compile all + * four of its virtual method overrides, which means we must be prepared to + * pass all four combinations of @c const and non-const arguments to + * the registered callable. That only works when the registered callable + * accepts both parameters as @c const. + * + * Of course the virtual method overrides could use @c const_cast to force + * them to compile correctly regardless of the const-ness of the + * registered callable's parameter declarations. But if we're going to force + * the issue with @c const_cast anyway, why bother with the four different + * virtual methods? Why not just require canonical parameter + * const-ness for any callables used with this mechanism? + * + * We therefore require that your callable accept both params as + * non-const. (This is more general than @c const: you can perform @c + * const operations on a non-const parameter, but you can't perform + * non-const operations on a @c const parameter.) + * + * For ease of use, though, our invocation method accepts both params as @c + * const. Again, you can pass a non-const object to a @c const param, + * but not the other way around. We take care of the @c const_cast for you. + */ +// LLDoubleDispatch is a template because we have to assume that all parameter +// types are subclasses of some common base class -- but we don't have to +// impose that base class on client code. Instead, we let IT tell US the +// common parameter base class. +template +class LLDoubleDispatch +{ + typedef LLDoubleDispatch self_type; + +public: + LLDoubleDispatch() {} + + /** + * Call the first matching entry. If there's no registered Functor + * appropriate for this pair of parameter types, this call will do + * @em nothing! (If you want notification in this case, simply add a new + * Functor for (ParamBaseType&, ParamBaseType&) at the end of the table. + * The two base-class entries should match anything that isn't matched by + * any more specific entry.) + * + * See note in class documentation about const-correctness. + */ + inline + ReturnType operator()(const ParamBaseType& param1, const ParamBaseType& param2) const; + + // Borrow a trick from Alexandrescu: use a Type class to "wrap" a type + // for purposes of passing the type itself into a template method. + template + struct Type {}; + + /** + * Add a new Entry for a given @a Functor. As mentioned above, the order + * in which you add these entries is very important. + * + * If you want symmetrical entries -- that is, if a B and an A can call + * the same Functor as an A and a B -- then pass @c true for the last + * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But + * your @a Functor can still be written to expect exactly the pair of types + * you've explicitly specified, because the Entry with the reversed params + * will call a special thunk that swaps params before calling your @a + * Functor. + */ + template + void add(const Type& t1, const Type& t2, Functor func, bool symmetrical=false) + { + insert(t1, t2, func); + if (symmetrical) + { + // Use boost::bind() to construct a param-swapping thunk. Don't + // forget to reverse the parameters too. + insert(t2, t1, boost::bind(func, _2, _1)); + } + } + + /** + * Add a new Entry for a given @a Functor, explicitly passing instances of + * the Functor's leaf param types to help us figure out where to insert. + * Because it can use RTTI, this add() method isn't order-sensitive like + * the other one. + * + * If you want symmetrical entries -- that is, if a B and an A can call + * the same Functor as an A and a B -- then pass @c true for the last + * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But + * your @a Functor can still be written to expect exactly the pair of types + * you've explicitly specified, because the Entry with the reversed params + * will call a special thunk that swaps params before calling your @a + * Functor. + */ + template + void add(const Type1& prototype1, const Type2& prototype2, Functor func, bool symmetrical=false) + { + // Because we expect our caller to pass leaf param types, we can just + // perform an ordinary search to find the first matching iterator. If + // we find an existing Entry that matches both params, either the + // param types are the same, or the existing Entry uses the base class + // for one or both params, and the new Entry must precede that. Assume + // our client won't register two callables with exactly the SAME set + // of types; in that case we'll insert the new one before any earlier + // ones, meaning the last one registered will "win." Note that if + // find() doesn't find any matching Entry, it will return end(), + // meaning the new Entry will be last, which is fine. + typename DispatchTable::iterator insertion = find(prototype1, prototype2); + insert(Type(), Type(), func, insertion); + if (symmetrical) + { + insert(Type(), Type(), boost::bind(func, _2, _1), insertion); + } + } + + /** + * Add a new Entry for a given @a Functor, specifying the Functor's leaf + * param types as explicit template arguments. This will instantiate + * temporary objects of each of these types, which requires that they have + * a lightweight default constructor. + * + * If you want symmetrical entries -- that is, if a B and an A can call + * the same Functor as an A and a B -- then pass @c true for the last + * parameter, and we'll add a (B, A) entry as well as an (A, B) entry. But + * your @a Functor can still be written to expect exactly the pair of types + * you've explicitly specified, because the Entry with the reversed params + * will call a special thunk that swaps params before calling your @a + * Functor. + */ + template + void add(Functor func, bool symmetrical=false) + { + // This is a convenience wrapper for the add() variant taking explicit + // instances. + add(Type1(), Type2(), func, symmetrical); + } + +private: + /// This is the base class for each entry in our dispatch table. + struct EntryBase + { + virtual ~EntryBase() {} + virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const = 0; + virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const = 0; + }; + + /// Here's the template subclass that actually creates each entry. + template + class Entry: public EntryBase + { + public: + Entry(Functor func): mFunc(func) {} + /// Is this entry appropriate for these arguments? + virtual bool matches(const ParamBaseType& param1, const ParamBaseType& param2) const + { + return (dynamic_cast(¶m1) && + dynamic_cast(¶m2)); + } + /// invocation + virtual ReturnType operator()(ParamBaseType& param1, ParamBaseType& param2) const + { + // We perform the downcast so callable can accept leaf param + // types, instead of accepting ParamBaseType and downcasting + // explicitly. + return mFunc(dynamic_cast(param1), dynamic_cast(param2)); + } + private: + /// Bind whatever function or function object the instantiator passed. + Functor mFunc; + }; + + /// shared_ptr manages Entry lifespan for us + typedef boost::shared_ptr EntryPtr; + /// use a @c list to make it easy to insert + typedef std::list DispatchTable; + DispatchTable mDispatch; + + /// Look up the location of the first matching entry. + typename DispatchTable::const_iterator find(const ParamBaseType& param1, const ParamBaseType& param2) const + { + // We assert that it's safe to call the non-const find() method on a + // const LLDoubleDispatch instance. Cast away the const-ness of 'this'. + return const_cast(this)->find(param1, param2); + } + + /// Look up the location of the first matching entry. + typename DispatchTable::iterator find(const ParamBaseType& param1, const ParamBaseType& param2) + { + return std::find_if(mDispatch.begin(), mDispatch.end(), + boost::bind(&EntryBase::matches, _1, + boost::ref(param1), boost::ref(param2))); + } + + /// Look up the first matching entry. + EntryPtr lookup(const ParamBaseType& param1, const ParamBaseType& param2) const + { + typename DispatchTable::const_iterator found = find(param1, param2); + if (found != mDispatch.end()) + { + // Dereferencing the list iterator gets us an EntryPtr + return *found; + } + // not found + return EntryPtr(); + } + + // Break out the actual insert operation so the public add() template + // function can avoid calling itself recursively. See add() comments. + template + void insert(const Type& param1, const Type& param2, Functor func) + { + insert(param1, param2, func, mDispatch.end()); + } + + // Break out the actual insert operation so the public add() template + // function can avoid calling itself recursively. See add() comments. + template + void insert(const Type&, const Type&, Functor func, + typename DispatchTable::iterator where) + { + mDispatch.insert(where, EntryPtr(new Entry(func))); + } + + /// Don't implement the copy ctor. Everyone will be happier if the + /// LLDoubleDispatch object isn't copied. + LLDoubleDispatch(const LLDoubleDispatch& src); +}; + +template +ReturnType LLDoubleDispatch::operator()(const ParamBaseType& param1, + const ParamBaseType& param2) const +{ + EntryPtr found = lookup(param1, param2); + if (found.get() == 0) + return ReturnType(); // bogus return value + + // otherwise, call the Functor we found + return (*found)(const_cast(param1), const_cast(param2)); +} + +#endif /* ! defined(LL_LLDOUBLEDISPATCH_H) */ diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 8102eddb18..77c0c2294a 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -53,12 +53,11 @@ #include "llapp.h" #include "llapr.h" #include "llfile.h" -#include "llfixedbuffer.h" #include "lllivefile.h" #include "llsd.h" #include "llsdserialize.h" #include "llstl.h" - +#include "lltimer.h" namespace { #if !LL_WINDOWS @@ -192,16 +191,16 @@ namespace { class RecordToFixedBuffer : public LLError::Recorder { public: - RecordToFixedBuffer(LLFixedBuffer& buffer) : mBuffer(buffer) { } + RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { } virtual void recordMessage(LLError::ELevel level, - const std::string& message) + const std::string& message) { - mBuffer.addLine(message); + mBuffer->addLine(message); } private: - LLFixedBuffer& mBuffer; + LLLineBuffer* mBuffer; }; #if LL_WINDOWS @@ -209,7 +208,7 @@ namespace { { public: virtual void recordMessage(LLError::ELevel level, - const std::string& message) + const std::string& message) { llutf16string utf16str = wstring_to_utf16str(utf8str_to_wstring(message)); @@ -792,7 +791,7 @@ namespace LLError addRecorder(f); } - void logToFixedBuffer(LLFixedBuffer* fixedBuffer) + void logToFixedBuffer(LLLineBuffer* fixedBuffer) { LLError::Settings& s = LLError::Settings::get(); @@ -805,7 +804,7 @@ namespace LLError return; } - s.fixedBufferRecorder = new RecordToFixedBuffer(*fixedBuffer); + s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); addRecorder(s.fixedBufferRecorder); } diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index c9424f8a5e..fab0a1ef9f 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -38,7 +38,6 @@ #include "boost/function.hpp" #include -class LLFixedBuffer; class LLSD; /* @@ -49,6 +48,18 @@ class LLSD; These implementations are in llerror.cpp. */ +// Line buffer interface +class LLLineBuffer +{ +public: + LLLineBuffer() {}; + virtual ~LLLineBuffer() {}; + + virtual void clear() = 0; // Clear the buffer, and reset it. + + virtual void addLine(const std::string& utf8line) = 0; +}; + namespace LLError { @@ -73,6 +84,7 @@ namespace LLError void setFunctionLevel(const std::string& function_name, LLError::ELevel); void setClassLevel(const std::string& class_name, LLError::ELevel); void setFileLevel(const std::string& file_name, LLError::ELevel); + void setTagLevel(const std::string& file_name, LLError::ELevel); void configure(const LLSD&); // the LLSD can configure all of the settings @@ -143,7 +155,7 @@ namespace LLError // each error message is passed to each recorder via recordMessage() void logToFile(const std::string& filename); - void logToFixedBuffer(LLFixedBuffer*); + void logToFixedBuffer(LLLineBuffer*); // Utilities to add recorders for logging to a file or a fixed buffer // A second call to the same function will remove the logger added // with the first. diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp index 4c779c58c8..f0e46ae78d 100644 --- a/indra/llcommon/llerrorthread.cpp +++ b/indra/llcommon/llerrorthread.cpp @@ -31,7 +31,9 @@ #include "linden_common.h" #include "llerrorthread.h" + #include "llapp.h" +#include "lltimer.h" // ms_sleep() LLErrorThread::LLErrorThread() : LLThread("Error"), diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index a74ddbd091..2cc8577219 100644 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -35,7 +35,7 @@ #define LL_EVENT_H #include "llsd.h" -#include "llmemory.h" +#include "llpointer.h" #include "llthread.h" namespace LLOldEvents diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index f70d532e4c..240adcdd41 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -22,7 +22,16 @@ #include #include #include +#if LL_WINDOWS + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) +#endif #include +#if LL_WINDOWS + #pragma warning (pop) +#endif + #include #include #include @@ -38,7 +47,7 @@ #include #include #include "llsd.h" -#include "llmemory.h" +#include "llsingleton.h" #include "lldependencies.h" // override this to allow binding free functions with more parameters diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 94b51119e4..0d89353dee 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -30,229 +30,215 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFASTTIMER_H -#define LL_LLFASTTIMER_H +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H + +#include "llinstancetracker.h" #define FAST_TIMER_ON 1 U64 get_cpu_clock_count(); +class LLMutex; + +#include +#include "llsd.h" + + class LLFastTimer { public: - enum EFastTimerType + // stores a "named" timer instance to be reused via multiple LLFastTimer stack instances + class NamedTimer + : public LLInstanceTracker { - // high level - FTM_FRAME, - FTM_UPDATE, - FTM_RENDER, - FTM_SWAP, - FTM_CLIENT_COPY, - FTM_IDLE, - FTM_SLEEP, + public: + ~NamedTimer(); - // common messaging components - FTM_PUMP, - FTM_CURL, + enum { HISTORY_NUM = 60 }; + + const std::string& getName() { return mName; } + NamedTimer* getParent() { return mParent; } + void setParent(NamedTimer* parent); + S32 getDepth(); + std::string getToolTip(S32 history_index = -1); + + typedef std::vector::const_iterator child_const_iter; + child_const_iter beginChildren(); + child_const_iter endChildren(); + std::vector& getChildren(); + + void setCollapsed(bool collapsed) { mCollapsed = collapsed; } + bool getCollapsed() const { return mCollapsed; } + + U64 getCountAverage() const { return mCountAverage; } + U64 getCallAverage() const { return mCallAverage; } + + U64 getHistoricalCount(S32 history_index = 0) const; + U64 getHistoricalCalls(S32 history_index = 0) const; + + static NamedTimer& getRootNamedTimer(); + + struct FrameState + { + FrameState(NamedTimer* timerp); + + U64 mSelfTimeCounter; + U64 mLastStartTime; // most recent time when this timer was started + U32 mCalls; + FrameState* mParent; // info for caller timer + FrameState* mLastCaller; // used to bootstrap tree construction + NamedTimer* mTimer; + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + }; + + FrameState& getFrameStateFast() const + { + return (*sTimerInfos)[mFrameStateIndex]; + } + + S32 getFrameStateIndex() const { return mFrameStateIndex; } + + FrameState& getFrameState() const; + + + private: + friend class LLFastTimer; + friend class NamedTimerFactory; + + // + // methods + // + NamedTimer(const std::string& name); + // recursive call to gather total time from children + static void accumulateTimings(); + + // called once per frame by LLFastTimer + static void processFrame(); + + static void buildHierarchy(); + static void resetFrame(); + static void reset(); + + typedef std::vector info_list_t; + static info_list_t& getFrameStateList(); + static void createFrameStateList(); // must call before any call to getFrameStateList() - // common simulation components - FTM_UPDATE_ANIMATION, - FTM_UPDATE_TERRAIN, - FTM_UPDATE_PRIMITIVES, - FTM_UPDATE_PARTICLES, - FTM_SIMULATE_PARTICLES, - FTM_UPDATE_SKY, - FTM_UPDATE_TEXTURES, - FTM_UPDATE_WLPARAM, - FTM_UPDATE_WATER, - FTM_UPDATE_CLOUDS, - FTM_UPDATE_GRASS, - FTM_UPDATE_TREE, - FTM_UPDATE_AVATAR, - - // common render components - FTM_SHADOW_GEOMETRY, - FTM_SHADOW_RENDER, - FTM_SHADOW_TERRAIN, - FTM_SHADOW_AVATAR, - FTM_SHADOW_SIMPLE, - FTM_SHADOW_ALPHA, - FTM_SHADOW_TREE, - - FTM_RENDER_GEOMETRY, - FTM_RENDER_TERRAIN, - FTM_RENDER_SIMPLE, - FTM_RENDER_FULLBRIGHT, - FTM_RENDER_GLOW, - FTM_RENDER_GRASS, - FTM_RENDER_INVISIBLE, - FTM_RENDER_SHINY, - FTM_RENDER_BUMP, - FTM_RENDER_TREES, - FTM_RENDER_CHARACTERS, - FTM_RENDER_OCCLUSION, - FTM_RENDER_ALPHA, - FTM_RENDER_CLOUDS, - FTM_RENDER_HUD, - FTM_RENDER_PARTICLES, - FTM_RENDER_WATER, - FTM_RENDER_WL_SKY, - FTM_RENDER_FAKE_VBO_UPDATE, - FTM_RENDER_TIMER, - FTM_RENDER_UI, - FTM_RENDER_BLOOM, - FTM_RENDER_BLOOM_FBO, - FTM_RENDER_FONTS, - - // newview specific - FTM_MESSAGES, - FTM_MOUSEHANDLER, - FTM_KEYHANDLER, - FTM_REBUILD, - FTM_STATESORT, - FTM_STATESORT_DRAWABLE, - FTM_STATESORT_POSTSORT, - FTM_REBUILD_VBO, - FTM_REBUILD_VOLUME_VB, - FTM_REBUILD_BRIDGE_VB, - FTM_REBUILD_HUD_VB, - FTM_REBUILD_TERRAIN_VB, - FTM_REBUILD_WATER_VB, - FTM_REBUILD_TREE_VB, - FTM_REBUILD_PARTICLE_VB, - FTM_REBUILD_CLOUD_VB, - FTM_REBUILD_GRASS_VB, - FTM_REBUILD_NONE_VB, - FTM_REBUILD_OCCLUSION_VB, - FTM_POOLS, - FTM_POOLRENDER, - FTM_IDLE_CB, - FTM_WORLD_UPDATE, - FTM_UPDATE_MOVE, - FTM_OCTREE_BALANCE, - FTM_UPDATE_LIGHTS, - FTM_CULL, - FTM_CULL_REBOUND, - FTM_FRUSTUM_CULL, - FTM_GEO_UPDATE, - FTM_GEO_RESERVE, - FTM_GEO_LIGHT, - FTM_GEO_SHADOW, - FTM_GEO_SKY, - FTM_GEN_VOLUME, - FTM_GEN_TRIANGLES, - FTM_GEN_FLEX, - FTM_AUDIO_UPDATE, - FTM_RESET_DRAWORDER, - FTM_OBJECTLIST_UPDATE, - FTM_AVATAR_UPDATE, - FTM_JOINT_UPDATE, - FTM_ATTACHMENT_UPDATE, - FTM_LOD_UPDATE, - FTM_REGION_UPDATE, - FTM_CLEANUP, - FTM_NETWORK, - FTM_IDLE_NETWORK, - FTM_CREATE_OBJECT, - FTM_LOAD_AVATAR, - FTM_PROCESS_MESSAGES, - FTM_PROCESS_OBJECTS, - FTM_PROCESS_IMAGES, - FTM_IMAGE_UPDATE, - FTM_IMAGE_CREATE, - FTM_IMAGE_DECODE, - FTM_IMAGE_MARK_DIRTY, - FTM_PIPELINE, - FTM_VFILE_WAIT, - FTM_FLEXIBLE_UPDATE, - FTM_OCCLUSION_READBACK, - FTM_HUD_EFFECTS, - FTM_HUD_UPDATE, - FTM_INVENTORY, - FTM_AUTO_SELECT, - FTM_ARRANGE, - FTM_FILTER, - FTM_REFRESH, - FTM_SORT, - FTM_PICK, - - // Temp - FTM_TEMP1, - FTM_TEMP2, - FTM_TEMP3, - FTM_TEMP4, - FTM_TEMP5, - FTM_TEMP6, - FTM_TEMP7, - FTM_TEMP8, - - FTM_OTHER, // Special, used by display code - - FTM_NUM_TYPES + // + // members + // + S32 mFrameStateIndex; + + std::string mName; + + U64 mTotalTimeCounter; + + U64 mCountAverage; + U64 mCallAverage; + + U64* mCountHistory; + U64* mCallHistory; + + // tree structure + NamedTimer* mParent; // NamedTimer of caller(parent) + std::vector mChildren; + bool mCollapsed; // don't show children + bool mNeedsSorting; // sort children whenever child added + + static info_list_t* sTimerInfos; }; - enum { FTM_HISTORY_NUM = 60 }; - enum { FTM_MAX_DEPTH = 64 }; - + + // used to statically declare a new named timer + class DeclareTimer + { + public: + DeclareTimer(const std::string& name, bool open); + DeclareTimer(const std::string& name); + + // convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) + operator NamedTimer::FrameState&() { return mNamedTimer.getFrameStateFast(); } + private: + NamedTimer& mNamedTimer; + }; + + public: - static LLFastTimer::EFastTimerType sCurType; + enum RootTimerMarker { ROOT }; + + static LLMutex* sLogLock; + static std::queue sLogQueue; + static BOOL sLog; + static BOOL sMetricLog; - LLFastTimer(EFastTimerType type) + LLFastTimer(RootTimerMarker); + + LLFastTimer(NamedTimer::FrameState& timer) + : mFrameState(&timer) { #if FAST_TIMER_ON - mType = type; - sCurType = type; - // These don't get counted, because they use CPU clockticks - //gTimerBins[gCurTimerBin]++; - //LLTimer::sNumTimerCalls++; + NamedTimer::FrameState* frame_state = mFrameState; + frame_state->mLastStartTime = get_cpu_clock_count(); + mStartSelfTime = frame_state->mLastStartTime; - U64 cpu_clocks = get_cpu_clock_count(); - - sStart[sCurDepth] = cpu_clocks; - sCurDepth++; -#endif - }; - ~LLFastTimer() - { -#if FAST_TIMER_ON - U64 end,delta; - int i; - - // These don't get counted, because they use CPU clockticks - //gTimerBins[gCurTimerBin]++; - //LLTimer::sNumTimerCalls++; - end = get_cpu_clock_count(); - - sCurDepth--; - delta = end - sStart[sCurDepth]; - sCounter[mType] += delta; - sCalls[mType]++; - // Subtract delta from parents - for (i=0; imActiveCount++; + frame_state->mCalls++; + // keep current parent as long as it is active when we are + frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); + + mLastTimer = sCurTimer; + sCurTimer = this; #endif } + ~LLFastTimer() + { +#if FAST_TIMER_ON + NamedTimer::FrameState* frame_state = mFrameState; + U64 cur_time = get_cpu_clock_count(); + frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + + frame_state->mActiveCount--; + LLFastTimer* last_timer = mLastTimer; + sCurTimer = last_timer; + + // store last caller to bootstrap tree creation + frame_state->mLastCaller = last_timer->mFrameState; + + // we are only tracking self time, so subtract our total time delta from parents + U64 total_time = cur_time - frame_state->mLastStartTime; + last_timer->mStartSelfTime += total_time; +#endif + } + + + // call this once a frame to reset timers + static void nextFrame(); + + // call this to reset timer hierarchy, averages, etc. static void reset(); + static U64 countsPerSecond(); + static S32 getLastFrameIndex() { return sLastFrameIndex; } + static S32 getCurFrameIndex() { return sCurFrameIndex; } + + static void writeLog(std::ostream& os); + static const NamedTimer* getTimerByName(const std::string& name); public: - static int sCurDepth; - static U64 sStart[FTM_MAX_DEPTH]; - static U64 sCounter[FTM_NUM_TYPES]; - static U64 sCalls[FTM_NUM_TYPES]; - static U64 sCountAverage[FTM_NUM_TYPES]; - static U64 sCallAverage[FTM_NUM_TYPES]; - static U64 sCountHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES]; - static U64 sCallHistory[FTM_HISTORY_NUM][FTM_NUM_TYPES]; - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static int sPauseHistory; - static int sResetHistory; - static F64 sCPUClockFrequency; + static bool sPauseHistory; + static bool sResetHistory; private: - EFastTimerType mType; + typedef std::vector timer_stack_t; + static LLFastTimer* sCurTimer; + static S32 sCurFrameIndex; + static S32 sLastFrameIndex; + + static F64 sCPUClockFrequency; + U64 mStartSelfTime; // start time + time of all child timers + NamedTimer::FrameState* mFrameState; + LLFastTimer* mLastTimer; }; - #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index e9d6029378..1f6a06c247 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -32,20 +32,21 @@ #include "llfixedbuffer.h" +//////////////////////////////////////////////////////////////////////////// + LLFixedBuffer::LLFixedBuffer(const U32 max_lines) - : mMutex(NULL) + : LLLineBuffer(), + mMaxLines(max_lines), + mMutex(NULL) { - mMaxLines = max_lines; mTimer.reset(); } - LLFixedBuffer::~LLFixedBuffer() { clear(); } - void LLFixedBuffer::clear() { mMutex.lock() ; @@ -61,10 +62,10 @@ void LLFixedBuffer::clear() void LLFixedBuffer::addLine(const std::string& utf8line) { LLWString wstring = utf8str_to_wstring(utf8line); - LLFixedBuffer::addLine(wstring); + addWLine(wstring); } -void LLFixedBuffer::addLine(const LLWString& line) +void LLFixedBuffer::addWLine(const LLWString& line) { if (line.empty()) { diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h index 992a024df1..01b46d327a 100644 --- a/indra/llcommon/llfixedbuffer.h +++ b/indra/llcommon/llfixedbuffer.h @@ -38,14 +38,14 @@ #include #include "llstring.h" #include "llthread.h" +#include "llerrorcontrol.h" -// Fixed size buffer for console output and other things. - -class LLFixedBuffer +// fixed buffer implementation +class LLFixedBuffer : public LLLineBuffer { public: LLFixedBuffer(const U32 max_lines = 20); - virtual ~LLFixedBuffer(); + ~LLFixedBuffer(); LLTimer mTimer; U32 mMaxLines; @@ -53,22 +53,18 @@ public: std::deque mAddTimes; std::deque mLineLengths; - void clear(); // Clear the buffer, and reset it. + /*virtual*/ void clear(); // Clear the buffer, and reset it. - //do not make these two "virtual" - void addLine(const std::string& utf8line); - void addLine(const LLWString& line); + /*virtual*/ void addLine(const std::string& utf8line); - // Get lines currently in the buffer, up to max_size chars, max_length lines - char *getLines(U32 max_size = 0, U32 max_length = 0); void setMaxLines(S32 max_lines); + protected: - virtual void removeExtraLines(); + void removeExtraLines(); + void addWLine(const LLWString& line); protected: LLMutex mMutex ; }; -const U32 FIXED_BUF_MAX_LINE_LEN = 255; // Not including termnating 0 - #endif //LL_FIXED_BUFFER_H diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h new file mode 100644 index 0000000000..ea50acbbc5 --- /dev/null +++ b/indra/llcommon/llinstancetracker.h @@ -0,0 +1,121 @@ +/** + * @file llinstancetracker.h + * @brief LLInstanceTracker is a mixin class that automatically tracks object + * instances with or without an associated key + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINSTANCETRACKER_H +#define LL_LLINSTANCETRACKER_H + +#include + +#include "string_table.h" +#include + +// This mix-in class adds support for tracking all instances of the specified class parameter T +// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup +// If KEY is not provided, then instances are stored in a simple set +// *NOTE: see explicit specialization below for default KEY==T* case +template +class LLInstanceTracker : boost::noncopyable +{ +public: + typedef typename std::map::iterator instance_iter; + typedef typename std::map::const_iterator instance_const_iter; + + static T* getInstance(const KEY& k) { instance_iter found = getMap().find(k); return (found == getMap().end()) ? NULL : found->second; } + + static instance_iter beginInstances() { return getMap().begin(); } + static instance_iter endInstances() { return getMap().end(); } + static S32 instanceCount() { return getMap().size(); } +protected: + LLInstanceTracker(KEY key) { add(key); } + virtual ~LLInstanceTracker() { remove(); } + virtual void setKey(KEY key) { remove(); add(key); } + virtual const KEY& getKey() const { return mKey; } + +private: + void add(KEY key) + { + mKey = key; + getMap()[key] = static_cast(this); + } + void remove() { getMap().erase(mKey); } + + static std::map& getMap() + { + if (! sInstances) + { + sInstances = new std::map; + } + return *sInstances; + } + +private: + + KEY mKey; + static std::map* sInstances; +}; + +// explicit specialization for default case where KEY is T* +// use a simple std::set +template +class LLInstanceTracker +{ +public: + typedef typename std::set::iterator instance_iter; + typedef typename std::set::const_iterator instance_const_iter; + + static instance_iter beginInstances() { return getSet().begin(); } + static instance_iter endInstances() { return getSet().end(); } + static S32 instanceCount() { return getSet().size(); } + +protected: + LLInstanceTracker() { getSet().insert(static_cast(this)); } + virtual ~LLInstanceTracker() { getSet().erase(static_cast(this)); } + + LLInstanceTracker(const LLInstanceTracker& other) { getSet().insert(static_cast(this)); } + + static std::set& getSet() // called after getReady() but before go() + { + if (! sInstances) + { + sInstances = new std::set; + } + return *sInstances; + } + + static std::set* sInstances; +}; + +template std::map* LLInstanceTracker::sInstances = NULL; +template std::set* LLInstanceTracker::sInstances = NULL; + +#endif diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 14b4f9f4b0..da9cb94e13 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -83,6 +83,7 @@ documentation and/or software. #include "llmd5.h" #include +#include // cerr // how many bytes to grab at a time when checking files const int LLMD5::BLOCK_LEN = 4096; diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index a6de3d2d69..2a8015e26d 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -44,7 +44,6 @@ #endif #include "llmemory.h" -#include "llmemtype.h" //---------------------------------------------------------------------------- @@ -74,162 +73,6 @@ void LLMemory::freeReserve() reserveMem = NULL; } - -//---------------------------------------------------------------------------- - -//static -#if MEM_TRACK_TYPE -S32 LLMemType::sCurDepth = 0; -S32 LLMemType::sCurType = LLMemType::MTYPE_INIT; -S32 LLMemType::sType[LLMemType::MTYPE_MAX_DEPTH]; -S32 LLMemType::sMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sMaxMemCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sNewCount[LLMemType::MTYPE_NUM_TYPES] = { 0 }; -S32 LLMemType::sOverheadMem = 0; - -const char* LLMemType::sTypeDesc[LLMemType::MTYPE_NUM_TYPES] = -{ - "INIT", - "STARTUP", - "MAIN", - - "IMAGEBASE", - "IMAGERAW", - "IMAGEFORMATTED", - - "APPFMTIMAGE", - "APPRAWIMAGE", - "APPAUXRAWIMAGE", - - "DRAWABLE", - "OBJECT", - "PIPELINE", - "AVATAR", - "PARTICLES", - "REGIONS", - "INVENTORY", - "ANIMATION", - "NETWORK", - "PHYSICS", - "INTERESTLIST", - - "SCRIPT", - "SCRIPT_RUN", - "SCRIPT_BYTECODE", - - "IO_PUMP", - "IO_TCP", - "IO_BUFFER", - "IO_HTTP_SERVER" - "IO_SD_SERVER", - "IO_SD_CLIENT", - "IO_URL_REQUEST", - - "TEMP1", - "TEMP2", - "TEMP3", - "TEMP4", - "TEMP5", - "TEMP6", - "TEMP7", - "TEMP8", - "TEMP9" -}; - -#endif -S32 LLMemType::sTotalMem = 0; -S32 LLMemType::sMaxTotalMem = 0; - -//static -void LLMemType::printMem() -{ - S32 misc_mem = sTotalMem; -#if MEM_TRACK_TYPE - for (S32 i=0; i>20,sMaxMemCount[i]>>20, sNewCount[i]) << llendl; - } - misc_mem -= sMemCount[i]; - } -#endif - llinfos << llformat("MEM: % 20s %03d MB","MISC",misc_mem>>20) << llendl; - llinfos << llformat("MEM: % 20s %03d MB (Max=%d MB)","TOTAL",sTotalMem>>20,sMaxTotalMem>>20) << llendl; -} - -#if MEM_TRACK_MEM - -void* ll_allocate (size_t size) -{ - if (size == 0) - { - llwarns << "Null allocation" << llendl; - } - - size = (size+3)&~3; - S32 alloc_size = size + 4; -#if MEM_TRACK_TYPE - alloc_size += 4; -#endif - char* p = (char*)malloc(alloc_size); - if (p == NULL) - { - LLMemory::freeReserve(); - llerrs << "Out of memory Error" << llendl; - } - LLMemType::sTotalMem += size; - LLMemType::sMaxTotalMem = llmax(LLMemType::sTotalMem, LLMemType::sMaxTotalMem); - LLMemType::sOverheadMem += 4; - *(size_t*)p = size; - p += 4; -#if MEM_TRACK_TYPE - if (LLMemType::sCurType < 0 || LLMemType::sCurType >= LLMemType::MTYPE_NUM_TYPES) - { - llerrs << "Memory Type Error: new" << llendl; - } - LLMemType::sOverheadMem += 4; - *(S32*)p = LLMemType::sCurType; - p += 4; - LLMemType::sMemCount[LLMemType::sCurType] += size; - if (LLMemType::sMemCount[LLMemType::sCurType] > LLMemType::sMaxMemCount[LLMemType::sCurType]) - { - LLMemType::sMaxMemCount[LLMemType::sCurType] = LLMemType::sMemCount[LLMemType::sCurType]; - } - LLMemType::sNewCount[LLMemType::sCurType]++; -#endif - return (void*)p; -} - -void ll_release (void *pin) -{ - if (!pin) - { - return; - } - char* p = (char*)pin; -#if MEM_TRACK_TYPE - p -= 4; - S32 type = *(S32*)p; - if (type < 0 || type >= LLMemType::MTYPE_NUM_TYPES) - { - llerrs << "Memory Type Error: delete" << llendl; - } -#endif - p -= 4; - S32 size = *(size_t*)p; - LLMemType::sOverheadMem -= 4; -#if MEM_TRACK_TYPE - LLMemType::sMemCount[type] -= size; - LLMemType::sOverheadMem -= 4; - LLMemType::sNewCount[type]--; -#endif - LLMemType::sTotalMem -= size; - free(p); -} - -#else - void* ll_allocate (size_t size) { if (size == 0) @@ -250,52 +93,11 @@ void ll_release (void *p) free(p); } -#endif - -#if MEM_TRACK_MEM - -void* operator new (size_t size) -{ - return ll_allocate(size); -} - -void* operator new[] (size_t size) -{ - return ll_allocate(size); -} - -void operator delete (void *p) -{ - ll_release(p); -} - -void operator delete[] (void *p) -{ - ll_release(p); -} - -#endif - -//---------------------------------------------------------------------------- - -LLRefCount::LLRefCount() : - mRef(0) -{ -} - -LLRefCount::~LLRefCount() -{ - if (mRef != 0) - { - llerrs << "deleting non-zero reference" << llendl; - } -} - //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS() { HANDLE self = GetCurrentProcess(); PROCESS_MEMORY_COUNTERS counters; @@ -333,7 +135,7 @@ U64 getCurrentRSS() // } // } -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS() { U64 residentSize = 0; task_basic_info_data_t basicInfo; @@ -357,7 +159,7 @@ U64 getCurrentRSS() #elif defined(LL_LINUX) -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS() { static const char statPath[] = "/proc/self/stat"; LLFILE *fp = LLFile::fopen(statPath, "r"); @@ -396,7 +198,7 @@ bail: #define _STRUCTURED_PROC 1 #include -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS() { char path [LL_MAX_PATH]; /* Flawfinder: ignore */ @@ -419,7 +221,7 @@ U64 getCurrentRSS() } #else -U64 getCurrentRSS() +U64 LLMemory::getCurrentRSS() { return 0; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index b5c0711484..f41da37ba6 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -29,21 +29,17 @@ * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ -#ifndef LL_MEMORY_H -#define LL_MEMORY_H +#ifndef LLMEMORY_H +#define LLMEMORY_H -#include -#include -#include "llerror.h" extern S32 gTotalDAlloc; extern S32 gTotalDAUse; extern S32 gDACount; -const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA; - -//---------------------------------------------------------------------------- +extern void* ll_allocate (size_t size); +extern void ll_release (void *p); class LLMemory { @@ -51,422 +47,19 @@ public: static void initClass(); static void cleanupClass(); static void freeReserve(); + // Return the resident set size of the current process, in bytes. + // Return value is zero if not known. + static U64 getCurrentRSS(); private: static char* reserveMem; }; -//---------------------------------------------------------------------------- -// RefCount objects should generally only be accessed by way of LLPointer<>'s -// NOTE: LLPointer x = new LLFoo(); MAY NOT BE THREAD SAFE -// if LLFoo::LLFoo() does anything like put itself in an update queue. -// The queue may get accessed before it gets assigned to x. -// The correct implementation is: -// LLPointer x = new LLFoo; // constructor does not do anything interesting -// x->instantiate(); // does stuff like place x into an update queue +// LLRefCount moved to llrefcount.h -// see llthread.h for LLThreadSafeRefCount +// LLPointer moved to llpointer.h -//---------------------------------------------------------------------------- +// LLSafeHandle moved to llsafehandle.h -class LLRefCount -{ -protected: - LLRefCount(const LLRefCount&); // not implemented -private: - LLRefCount&operator=(const LLRefCount&); // not implemented - -protected: - virtual ~LLRefCount(); // use unref() - -public: - LLRefCount(); - - void ref() - { - mRef++; - } - - S32 unref() - { - llassert(mRef >= 1); - if (0 == --mRef) - { - delete this; - return 0; - } - return mRef; - } - - S32 getNumRefs() const - { - return mRef; - } - -private: - S32 mRef; -}; - -//---------------------------------------------------------------------------- - -// Note: relies on Type having ref() and unref() methods -template class LLPointer -{ -public: - - LLPointer() : - mPointer(NULL) - { - } - - LLPointer(Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLPointer(const LLPointer& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLPointer(const LLPointer& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - ~LLPointer() - { - unref(); - } - - Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - Type* operator->() { return mPointer; } - const Type& operator*() const { return *mPointer; } - Type& operator*() { return *mPointer; } - - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } - bool operator!() const { return (mPointer == NULL); } - bool isNull() const { return (mPointer == NULL); } - bool notNull() const { return (mPointer != NULL); } - - operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } - - LLPointer& operator =(Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - - return *this; - } - - LLPointer& operator =(const LLPointer& ptr) - { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLPointer& operator =(const LLPointer& ptr) - { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLPointer& a, LLPointer& b) - { - Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } - -protected: - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *tempp = mPointer; - mPointer = NULL; - tempp->unref(); - if (mPointer != NULL) - { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; - unref(); - } - } - } - -protected: - Type* mPointer; -}; - -//template -//class LLPointerTraits -//{ -// static Type* null(); -//}; -// -// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL. -// This is useful in instances where operations on NULL pointers are semantically safe and/or -// when error checking occurs at a different granularity or in a different part of the code -// than when referencing an object via a LLSafeHandle. -// - -template -class LLSafeHandle -{ -public: - LLSafeHandle() : - mPointer(NULL) - { - } - - LLSafeHandle(Type* ptr) : - mPointer(NULL) - { - assign(ptr); - } - - LLSafeHandle(const LLSafeHandle& ptr) : - mPointer(NULL) - { - assign(ptr.mPointer); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLSafeHandle(const LLSafeHandle& ptr) : - mPointer(NULL) - { - assign(ptr.get()); - } - - ~LLSafeHandle() - { - unref(); - } - - const Type* operator->() const { return nonNull(mPointer); } - Type* operator->() { return nonNull(mPointer); } - - Type* get() const { return mPointer; } - // we disallow these operations as they expose our null objects to direct manipulation - // and bypass the reference counting semantics - //const Type& operator*() const { return *nonNull(mPointer); } - //Type& operator*() { return *nonNull(mPointer); } - - operator BOOL() const { return mPointer != NULL; } - operator bool() const { return mPointer != NULL; } - bool operator!() const { return mPointer == NULL; } - bool isNull() const { return mPointer == NULL; } - bool notNull() const { return mPointer != NULL; } - - - operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLSafeHandle& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLSafeHandle& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLSafeHandle& ptr) const { return (mPointer > ptr.mPointer); } - - LLSafeHandle& operator =(Type* ptr) - { - assign(ptr); - return *this; - } - - LLSafeHandle& operator =(const LLSafeHandle& ptr) - { - assign(ptr.mPointer); - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLSafeHandle& operator =(const LLSafeHandle& ptr) - { - assign(ptr.get()); - return *this; - } - -public: - typedef Type* (*NullFunc)(); - static const NullFunc sNullFunc; - -protected: - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *tempp = mPointer; - mPointer = NULL; - tempp->unref(); - if (mPointer != NULL) - { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; - unref(); - } - } - } - - void assign(Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - } - - static Type* nonNull(Type* ptr) - { - return ptr == NULL ? sNullFunc() : ptr; - } - -protected: - Type* mPointer; -}; - -// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL -// NOT a smart pointer like LLPointer<> -// Useful for example in std::map > -// (std::map uses the default constructor for creating new entries) -template class LLInitializedPointer -{ -public: - LLInitializedPointer() : mPointer(NULL) {} - ~LLInitializedPointer() { delete mPointer; } - - const T* operator->() const { return mPointer; } - T* operator->() { return mPointer; } - const T& operator*() const { return *mPointer; } - T& operator*() { return *mPointer; } - operator const T*() const { return mPointer; } - operator T*() { return mPointer; } - T* operator=(T* x) { return (mPointer = x); } - operator bool() const { return mPointer != NULL; } - bool operator!() const { return mPointer == NULL; } - bool operator==(T* rhs) { return mPointer == rhs; } - bool operator==(const LLInitializedPointer* rhs) { return mPointer == rhs.mPointer; } - -protected: - T* mPointer; -}; - -//---------------------------------------------------------------------------- - -// LLSingleton implements the getInstance() method part of the Singleton -// pattern. It can't make the derived class constructors protected, though, so -// you have to do that yourself. -// -// There are two ways to use LLSingleton. The first way is to inherit from it -// while using the typename that you'd like to be static as the template -// parameter, like so: -// -// class Foo: public LLSingleton{}; -// -// Foo& instance = Foo::instance(); -// -// The second way is to use the singleton class directly, without inheritance: -// -// typedef LLSingleton FooSingleton; -// -// Foo& instance = FooSingleton::instance(); -// -// In this case, the class being managed as a singleton needs to provide an -// initSingleton() method since the LLSingleton virtual method won't be -// available -// -// As currently written, it is not thread-safe. -template -class LLSingleton -{ -public: - virtual ~LLSingleton() {} -#ifdef LL_MSVC7 -// workaround for VC7 compiler bug -// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx -// our version doesn't introduce a nested struct so that you can still declare LLSingleton -// a friend and hide your constructor - static T* getInstance() - { - LLSingleton singleton; - return singleton.vsHack(); - } - - T* vsHack() -#else - static T* getInstance() -#endif - { - static T instance; - static bool needs_init = true; - if (needs_init) - { - needs_init = false; - instance.initSingleton(); - } - return &instance; - } - - static T& instance() - { - return *getInstance(); - } - -private: - virtual void initSingleton() {} -}; - -//---------------------------------------------------------------------------- - -// Return the resident set size of the current process, in bytes. -// Return value is zero if not known. -U64 getCurrentRSS(); +// LLSingleton moved to llsingleton.h #endif diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp new file mode 100644 index 0000000000..4e33439711 --- /dev/null +++ b/indra/llcommon/llmemtype.cpp @@ -0,0 +1,237 @@ +/** + * @file llmemtype.cpp + * @brief Simple memory allocation/deallocation tracking stuff here + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llmemtype.h" +#include "llallocator.h" + +std::vector LLMemType::DeclareMemType::mNameList; + +LLMemType::DeclareMemType LLMemType::MTYPE_INIT("Init"); +LLMemType::DeclareMemType LLMemType::MTYPE_STARTUP("Startup"); +LLMemType::DeclareMemType LLMemType::MTYPE_MAIN("Main"); +LLMemType::DeclareMemType LLMemType::MTYPE_FRAME("Frame"); + +LLMemType::DeclareMemType LLMemType::MTYPE_GATHER_INPUT("GatherInput"); +LLMemType::DeclareMemType LLMemType::MTYPE_JOY_KEY("JoyKey"); + +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE("Idle"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_PUMP("IdlePump"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_NETWORK("IdleNetwork"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_REGIONS("IdleUpdateRegions"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION("IdleUpdateViewerRegion"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_SURFACE("IdleUpdateSurface"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY("IdleUpdateParcelOverlay"); +LLMemType::DeclareMemType LLMemType::MTYPE_IDLE_AUDIO("IdleAudio"); + +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING("CacheProcessPending"); +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS("CacheProcessPendingAsks"); +LLMemType::DeclareMemType LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES("CacheProcessPendingReplies"); + +LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_CHECK_ALL("MessageCheckAll"); +LLMemType::DeclareMemType LLMemType::MTYPE_MESSAGE_PROCESS_ACKS("MessageProcessAcks"); + +LLMemType::DeclareMemType LLMemType::MTYPE_RENDER("Render"); +LLMemType::DeclareMemType LLMemType::MTYPE_SLEEP("Sleep"); + +LLMemType::DeclareMemType LLMemType::MTYPE_NETWORK("Network"); +LLMemType::DeclareMemType LLMemType::MTYPE_PHYSICS("Physics"); +LLMemType::DeclareMemType LLMemType::MTYPE_INTERESTLIST("InterestList"); + +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEBASE("ImageBase"); +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGERAW("ImageRaw"); +LLMemType::DeclareMemType LLMemType::MTYPE_IMAGEFORMATTED("ImageFormatted"); + +LLMemType::DeclareMemType LLMemType::MTYPE_APPFMTIMAGE("AppFmtImage"); +LLMemType::DeclareMemType LLMemType::MTYPE_APPRAWIMAGE("AppRawImage"); +LLMemType::DeclareMemType LLMemType::MTYPE_APPAUXRAWIMAGE("AppAuxRawImage"); + +LLMemType::DeclareMemType LLMemType::MTYPE_DRAWABLE("Drawable"); + +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT("Object"); +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE("ObjectProcessUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE("ObjectProcessUpdateCore"); + +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY("Display"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE("DisplayUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA("DisplayUpdateCam"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_GEOM("DisplayUpdateGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SWAP("DisplaySwap"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_UPDATE_HUD("DisplayUpdateHud"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_GEN_REFLECTION("DisplayGenRefl"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE("DisplayImageUpdate"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_STATE_SORT("DisplayStateSort"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_SKY("DisplaySky"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_GEOM("DisplayRenderGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_FLUSH("DisplayRenderFlush"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_UI("DisplayRenderUI"); +LLMemType::DeclareMemType LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS("DisplayRenderAttach"); + +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DATA("VertexData"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CONSTRUCTOR("VertexConstr"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTRUCTOR("VertexDestr"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_VERTICES("VertexCreateVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CREATE_INDICES("VertexCreateIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_BUFFER("VertexDestroyBuff"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_DESTROY_INDICES("VertexDestroyIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_VERTS("VertexUpdateVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UPDATE_INDICES("VertexUpdateIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER("VertexAllocateBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_RESIZE_BUFFER("VertexResizeBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER("VertexMapBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES("VertexMapBufferVerts"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES("VertexMapBufferIndices"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_UNMAP_BUFFER("VertexUnmapBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_STRIDE("VertexSetStride"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SET_BUFFER("VertexSetBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER("VertexSetupVertBuff"); +LLMemType::DeclareMemType LLMemType::MTYPE_VERTEX_CLEANUP_CLASS("VertexCleanupClass"); + +LLMemType::DeclareMemType LLMemType::MTYPE_SPACE_PARTITION("SpacePartition"); + +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE("Pipeline"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_INIT("PipelineInit"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS("PipelineCreateBuffs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RESTORE_GL("PipelineRestroGL"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS("PipelineUnloadShaders"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL("PipelineLightingDetail"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE("PipelineGetPoolType"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_POOL("PipelineAddPool"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE("PipelineAllocDrawable"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_ADD_OBJECT("PipelineAddObj"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS("PipelineCreateObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_MOVE("PipelineUpdateMove"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_GEOM("PipelineUpdateGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_VISIBLE("PipelineMarkVisible"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_MOVED("PipelineMarkMoved"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_SHIFT("PipelineMarkShift"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS("PipelineShiftObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_TEXTURED("PipelineMarkTextured"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_MARK_REBUILD("PipelineMarkRebuild"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_UPDATE_CULL("PipelineUpdateCull"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_STATE_SORT("PipelineStateSort"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_POST_SORT("PipelinePostSort"); + +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS("PipelineHudEls"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_HL("PipelineRenderHL"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM("PipelineRenderGeom"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED("PipelineRenderGeomDef"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF("PipelineRenderGeomPostDef"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW("PipelineRenderGeomShadow"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_SELECT("PipelineRenderSelect"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_REBUILD_POOLS("PipelineRebuildPools"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP("PipelineQuickLookup"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS("PipelineRenderObjs"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR("PipelineGenImpostors"); +LLMemType::DeclareMemType LLMemType::MTYPE_PIPELINE_RENDER_BLOOM("PipelineRenderBloom"); + +LLMemType::DeclareMemType LLMemType::MTYPE_UPKEEP_POOLS("UpkeepPools"); + +LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR("Avatar"); +LLMemType::DeclareMemType LLMemType::MTYPE_AVATAR_MESH("AvatarMesh"); +LLMemType::DeclareMemType LLMemType::MTYPE_PARTICLES("Particles"); +LLMemType::DeclareMemType LLMemType::MTYPE_REGIONS("Regions"); + +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY("Inventory"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DRAW("InventoryDraw"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS("InventoryBuildNewViews"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_DO_FOLDER("InventoryDoFolder"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_POST_BUILD("InventoryPostBuild"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_FROM_XML("InventoryFromXML"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_CREATE_NEW_ITEM("InventoryCreateNewItem"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_INIT("InventoryViewInit"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_SHOW("InventoryViewShow"); +LLMemType::DeclareMemType LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE("InventoryViewToggle"); + +LLMemType::DeclareMemType LLMemType::MTYPE_ANIMATION("Animation"); +LLMemType::DeclareMemType LLMemType::MTYPE_VOLUME("Volume"); +LLMemType::DeclareMemType LLMemType::MTYPE_PRIMITIVE("Primitive"); + +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT("Script"); +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_RUN("ScriptRun"); +LLMemType::DeclareMemType LLMemType::MTYPE_SCRIPT_BYTECODE("ScriptByteCode"); + +LLMemType::DeclareMemType LLMemType::MTYPE_IO_PUMP("IoPump"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_TCP("IoTCP"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_BUFFER("IoBuffer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_HTTP_SERVER("IoHttpServer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_SERVER("IoSDServer"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_SD_CLIENT("IoSDClient"); +LLMemType::DeclareMemType LLMemType::MTYPE_IO_URL_REQUEST("IOUrlRequest"); + +LLMemType::DeclareMemType LLMemType::MTYPE_DIRECTX_INIT("DirectXInit"); + +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP1("Temp1"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP2("Temp2"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP3("Temp3"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP4("Temp4"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP5("Temp5"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP6("Temp6"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP7("Temp7"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP8("Temp8"); +LLMemType::DeclareMemType LLMemType::MTYPE_TEMP9("Temp9"); + +LLMemType::DeclareMemType LLMemType::MTYPE_OTHER("Other"); + + +LLMemType::DeclareMemType::DeclareMemType(char const * st) +{ + mID = (S32)mNameList.size(); + mName = st; + + mNameList.push_back(mName); +} + +LLMemType::DeclareMemType::~DeclareMemType() +{ +} + +LLMemType::LLMemType(LLMemType::DeclareMemType& dt) +{ + mTypeIndex = dt.mID; + LLAllocator::pushMemType(dt.mID); +} + +LLMemType::~LLMemType() +{ + LLAllocator::popMemType(); +} + +char const * LLMemType::getNameFromID(S32 id) +{ + if (id < 0 || id >= (S32)DeclareMemType::mNameList.size()) + { + return "INVALID"; + } + + return DeclareMemType::mNameList[id]; +} + diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index a9ebc2062f..12310fcdb4 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -36,128 +36,210 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -class LLMemType; - -extern void* ll_allocate (size_t size); -extern void ll_release (void *p); - -#define MEM_TRACK_MEM 0 -#define MEM_TRACK_TYPE (1 && MEM_TRACK_MEM) - -#if MEM_TRACK_TYPE -#define MEM_DUMP_DATA 1 -#define MEM_TYPE_NEW(T) \ -static void* operator new(size_t s) { LLMemType mt(T); return ll_allocate(s); } \ -static void operator delete(void* p) { ll_release(p); } - -#else -#define MEM_TYPE_NEW(T) -#endif // MEM_TRACK_TYPE - - //---------------------------------------------------------------------------- +#include "linden_common.h" +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// WARNING: Never commit with MEM_TRACK_MEM == 1 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define MEM_TRACK_MEM (0 && LL_WINDOWS) + +#include + +#define MEM_TYPE_NEW(T) + class LLMemType { public: - // Also update sTypeDesc in llmemory.cpp - enum EMemType + + // class we'll initialize all instances of as + // static members of MemType. Then use + // to construct any new mem type. + class DeclareMemType { - MTYPE_INIT, - MTYPE_STARTUP, - MTYPE_MAIN, - - MTYPE_IMAGEBASE, - MTYPE_IMAGERAW, - MTYPE_IMAGEFORMATTED, + public: + DeclareMemType(char const * st); + ~DeclareMemType(); + + S32 mID; + char const * mName; - MTYPE_APPFMTIMAGE, - MTYPE_APPRAWIMAGE, - MTYPE_APPAUXRAWIMAGE, - - MTYPE_DRAWABLE, - MTYPE_OBJECT, - MTYPE_VERTEX_DATA, - MTYPE_SPACE_PARTITION, - MTYPE_PIPELINE, - MTYPE_AVATAR, - MTYPE_AVATAR_MESH, - MTYPE_PARTICLES, - MTYPE_REGIONS, - MTYPE_INVENTORY, - MTYPE_ANIMATION, - MTYPE_VOLUME, - MTYPE_PRIMITIVE, - - MTYPE_NETWORK, - MTYPE_PHYSICS, - MTYPE_INTERESTLIST, - - MTYPE_SCRIPT, - MTYPE_SCRIPT_RUN, - MTYPE_SCRIPT_BYTECODE, - - MTYPE_IO_PUMP, - MTYPE_IO_TCP, - MTYPE_IO_BUFFER, - MTYPE_IO_HTTP_SERVER, - MTYPE_IO_SD_SERVER, - MTYPE_IO_SD_CLIENT, - MTYPE_IO_URL_REQUEST, - - MTYPE_TEMP1, - MTYPE_TEMP2, - MTYPE_TEMP3, - MTYPE_TEMP4, - MTYPE_TEMP5, - MTYPE_TEMP6, - MTYPE_TEMP7, - MTYPE_TEMP8, - MTYPE_TEMP9, - - MTYPE_OTHER, // Special, used by display code - - MTYPE_NUM_TYPES + // array so we can map an index ID to Name + static std::vector mNameList; }; - enum { MTYPE_MAX_DEPTH = 64 }; - -public: - LLMemType(EMemType type) - { -#if MEM_TRACK_TYPE - if (type < 0 || type >= MTYPE_NUM_TYPES) - llerrs << "LLMemType error" << llendl; - if (sCurDepth < 0 || sCurDepth >= MTYPE_MAX_DEPTH) - llerrs << "LLMemType error" << llendl; - sType[sCurDepth] = sCurType; - sCurDepth++; - sCurType = type; -#endif - } - ~LLMemType() - { -#if MEM_TRACK_TYPE - sCurDepth--; - sCurType = sType[sCurDepth]; -#endif - } - static void reset(); - static void printMem(); + LLMemType(DeclareMemType& dt); + ~LLMemType(); + + static char const * getNameFromID(S32 id); + + static DeclareMemType MTYPE_INIT; + static DeclareMemType MTYPE_STARTUP; + static DeclareMemType MTYPE_MAIN; + static DeclareMemType MTYPE_FRAME; + + static DeclareMemType MTYPE_GATHER_INPUT; + static DeclareMemType MTYPE_JOY_KEY; + + static DeclareMemType MTYPE_IDLE; + static DeclareMemType MTYPE_IDLE_PUMP; + static DeclareMemType MTYPE_IDLE_NETWORK; + static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; + static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; + static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; + static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; + static DeclareMemType MTYPE_IDLE_AUDIO; + + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; + static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; + + static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; + static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; + + static DeclareMemType MTYPE_RENDER; + static DeclareMemType MTYPE_SLEEP; + + static DeclareMemType MTYPE_NETWORK; + static DeclareMemType MTYPE_PHYSICS; + static DeclareMemType MTYPE_INTERESTLIST; + + static DeclareMemType MTYPE_IMAGEBASE; + static DeclareMemType MTYPE_IMAGERAW; + static DeclareMemType MTYPE_IMAGEFORMATTED; -public: -#if MEM_TRACK_TYPE - static S32 sCurDepth; - static S32 sCurType; - static S32 sType[MTYPE_MAX_DEPTH]; - static S32 sMemCount[MTYPE_NUM_TYPES]; - static S32 sMaxMemCount[MTYPE_NUM_TYPES]; - static S32 sNewCount[MTYPE_NUM_TYPES]; - static S32 sOverheadMem; - static const char* sTypeDesc[MTYPE_NUM_TYPES]; -#endif - static S32 sTotalMem; - static S32 sMaxTotalMem; + static DeclareMemType MTYPE_APPFMTIMAGE; + static DeclareMemType MTYPE_APPRAWIMAGE; + static DeclareMemType MTYPE_APPAUXRAWIMAGE; + + static DeclareMemType MTYPE_DRAWABLE; + + static DeclareMemType MTYPE_OBJECT; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; + static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; + + static DeclareMemType MTYPE_DISPLAY; + static DeclareMemType MTYPE_DISPLAY_UPDATE; + static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; + static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; + static DeclareMemType MTYPE_DISPLAY_SWAP; + static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; + static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; + static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; + static DeclareMemType MTYPE_DISPLAY_STATE_SORT; + static DeclareMemType MTYPE_DISPLAY_SKY; + static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; + static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; + static DeclareMemType MTYPE_DISPLAY_RENDER_UI; + static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; + + static DeclareMemType MTYPE_VERTEX_DATA; + static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; + static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; + static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; + static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; + static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER; + static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; + static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; + static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; + static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; + static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; + static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; + static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; + static DeclareMemType MTYPE_VERTEX_SET_STRIDE; + static DeclareMemType MTYPE_VERTEX_SET_BUFFER; + static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; + static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; + + static DeclareMemType MTYPE_SPACE_PARTITION; + + static DeclareMemType MTYPE_PIPELINE; + static DeclareMemType MTYPE_PIPELINE_INIT; + static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; + static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; + static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; + static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; + static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; + static DeclareMemType MTYPE_PIPELINE_ADD_POOL; + static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; + static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; + static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; + static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; + static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; + static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; + static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; + static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; + static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; + static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; + static DeclareMemType MTYPE_PIPELINE_STATE_SORT; + static DeclareMemType MTYPE_PIPELINE_POST_SORT; + + static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; + static DeclareMemType MTYPE_PIPELINE_RENDER_HL; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; + static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; + static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; + static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; + static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; + static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; + static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; + static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; + + static DeclareMemType MTYPE_UPKEEP_POOLS; + + static DeclareMemType MTYPE_AVATAR; + static DeclareMemType MTYPE_AVATAR_MESH; + static DeclareMemType MTYPE_PARTICLES; + static DeclareMemType MTYPE_REGIONS; + + static DeclareMemType MTYPE_INVENTORY; + static DeclareMemType MTYPE_INVENTORY_DRAW; + static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; + static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; + static DeclareMemType MTYPE_INVENTORY_POST_BUILD; + static DeclareMemType MTYPE_INVENTORY_FROM_XML; + static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; + static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; + static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; + static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; + + static DeclareMemType MTYPE_ANIMATION; + static DeclareMemType MTYPE_VOLUME; + static DeclareMemType MTYPE_PRIMITIVE; + + static DeclareMemType MTYPE_SCRIPT; + static DeclareMemType MTYPE_SCRIPT_RUN; + static DeclareMemType MTYPE_SCRIPT_BYTECODE; + + static DeclareMemType MTYPE_IO_PUMP; + static DeclareMemType MTYPE_IO_TCP; + static DeclareMemType MTYPE_IO_BUFFER; + static DeclareMemType MTYPE_IO_HTTP_SERVER; + static DeclareMemType MTYPE_IO_SD_SERVER; + static DeclareMemType MTYPE_IO_SD_CLIENT; + static DeclareMemType MTYPE_IO_URL_REQUEST; + + static DeclareMemType MTYPE_DIRECTX_INIT; + + static DeclareMemType MTYPE_TEMP1; + static DeclareMemType MTYPE_TEMP2; + static DeclareMemType MTYPE_TEMP3; + static DeclareMemType MTYPE_TEMP4; + static DeclareMemType MTYPE_TEMP5; + static DeclareMemType MTYPE_TEMP6; + static DeclareMemType MTYPE_TEMP7; + static DeclareMemType MTYPE_TEMP8; + static DeclareMemType MTYPE_TEMP9; + + static DeclareMemType MTYPE_OTHER; // Special; used by display code + + S32 mTypeIndex; }; //---------------------------------------------------------------------------- diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp index 8db3284c42..30e5d435ae 100644 --- a/indra/llcommon/llmetrics.cpp +++ b/indra/llcommon/llmetrics.cpp @@ -71,7 +71,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location, metrics["location"] = location; metrics["stats"] = stats; - llinfos << "LLMETRICS: " << LLSDNotationStreamer(metrics) << llendl; + llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl; } // Store this: diff --git a/indra/llcommon/lloptioninterface.cpp b/indra/llcommon/lloptioninterface.cpp new file mode 100644 index 0000000000..68c1ff1c41 --- /dev/null +++ b/indra/llcommon/lloptioninterface.cpp @@ -0,0 +1,39 @@ +/** + * @file lloptioninterface.cpp + * @brief + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "lloptioninterface.h" + + +LLOptionInterface::~LLOptionInterface() +{ + +} diff --git a/indra/llcommon/lloptioninterface.h b/indra/llcommon/lloptioninterface.h new file mode 100644 index 0000000000..4faf95f5e1 --- /dev/null +++ b/indra/llcommon/lloptioninterface.h @@ -0,0 +1,46 @@ +/** + * @file lloptioninterface.h + * @brief + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLOPTIONINTERFACE_H +#define LL_LLOPTIONINTERFACE_H + +#include "linden_common.h" + +class LLSD; +class LLOptionInterface +{ +public: + virtual ~LLOptionInterface() = 0; + virtual LLSD getOption(const std::string& name) const = 0; +}; + +#endif diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h new file mode 100644 index 0000000000..2c37eadcc6 --- /dev/null +++ b/indra/llcommon/llpointer.h @@ -0,0 +1,177 @@ +/** + * @file llpointer.h + * @brief A reference-counted pointer for objects derived from LLRefCount + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLPOINTER_H +#define LLPOINTER_H + +#include "llerror.h" // *TODO: consider eliminating this + +//---------------------------------------------------------------------------- +// RefCount objects should generally only be accessed by way of LLPointer<>'s +// NOTE: LLPointer x = new LLFoo(); MAY NOT BE THREAD SAFE +// if LLFoo::LLFoo() does anything like put itself in an update queue. +// The queue may get accessed before it gets assigned to x. +// The correct implementation is: +// LLPointer x = new LLFoo; // constructor does not do anything interesting +// x->instantiate(); // does stuff like place x into an update queue + +// see llthread.h for LLThreadSafeRefCount + +//---------------------------------------------------------------------------- + +// Note: relies on Type having ref() and unref() methods +template class LLPointer +{ +public: + + LLPointer() : + mPointer(NULL) + { + } + + LLPointer(Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLPointer(const LLPointer& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLPointer(const LLPointer& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLPointer() + { + unref(); + } + + Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + Type* operator->() { return mPointer; } + const Type& operator*() const { return *mPointer; } + Type& operator*() { return *mPointer; } + + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } + bool operator!() const { return (mPointer == NULL); } + bool isNull() const { return (mPointer == NULL); } + bool notNull() const { return (mPointer != NULL); } + + operator Type*() const { return mPointer; } + operator const Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } + + LLPointer& operator =(Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + + return *this; + } + + LLPointer& operator =(const LLPointer& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLPointer& operator =(const LLPointer& ptr) + { + if( mPointer != ptr.get() ) + { + unref(); + mPointer = ptr.get(); + ref(); + } + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLPointer& a, LLPointer& b) + { + Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } + +protected: + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *tempp = mPointer; + mPointer = NULL; + tempp->unref(); + if (mPointer != NULL) + { + llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + unref(); + } + } + } + +protected: + Type* mPointer; +}; + +#endif diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 2e4fd4787a..4401be1679 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -127,8 +127,10 @@ using snprintf_hack::snprintf; #pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. #pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. //#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" #pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( disable : 4786 ) // silly MS warning deep inside their include file +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden #pragma warning( disable : 4284 ) // silly MS warning deep inside their include file #pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. #pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) diff --git a/indra/llcommon/llprocesslauncher.cpp b/indra/llcommon/llprocesslauncher.cpp new file mode 100644 index 0000000000..f0315e92eb --- /dev/null +++ b/indra/llcommon/llprocesslauncher.cpp @@ -0,0 +1,344 @@ +/** + * @file llprocesslauncher.cpp + * @brief Utility class for launching, terminating, and tracking the state of processes. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llprocesslauncher.h" + +#include +#if LL_DARWIN || LL_LINUX +// not required or present on Win32 +#include +#endif + +LLProcessLauncher::LLProcessLauncher() +{ +#if LL_WINDOWS + mProcessHandle = 0; +#else + mProcessID = 0; +#endif +} + +LLProcessLauncher::~LLProcessLauncher() +{ + kill(); +} + +void LLProcessLauncher::setExecutable(const std::string &executable) +{ + mExecutable = executable; +} + +void LLProcessLauncher::setWorkingDirectory(const std::string &dir) +{ + mWorkingDir = dir; +} + +void LLProcessLauncher::clearArguments() +{ + mLaunchArguments.clear(); +} + +void LLProcessLauncher::addArgument(const std::string &arg) +{ + mLaunchArguments.push_back(arg); +} + +void LLProcessLauncher::addArgument(const char *arg) +{ + mLaunchArguments.push_back(std::string(arg)); +} + +#if LL_WINDOWS + +int LLProcessLauncher::launch(void) +{ + // If there was already a process associated with this object, kill it. + kill(); + orphan(); + + int result = 0; + + PROCESS_INFORMATION pinfo; + STARTUPINFOA sinfo; + memset(&sinfo, 0, sizeof(sinfo)); + + std::string args = mExecutable; + for(int i = 0; i < (int)mLaunchArguments.size(); i++) + { + args += " "; + args += mLaunchArguments[i]; + } + + // So retarded. Windows requires that the second parameter to CreateProcessA be a writable (non-const) string... + char *args2 = new char[args.size() + 1]; + strcpy(args2, args.c_str()); + + if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) ) + { + // TODO: do better than returning the OS-specific error code on failure... + result = GetLastError(); + if(result == 0) + { + // Make absolutely certain we return a non-zero value on failure. + result = -1; + } + } + else + { + // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on + // CloseHandle(pinfo.hProcess); // stops leaks - nothing else + mProcessHandle = pinfo.hProcess; + CloseHandle(pinfo.hThread); // stops leaks - nothing else + } + + delete[] args2; + + return result; +} + +bool LLProcessLauncher::isRunning(void) +{ + if(mProcessHandle != 0) + { + DWORD waitresult = WaitForSingleObject(mProcessHandle, 0); + if(waitresult == WAIT_OBJECT_0) + { + // the process has completed. + mProcessHandle = 0; + } + } + + return (mProcessHandle != 0); +} +bool LLProcessLauncher::kill(void) +{ + bool result = true; + + if(mProcessHandle != 0) + { + TerminateProcess(mProcessHandle,0); + + if(isRunning()) + { + result = false; + } + } + + return result; +} + +void LLProcessLauncher::orphan(void) +{ + // Forget about the process + mProcessHandle = 0; +} + +// static +void LLProcessLauncher::reap(void) +{ + // No actions necessary on Windows. +} + +#else // Mac and linux + +#include +#include +#include + +static std::list sZombies; + +// Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise. +static bool reap_pid(pid_t pid) +{ + bool result = false; + + pid_t wait_result = ::waitpid(pid, NULL, WNOHANG); + if(wait_result == pid) + { + result = true; + } + else if(wait_result == -1) + { + if(errno == ECHILD) + { + // No such process -- this may mean we're ignoring SIGCHILD. + result = true; + } + } + + return result; +} + +int LLProcessLauncher::launch(void) +{ + // If there was already a process associated with this object, kill it. + kill(); + orphan(); + + int result = 0; + int current_wd = -1; + + // create an argv vector for the child process + const char ** fake_argv = new const char *[mLaunchArguments.size() + 2]; // 1 for the executable path, 1 for the NULL terminator + + int i = 0; + + // add the executable path + fake_argv[i++] = mExecutable.c_str(); + + // and any arguments + for(int j=0; j < mLaunchArguments.size(); j++) + fake_argv[i++] = mLaunchArguments[j].c_str(); + + // terminate with a null pointer + fake_argv[i] = NULL; + + if(!mWorkingDir.empty()) + { + // save the current working directory + current_wd = ::open(".", O_RDONLY); + + // and change to the one the child will be executed in + if (::chdir(mWorkingDir.c_str())) + { + // chdir failed + } + } + + // flush all buffers before the child inherits them + ::fflush(NULL); + + pid_t id = vfork(); + if(id == 0) + { + // child process + + ::execv(mExecutable.c_str(), (char * const *)fake_argv); + + // If we reach this point, the exec failed. + // Use _exit() instead of exit() per the vfork man page. + _exit(0); + } + + // parent process + + if(current_wd >= 0) + { + // restore the previous working directory + if (::fchdir(current_wd)) + { + // chdir failed + } + ::close(current_wd); + } + + delete[] fake_argv; + + mProcessID = id; + + // At this point, the child process will have been created (since that's how vfork works -- the child borrowed our execution context until it forked) + // If the process doesn't exist at this point, the exec failed. + if(!isRunning()) + { + result = -1; + } + + return result; +} + +bool LLProcessLauncher::isRunning(void) +{ + if(mProcessID != 0) + { + // Check whether the process has exited, and reap it if it has. + if(reap_pid(mProcessID)) + { + // the process has exited. + mProcessID = 0; + } + } + + return (mProcessID != 0); +} + +bool LLProcessLauncher::kill(void) +{ + bool result = true; + + if(mProcessID != 0) + { + // Try to kill the process. We'll do approximately the same thing whether the kill returns an error or not, so we ignore the result. + (void)::kill(mProcessID, SIGTERM); + + // This will have the side-effect of reaping the zombie if the process has exited. + if(isRunning()) + { + result = false; + } + } + + return result; +} + +void LLProcessLauncher::orphan(void) +{ + // Disassociate the process from this object + if(mProcessID != 0) + { + // We may still need to reap the process's zombie eventually + sZombies.push_back(mProcessID); + + mProcessID = 0; + } +} + +// static +void LLProcessLauncher::reap(void) +{ + // Attempt to real all saved process ID's. + + std::list::iterator iter = sZombies.begin(); + while(iter != sZombies.end()) + { + if(reap_pid(*iter)) + { + iter = sZombies.erase(iter); + } + else + { + iter++; + } + } +} + +#endif diff --git a/indra/llcommon/llprocesslauncher.h b/indra/llcommon/llprocesslauncher.h new file mode 100644 index 0000000000..a1b8e22691 --- /dev/null +++ b/indra/llcommon/llprocesslauncher.h @@ -0,0 +1,85 @@ +/** + * @file llprocesslauncher.h + * @brief Utility class for launching, terminating, and tracking the state of processes. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPROCESSLAUNCHER_H +#define LL_LLPROCESSLAUNCHER_H + +#if LL_WINDOWS +#include +#endif + + +/* + LLProcessLauncher handles launching external processes with specified command line arguments. + It also keeps track of whether the process is still running, and can kill it if required. +*/ + +class LLProcessLauncher +{ + LOG_CLASS(LLProcessLauncher); +public: + LLProcessLauncher(); + virtual ~LLProcessLauncher(); + + void setExecutable(const std::string &executable); + void setWorkingDirectory(const std::string &dir); + + void clearArguments(); + void addArgument(const std::string &arg); + void addArgument(const char *arg); + + int launch(void); + bool isRunning(void); + + // Attempt to kill the process -- returns true if the process is no longer running when it returns. + // Note that even if this returns false, the process may exit some time after it's called. + bool kill(void); + + // Use this if you want the external process to continue execution after the LLProcessLauncher instance controlling it is deleted. + // Normally, the destructor will attempt to kill the process and wait for termination. + // This should only be used if the viewer is about to exit -- otherwise, the child process will become a zombie after it exits. + void orphan(void); + + // This needs to be called periodically on Mac/Linux to clean up zombie processes. + static void reap(void); +private: + std::string mExecutable; + std::string mWorkingDir; + std::vector mLaunchArguments; + +#if LL_WINDOWS + HANDLE mProcessHandle; +#else + pid_t mProcessID; +#endif +}; + +#endif // LL_LLPROCESSLAUNCHER_H diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp new file mode 100644 index 0000000000..ce93f09489 --- /dev/null +++ b/indra/llcommon/llptrto.cpp @@ -0,0 +1,108 @@ +/** + * @file llptrto.cpp + * @author Nat Goodspeed + * @date 2008-08-20 + * @brief Test for llptrto.h + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llptrto.h" +// STL headers +// std headers +// external library headers +#include +#include +// other Linden headers +#include "llmemory.h" + +// a refcounted class +class RCFoo: public LLRefCount +{ +public: + RCFoo() {} +}; + +// a refcounted subclass +class RCSubFoo: public RCFoo +{ +public: + RCSubFoo() {} +}; + +// a refcounted class using the other refcount base class +class TSRCFoo: public LLThreadSafeRefCount +{ +public: + TSRCFoo() {} +}; + +// a non-refcounted class +class Bar +{ +public: + Bar() {} +}; + +// a non-refcounted subclass +class SubBar: public Bar +{ +public: + SubBar() {} +}; + +int main(int argc, char *argv[]) +{ + // test LLPtrTo<> + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, LLPointer >::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, Bar*>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, SubBar*>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, int*>::value)); + + // Test LLRemovePointer<>. Note that we remove both pointer variants from + // each kind of type, regardless of whether the variant makes sense. + BOOST_STATIC_ASSERT((boost::is_same::type, RCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, RCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, RCSubFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, RCSubFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, TSRCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, TSRCFoo>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, Bar>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, Bar>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, SubBar>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, SubBar>::value)); + BOOST_STATIC_ASSERT((boost::is_same::type, int>::value)); + BOOST_STATIC_ASSERT((boost::is_same >::type, int>::value)); + + return 0; +} diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h new file mode 100644 index 0000000000..74c117a7f6 --- /dev/null +++ b/indra/llcommon/llptrto.h @@ -0,0 +1,93 @@ +/** + * @file llptrto.h + * @author Nat Goodspeed + * @date 2008-08-19 + * @brief LLPtrTo is a template helper to pick either TARGET* or -- when + * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount -- + * LLPointer. LLPtrTo<> chooses whichever pointer type is best. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLPTRTO_H) +#define LL_LLPTRTO_H + +#include "llpointer.h" +#include "llrefcount.h" // LLRefCount +#include "llthread.h" // LLThreadSafeRefCount +#include +#include +#include + +/** + * LLPtrTo::type is either of two things: + * + * * When TARGET is a subclass of either LLRefCount or LLThreadSafeRefCount, + * LLPtrTo::type is LLPointer. + * * Otherwise, LLPtrTo::type is TARGET*. + * + * This way, a class template can use LLPtrTo::type to select an + * appropriate pointer type to store. + */ +template +struct LLPtrTo +{ + typedef T* type; +}; + +/// specialize for subclasses of LLRefCount +template +struct LLPtrTo >::type> +{ + typedef LLPointer type; +}; + +/// specialize for subclasses of LLThreadSafeRefCount +template +struct LLPtrTo >::type> +{ + typedef LLPointer type; +}; + +/** + * LLRemovePointer::type gets you the underlying (pointee) type. + */ +template +struct LLRemovePointer +{ + typedef typename boost::remove_pointer::type type; +}; + +/// specialize for LLPointer +template +struct LLRemovePointer< LLPointer > +{ + typedef SOMECLASS type; +}; + +#endif /* ! defined(LL_LLPTRTO_H) */ diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index cd53e701d2..3db5c36545 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -31,7 +31,9 @@ #include "linden_common.h" #include "llqueuedthread.h" + #include "llstl.h" +#include "lltimer.h" // ms_sleep() //============================================================================ diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp new file mode 100644 index 0000000000..33b6875fb0 --- /dev/null +++ b/indra/llcommon/llrefcount.cpp @@ -0,0 +1,49 @@ +/** + * @file llrefcount.cpp + * @brief Base class for reference counted objects for use with LLPointer + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +#include "llrefcount.h" + +#include "llerror.h" + +LLRefCount::LLRefCount() : + mRef(0) +{ +} + +LLRefCount::~LLRefCount() +{ + if (mRef != 0) + { + llerrs << "deleting non-zero reference" << llendl; + } +} diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h new file mode 100644 index 0000000000..d3597b454c --- /dev/null +++ b/indra/llcommon/llrefcount.h @@ -0,0 +1,79 @@ +/** + * @file llrefcount.h + * @brief Base class for reference counted objects for use with LLPointer + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLREFCOUNT_H +#define LLREFCOUNT_H + +#include + +//---------------------------------------------------------------------------- +// RefCount objects should generally only be accessed by way of LLPointer<>'s +// see llthread.h for LLThreadSafeRefCount +//---------------------------------------------------------------------------- + +class LLRefCount +{ +protected: + LLRefCount(const LLRefCount& other); // no implementation +private: + LLRefCount& operator=(const LLRefCount&); // no implementation +protected: + virtual ~LLRefCount(); // use unref() + +public: + LLRefCount(); + + void ref() + { + mRef++; + } + + S32 unref() + { + llassert(mRef >= 1); + if (0 == --mRef) + { + delete this; + return 0; + } + return mRef; + } + + S32 getNumRefs() const + { + return mRef; + } + +private: + S32 mRef; +}; + +#endif diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h new file mode 100644 index 0000000000..1f7c682fd1 --- /dev/null +++ b/indra/llcommon/llsafehandle.h @@ -0,0 +1,167 @@ +/** + * @file llsafehandle.h + * @brief Reference-counted object where Object() is valid, not NULL. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLSAFEHANDLE_H +#define LLSAFEHANDLE_H + +#include "llerror.h" // *TODO: consider eliminating this + +// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL. +// This is useful in instances where operations on NULL pointers are semantically safe and/or +// when error checking occurs at a different granularity or in a different part of the code +// than when referencing an object via a LLSafeHandle. + +template +class LLSafeHandle +{ +public: + LLSafeHandle() : + mPointer(NULL) + { + } + + LLSafeHandle(Type* ptr) : + mPointer(NULL) + { + assign(ptr); + } + + LLSafeHandle(const LLSafeHandle& ptr) : + mPointer(NULL) + { + assign(ptr.mPointer); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLSafeHandle(const LLSafeHandle& ptr) : + mPointer(NULL) + { + assign(ptr.get()); + } + + ~LLSafeHandle() + { + unref(); + } + + const Type* operator->() const { return nonNull(mPointer); } + Type* operator->() { return nonNull(mPointer); } + + Type* get() const { return mPointer; } + // we disallow these operations as they expose our null objects to direct manipulation + // and bypass the reference counting semantics + //const Type& operator*() const { return *nonNull(mPointer); } + //Type& operator*() { return *nonNull(mPointer); } + + operator BOOL() const { return mPointer != NULL; } + operator bool() const { return mPointer != NULL; } + bool operator!() const { return mPointer == NULL; } + bool isNull() const { return mPointer == NULL; } + bool notNull() const { return mPointer != NULL; } + + + operator Type*() const { return mPointer; } + operator const Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLSafeHandle& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLSafeHandle& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLSafeHandle& ptr) const { return (mPointer > ptr.mPointer); } + + LLSafeHandle& operator =(Type* ptr) + { + assign(ptr); + return *this; + } + + LLSafeHandle& operator =(const LLSafeHandle& ptr) + { + assign(ptr.mPointer); + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLSafeHandle& operator =(const LLSafeHandle& ptr) + { + assign(ptr.get()); + return *this; + } + +public: + typedef Type* (*NullFunc)(); + static const NullFunc sNullFunc; + +protected: + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *tempp = mPointer; + mPointer = NULL; + tempp->unref(); + if (mPointer != NULL) + { + llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + unref(); + } + } + } + + void assign(Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + } + + static Type* nonNull(Type* ptr) + { + return ptr == NULL ? sNullFunc() : ptr; + } + +protected: + Type* mPointer; +}; + +#endif diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 2cc94c2914..9140ebb3f3 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -162,6 +162,7 @@ namespace virtual LLSD::Type type() const { return T; } + using LLSD::Impl::assign; // Unhiding base class virtuals... virtual void assign(LLSD::Impl*& var, DataRef value) { if (shared()) { @@ -349,6 +350,10 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } virtual bool has(const LLSD::String&) const; + + using LLSD::Impl::get; // Unhiding get(LLSD::Integer) + using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) + using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) virtual LLSD get(const LLSD::String&) const; LLSD& insert(const LLSD::String& k, const LLSD& v); virtual void erase(const LLSD::String&); @@ -439,6 +444,9 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + using LLSD::Impl::get; // Unhiding get(LLSD::String) + using LLSD::Impl::erase; // Unhiding erase(LLSD::String) + using LLSD::Impl::ref; // Unhiding ref(LLSD::String) virtual int size() const; virtual LLSD get(LLSD::Integer) const; void set(LLSD::Integer, const LLSD&); @@ -811,9 +819,15 @@ static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) { std::ostringstream out; if (useXMLFormat) - out << LLSDXMLStreamer(llsd); + { + LLSDXMLStreamer xml_streamer(llsd); + out << xml_streamer; + } else - out << LLSDNotationStreamer(llsd); + { + LLSDNotationStreamer notation_streamer(llsd); + out << notation_streamer; + } out_string = out.str(); } int len = out_string.length(); diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 7a66d70d3f..cf337be161 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -34,7 +34,7 @@ #include "linden_common.h" #include "llsdserialize.h" -#include "llmemory.h" +#include "llpointer.h" #include "llstreamtools.h" // for fullread #include diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index bb38b75d8f..7463d1e5dd 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -36,8 +36,9 @@ #define LL_LLSDSERIALIZE_H #include +#include "llpointer.h" +#include "llrefcount.h" #include "llsd.h" -#include "llmemory.h" /** * @class LLSDParser diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index aa0e0f3696..0202a033c3 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -171,6 +171,15 @@ char* ll_print_sd(const LLSD& sd) return buffer; } +char* ll_pretty_print_sd_ptr(const LLSD* sd) +{ + if (sd) + { + return ll_pretty_print_sd(*sd); + } + return NULL; +} + char* ll_pretty_print_sd(const LLSD& sd) { const U32 bufferSize = 10 * 1024; diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index b67ad521ea..501600f1d9 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -89,6 +89,7 @@ LLSD ll_binary_from_string(const LLSD& sd); char* ll_print_sd(const LLSD& sd); // Serializes sd to static buffer and returns pointer, using "pretty printing" mode. +char* ll_pretty_print_sd_ptr(const LLSD* sd); char* ll_pretty_print_sd(const LLSD& sd); //compares the structure of an LLSD to a template LLSD and stores the diff --git a/indra/llcommon/llsecondlifeurls.cpp b/indra/llcommon/llsecondlifeurls.cpp index 36d8e8870f..6323d9d36b 100644 --- a/indra/llcommon/llsecondlifeurls.cpp +++ b/indra/llcommon/llsecondlifeurls.cpp @@ -32,57 +32,59 @@ #include "linden_common.h" #include "llsecondlifeurls.h" - +/* const std::string CREATE_ACCOUNT_URL ( "http://secondlife.com/registration/"); const std::string MANAGE_ACCOUNT ( - "http://secondlife.com/account/"); + "http://secondlife.com/account/"); // *TODO: NOT USED const std::string AUCTION_URL ( "http://secondlife.com/auctions/auction-detail.php?id="); const std::string EVENTS_URL ( "http://secondlife.com/events/"); - +*/ const std::string TIER_UP_URL ( - "http://secondlife.com/app/landtier"); - -const std::string LAND_URL ( - "http://secondlife.com/app/landtier"); - -const std::string UPGRADE_TO_PREMIUM_URL ( - "http://secondlife.com/app/upgrade/"); + "http://secondlife.com/app/landtier"); // *TODO: Translate (simulator) const std::string DIRECTX_9_URL ( - "http://secondlife.com/support/"); + "http://secondlife.com/support/"); // *TODO: NOT USED +/* +const std::string LAND_URL ( + "http://secondlife.com/app/landtier"); // *TODO: NOT USED + +const std::string UPGRADE_TO_PREMIUM_URL ( + "http://secondlife.com/app/upgrade/"); // *TODO: NOT USED const std::string AMD_AGP_URL ( - "http://secondlife.com/support/"); + "http://secondlife.com/support/"); // *TODO: NOT USED const std::string VIA_URL ( - "http://secondlife.com/support/"); + "http://secondlife.com/support/"); // *TODO: NOT USED const std::string SUPPORT_URL ( "http://secondlife.com/support/"); const std::string INTEL_CHIPSET_URL ( - "http://secondlife.com/support/"); + "http://secondlife.com/support/"); // *TODO: NOT USED const std::string SIS_CHIPSET_URL ( - "http://secondlife.com/support/"); + "http://secondlife.com/support/"); // *TODO: NOT USED const std::string BLOGS_URL ( - "http://blog.secondlife.com/"); + "http://blog.secondlife.com/"); // *TODO: NOT USED const std::string BUY_CURRENCY_URL ( "http://secondlife.com/app/currency/"); const std::string LSL_DOC_URL ( - "http://secondlife.com/app/lsldoc/"); + "http://secondlife.com/app/lsldoc/"); // *TODO: NOT USED const std::string SL_KB_URL ( - "http://secondlife.com/knowledgebase/"); + "http://secondlife.com/knowledgebase/"); // *TODO: NOT USED const std::string RELEASE_NOTES_BASE_URL ( "http://secondlife.com/app/releasenotes/"); +*/ + diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h index 9fd75c363b..a2e5f0b9c6 100644 --- a/indra/llcommon/llsecondlifeurls.h +++ b/indra/llcommon/llsecondlifeurls.h @@ -32,7 +32,7 @@ #ifndef LL_LLSECONDLIFEURLS_H #define LL_LLSECONDLIFEURLS_H - +/* // Account registration web page extern const std::string CREATE_ACCOUNT_URL; @@ -42,18 +42,21 @@ extern const std::string MANAGE_ACCOUNT; extern const std::string AUCTION_URL; extern const std::string EVENTS_URL; - +*/ // Tier up to a new land level. extern const std::string TIER_UP_URL; + // Tier up to a new land level. extern const std::string LAND_URL; +// How to get DirectX 9 +extern const std::string DIRECTX_9_URL; + +/* // Upgrade from basic membership to premium membership extern const std::string UPGRADE_TO_PREMIUM_URL; -// How to get DirectX 9 -extern const std::string DIRECTX_9_URL; // Out of date VIA chipset extern const std::string VIA_URL; @@ -75,5 +78,5 @@ extern const std::string SL_KB_URL; // Release Notes Redirect URL for Server and Viewer extern const std::string RELEASE_NOTES_BASE_URL; - +*/ #endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h new file mode 100644 index 0000000000..2e7d845bf7 --- /dev/null +++ b/indra/llcommon/llsingleton.h @@ -0,0 +1,165 @@ +/** + * @file llsingleton.h + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLSINGLETON_H +#define LLSINGLETON_H + +#include "llerror.h" // *TODO: eliminate this + +#include + +// LLSingleton implements the getInstance() method part of the Singleton +// pattern. It can't make the derived class constructors protected, though, so +// you have to do that yourself. +// +// There are two ways to use LLSingleton. The first way is to inherit from it +// while using the typename that you'd like to be static as the template +// parameter, like so: +// +// class Foo: public LLSingleton{}; +// +// Foo& instance = Foo::instance(); +// +// The second way is to use the singleton class directly, without inheritance: +// +// typedef LLSingleton FooSingleton; +// +// Foo& instance = FooSingleton::instance(); +// +// In this case, the class being managed as a singleton needs to provide an +// initSingleton() method since the LLSingleton virtual method won't be +// available +// +// As currently written, it is not thread-safe. + +template +class LLSingleton : private boost::noncopyable +{ + +private: + typedef enum e_init_state + { + UNINITIALIZED, + CONSTRUCTING, + INITIALIZING, + INITIALIZED, + DELETED + } EInitState; + + static void deleteSingleton() + { + delete getData().mSingletonInstance; + getData().mSingletonInstance = NULL; + } + + // stores pointer to singleton instance + // and tracks initialization state of singleton + struct SingletonInstanceData + { + EInitState mInitState; + DERIVED_TYPE* mSingletonInstance; + + SingletonInstanceData() + : mSingletonInstance(NULL), + mInitState(UNINITIALIZED) + {} + + ~SingletonInstanceData() + { + deleteSingleton(); + } + }; + +public: + virtual ~LLSingleton() + { + SingletonInstanceData& data = getData(); + data.mSingletonInstance = NULL; + data.mInitState = DELETED; + } + + static SingletonInstanceData& getData() + { + static SingletonInstanceData data; + return data; + } + + static DERIVED_TYPE* getInstance() + { + SingletonInstanceData& data = getData(); + + if (data.mInitState == CONSTRUCTING) + { + llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; + } + + if (data.mInitState == DELETED) + { + llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; + } + + if (!data.mSingletonInstance) + { + data.mInitState = CONSTRUCTING; + data.mSingletonInstance = new DERIVED_TYPE(); + data.mInitState = INITIALIZING; + data.mSingletonInstance->initSingleton(); + data.mInitState = INITIALIZED; + } + + return data.mSingletonInstance; + } + + // Reference version of getInstance() + // Preferred over getInstance() as it disallows checking for NULL + static DERIVED_TYPE& instance() + { + return *getInstance(); + } + + // Has this singleton been created uet? + // Use this to avoid accessing singletons before the can safely be constructed + static bool instanceExists() + { + return getData().mInitState == INITIALIZED; + } + + // Has this singleton already been deleted? + // Use this to avoid accessing singletons from a static object's destructor + static bool destroyed() + { + return getData().mInitState == DELETED; + } + +private: + virtual void initSingleton() {} +}; + +#endif diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp new file mode 100644 index 0000000000..4be91b5b11 --- /dev/null +++ b/indra/llcommon/llstacktrace.cpp @@ -0,0 +1,141 @@ +/** + * @file llstacktrace.cpp + * @brief stack tracing functionality + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llstacktrace.h" + +#ifdef LL_WINDOWS + +#include +#include + +#include "windows.h" +#include "Dbghelp.h" + +typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( + IN ULONG frames_to_skip, + IN ULONG frames_to_capture, + OUT PVOID *backtrace, + OUT PULONG backtrace_hash); + +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = + (RtlCaptureStackBackTrace_Function*) + GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + +bool ll_get_stack_trace(std::vector& lines) +{ + const S32 MAX_STACK_DEPTH = 32; + const S32 STRING_NAME_LENGTH = 200; + const S32 FRAME_SKIP = 2; + static BOOL symbolsLoaded = false; + static BOOL firstCall = true; + + HANDLE hProc = GetCurrentProcess(); + + // load the symbols if they're not loaded + if(!symbolsLoaded && firstCall) + { + symbolsLoaded = SymInitialize(hProc, NULL, true); + firstCall = false; + } + + // if loaded, get the call stack + if(symbolsLoaded) + { + // create the frames to hold the addresses + void* frames[MAX_STACK_DEPTH]; + memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + S32 depth = 0; + + // get the addresses + depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + + IMAGEHLP_LINE64 line; + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + // create something to hold address info + PIMAGEHLP_SYMBOL64 pSym; + pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + pSym->MaxNameLength = STRING_NAME_LENGTH; + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + + // get address info for each address frame + // and store + for(S32 i=0; i < depth; i++) + { + std::stringstream stack_line; + BOOL ret; + + DWORD64 addr = (DWORD64)frames[i]; + ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); + if(ret) + { + stack_line << pSym->Name << " "; + } + + DWORD dummy; + ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); + if(ret) + { + std::string file_name = line.FileName; + std::string::size_type index = file_name.rfind("\\"); + stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; + } + + lines.push_back(stack_line.str()); + } + + free(pSym); + + // TODO: figure out a way to cleanup symbol loading + // Not hugely necessary, however. + //SymCleanup(hProc); + return true; + } + else + { + lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); + } + + return false; +} + +#else + +bool ll_get_stack_trace(std::vector& lines) +{ + return false; +} + +#endif + diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h new file mode 100644 index 0000000000..609b934a97 --- /dev/null +++ b/indra/llcommon/llstacktrace.h @@ -0,0 +1,44 @@ +/** + * @file llstacktrace.h + * @brief stack trace functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_LLSTACKTRACE_H +#define LL_LLSTACKTRACE_H + +#include "stdtypes.h" +#include +#include + +bool ll_get_stack_trace(std::vector& lines); + +#endif + diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index e650f911b7..0bd2609f4a 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -46,6 +46,7 @@ S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step" +LLStat::stat_map_t LLStat::sStatList; //------------------------------------------------------------------------ // Live config file to trigger stats logging @@ -754,28 +755,48 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats, LLTimer LLStat::sTimer; LLFrameTimer LLStat::sFrameTimer; -LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) +void LLStat::init() { - llassert(num_bins > 0); - U32 i; - mUseFrameTimer = use_frame_timer; + llassert(mNumBins > 0); mNumValues = 0; mLastValue = 0.f; mLastTime = 0.f; - mNumBins = num_bins; mCurBin = (mNumBins-1); mNextBin = 0; mBins = new F32[mNumBins]; mBeginTime = new F64[mNumBins]; mTime = new F64[mNumBins]; mDT = new F32[mNumBins]; - for (i = 0; i < mNumBins; i++) + for (U32 i = 0; i < mNumBins; i++) { mBins[i] = 0.f; mBeginTime[i] = 0.0; mTime[i] = 0.0; mDT[i] = 0.f; } + + if (!mName.empty()) + { + stat_map_t::iterator iter = sStatList.find(mName); + if (iter != sStatList.end()) + llwarns << "LLStat with duplicate name: " << mName << llendl; + sStatList.insert(std::make_pair(mName, this)); + } +} + +LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer) + : mUseFrameTimer(use_frame_timer), + mNumBins(num_bins) +{ + init(); +} + +LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer) + : mUseFrameTimer(use_frame_timer), + mNumBins(num_bins), + mName(name) +{ + init(); } LLStat::~LLStat() @@ -784,6 +805,15 @@ LLStat::~LLStat() delete[] mBeginTime; delete[] mTime; delete[] mDT; + + if (!mName.empty()) + { + // handle multiple entries with the same name + stat_map_t::iterator iter = sStatList.find(mName); + while (iter != sStatList.end() && iter->second != this) + ++iter; + sStatList.erase(iter); + } } void LLStat::reset() diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index e2e904bb06..76aa3963f4 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -267,8 +267,15 @@ private: // ---------------------------------------------------------------------------- class LLStat { +private: + typedef std::multimap stat_map_t; + static stat_map_t sStatList; + + void init(); + public: - LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE); + LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE); + LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE); ~LLStat(); void reset(); @@ -331,8 +338,22 @@ private: F32 *mDT; S32 mCurBin; S32 mNextBin; + + std::string mName; + static LLTimer sTimer; static LLFrameTimer sFrameTimer; + +public: + static LLStat* getStat(const std::string& name) + { + // return the first stat that matches 'name' + stat_map_t::iterator iter = sStatList.find(name); + if (iter != sStatList.end()) + return iter->second; + else + return NULL; + } }; - + #endif // LL_STAT_ diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 1f653c159c..d7da40d645 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -42,6 +42,9 @@ #include // for WideCharToMultiByte #endif +LLFastTimer::DeclareTimer STRING_LOCALIZATION("String Localization"); + + std::string ll_safe_string(const char* in) { if(in) return std::string(in); @@ -71,6 +74,24 @@ U8 hex_as_nybble(char hex) return 0; // uh - oh, not hex any more... } +bool iswindividual(llwchar elem) +{ + U32 cur_char = (U32)elem; + bool result = false; + if (0x2E80<= cur_char && cur_char <= 0x9FFF) + { + result = true; + } + else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) + { + result = true; + } + else if (0xF900<= cur_char && cur_char <= 0xFA60 ) + { + result = true; + } + return result; +} bool _read_file_into_string(std::string& str, const std::string& filename) { @@ -650,6 +671,11 @@ std::string ll_convert_wide_to_string(const wchar_t* in) } #endif // LL_WINDOWS +long LLStringOps::sltOffset; +long LLStringOps::localTimeOffset; +bool LLStringOps::daylightSavings; +std::map LLStringOps::datetimeToCodes; + S32 LLStringOps::collate(const llwchar* a, const llwchar* b) { #if LL_WINDOWS @@ -661,6 +687,59 @@ S32 LLStringOps::collate(const llwchar* a, const llwchar* b) #endif } +void LLStringOps::setupDatetimeInfo (bool daylight) +{ + time_t nowT, localT, gmtT; + struct tm * tmpT; + + nowT = time (NULL); + + tmpT = localtime (&nowT); + localT = mktime (tmpT); + + tmpT = gmtime (&nowT); + gmtT = mktime (tmpT); + + localTimeOffset = (long) (gmtT - localT); + + + daylightSavings = daylight; + sltOffset = (daylightSavings? 7 : 8 ) * 60 * 60; + + datetimeToCodes["wkday"] = "%a"; // Thu + datetimeToCodes["weekday"] = "%A"; // Thursday + datetimeToCodes["year4"] = "%Y"; // 2009 + datetimeToCodes["year"] = "%Y"; // 2009 + datetimeToCodes["year2"] = "%y"; // 09 + datetimeToCodes["mth"] = "%b"; // Aug + datetimeToCodes["month"] = "%B"; // August + datetimeToCodes["mthnum"] = "%m"; // 08 + datetimeToCodes["day"] = "%d"; // 31 + datetimeToCodes["hour24"] = "%H"; // 14 + datetimeToCodes["hour"] = "%H"; // 14 + datetimeToCodes["hour12"] = "%I"; // 02 + datetimeToCodes["min"] = "%M"; // 59 + datetimeToCodes["ampm"] = "%p"; // AM + datetimeToCodes["second"] = "%S"; // 59 + datetimeToCodes["timezone"] = "%Z"; // PST +} + +std::string LLStringOps::getDatetimeCode (std::string key) +{ + std::map::iterator iter; + + iter = datetimeToCodes.find (key); + if (iter != datetimeToCodes.end()) + { + return iter->second; + } + else + { + return std::string(""); + } +} + + namespace LLStringFn { // NOTE - this restricts output to ascii diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 6ba665b8d2..c6dcdd6d12 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -34,6 +34,11 @@ #define LL_LLSTRING_H #include +#include +#include +#include +#include "llsd.h" +#include "llfasttimer.h" #if LL_LINUX || LL_SOLARIS #include @@ -145,6 +150,12 @@ struct char_traits class LLStringOps { +private: + static long sltOffset; + static long localTimeOffset; + static bool daylightSavings; + static std::map datetimeToCodes; + public: static char toUpper(char elem) { return toupper((unsigned char)elem); } static llwchar toUpper(llwchar elem) { return towupper(elem); } @@ -172,6 +183,12 @@ public: static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); + + static void setupDatetimeInfo (bool daylight); + static long getSltOffset (void) {return sltOffset;} + static long getLocalTimeOffset (void) {return localTimeOffset;} + static bool getDaylightSavings (void) {return daylightSavings;} + static std::string getDatetimeCode (std::string key); }; /** @@ -201,6 +218,9 @@ private: template class LLStringUtilBase { +private: + static std::string sLocale; + public: typedef typename std::basic_string::size_type size_type; @@ -211,7 +231,15 @@ public: static std::basic_string null; typedef std::map format_map_t; - static S32 format(std::basic_string& s, const format_map_t& fmt_map); + static void getTokens (std::basic_string input, std::vector >& tokens); + static void formatNumber(std::basic_string& numStr, std::basic_string decimals); + static bool formatDatetime(std::basic_string& replacement, std::basic_string token, std::basic_string param, S32 secFromEpoch); + static S32 format(std::basic_string& s, const format_map_t& substitutions); + static S32 format(std::basic_string& s, const LLSD& substitutions); + static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const format_map_t& substitutions); + static bool simpleReplacement(std::basic_string& replacement, std::basic_string token, const LLSD& substitutions); + static void setLocale (std::string inLocale) {sLocale = inLocale;}; + static std::string getLocale (void) {return sLocale;}; static bool isValidIndex(const std::basic_string& string, size_type i) { @@ -253,7 +281,8 @@ public: static void replaceTabsWithSpaces( std::basic_string& string, size_type spaces_per_tab ); static void replaceNonstandardASCII( std::basic_string& string, T replacement ); static void replaceChar( std::basic_string& string, T target, T replacement ); - + static void replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ); + static BOOL containsNonprintable(const std::basic_string& string); static void stripNonprintable(std::basic_string& string); @@ -310,6 +339,9 @@ public: // Copies src into dst at a given offset. static void copyInto(std::basic_string& dst, const std::basic_string& src, size_type offset); + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + #ifdef _DEBUG static void testHarness(); #endif @@ -317,6 +349,7 @@ public: }; template std::basic_string LLStringUtilBase::null; +template std::string LLStringUtilBase::sLocale; typedef LLStringUtilBase LLStringUtil; typedef LLStringUtilBase LLWStringUtil; @@ -378,6 +411,7 @@ U8 hex_as_nybble(char hex); * @return Returns true on success. If false, str is unmodified. */ bool _read_file_into_string(std::string& str, const std::string& filename); +bool iswindividual(llwchar elem); /** * Unicode support @@ -564,61 +598,300 @@ namespace LLStringFn //////////////////////////////////////////////////////////// -// LLStringBase::format() -// -// This function takes a string 's' and a map 'fmt_map' of strings-to-strings. -// All occurances of strings in 's' from the left-hand side of 'fmt_map' are -// then replaced with the corresponding right-hand side of 'fmt_map', non- -// recursively. The function returns the number of substitutions made. +//static +template +void LLStringUtilBase::getTokens (std::basic_string input, std::vector >& tokens) +{ + const std::basic_string delims (","); + std::basic_string currToken; + size_type begIdx, endIdx; + + begIdx = input.find_first_not_of (delims); + while (begIdx != std::basic_string::npos) + { + endIdx = input.find_first_of (delims, begIdx); + if (endIdx == std::basic_string::npos) + { + endIdx = input.length(); + } + + currToken = input.substr(begIdx, endIdx - begIdx); + trim (currToken); + tokens.push_back(currToken); + begIdx = input.find_first_not_of (delims, endIdx); + } +} + +extern LLFastTimer::DeclareTimer STRING_LOCALIZATION; // static template -S32 LLStringUtilBase::format(std::basic_string& s, const format_map_t& fmt_map) +S32 LLStringUtilBase::format(std::basic_string& s, const format_map_t& substitutions) { - typedef typename std::basic_string::size_type string_size_type_t; - string_size_type_t scanstart = 0; + LLFastTimer ft(STRING_LOCALIZATION); S32 res = 0; - // Look for the first match of any keyword, replace that keyword, - // repeat from the end of the replacement string. This avoids - // accidentally performing substitution on a substituted string. - while (1) - { - string_size_type_t first_match_pos = scanstart; - string_size_type_t first_match_str_length = 0; - std::basic_string first_match_str_replacement; + std::basic_ostringstream output; + // match strings like [NAME,number,3] + const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]"); - for (format_map_t::const_iterator iter = fmt_map.begin(); - iter != fmt_map.end(); - ++iter) + + typename std::basic_string::const_iterator start = s.begin(); + typename std::basic_string::const_iterator end = s.end(); + boost::smatch match; + + + while (boost::regex_search(start, end, match, key, boost::match_default)) + { + bool found_replacement = false; + std::vector > tokens; + std::basic_string replacement; + + getTokens (std::basic_string(match[1].first, match[1].second), tokens); + + if (tokens.size() == 1) { - string_size_type_t n = s.find(iter->first, scanstart); - if (n != std::basic_string::npos && - (n < first_match_pos || - 0 == first_match_str_length)) + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::basic_string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::basic_string param; + if (tokens.size() > 2) param = tokens[2]; + + format_map_t::const_iterator iter = substitutions.find("datetime"); + if (iter != substitutions.end()) { - first_match_pos = n; - first_match_str_length = iter->first.length(); - first_match_str_replacement = iter->second; + S32 secFromEpoch = 0; + BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); + if (r) + { + found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); + } } } - if (0 == first_match_str_length) + if (found_replacement) { - // no more keys found to substitute from this point - // in the string forward. - break; + output << std::basic_string(start, match[0].first) << replacement; + res++; } else { - s.erase(first_match_pos, first_match_str_length); - s.insert(first_match_pos, first_match_str_replacement); - scanstart = first_match_pos + - first_match_str_replacement.length(); - ++res; + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output << std::basic_string(start, match[0].second); + } + + // update search position + start = match[0].second; + } + // send the remainder of the string (with no further matches for bracketed names) + output << std::basic_string(start, end); + s = output.str(); + return res; +} + +//static +template +S32 LLStringUtilBase::format(std::basic_string& s, const LLSD& substitutions) +{ + LLFastTimer ft(STRING_LOCALIZATION); + + S32 res = 0; + + if (!substitutions.isMap()) + { + return res; + } + + std::basic_ostringstream output; + // match strings like [NAME,number,3] + const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]"); + + + typename std::basic_string::const_iterator start = s.begin(); + typename std::basic_string::const_iterator end = s.end(); + boost::smatch match; + + + while (boost::regex_search(start, end, match, key, boost::match_default)) + { + bool found_replacement = false; + std::vector > tokens; + std::basic_string replacement; + + getTokens (std::basic_string(match[1].first, match[1].second), tokens); + + if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::basic_string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::basic_string param; + if (tokens.size() > 2) param = tokens[2]; + + S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); + found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); + } + + if (found_replacement) + { + output << std::basic_string(start, match[0].first) << replacement; + res++; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output << std::basic_string(start, match[0].second); + } + + // update search position + start = match[0].second; + } + // send the remainder of the string (with no further matches for bracketed names) + output << std::basic_string(start, end); + s = output.str(); + return res; +} + +// static +template +bool LLStringUtilBase::simpleReplacement(std::basic_string &replacement, std::basic_string token, const format_map_t& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + format_map_t::const_iterator iter = substitutions.find(token); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + // if not, see if there's one WITH brackets + iter = substitutions.find(std::basic_string("[" + token + "]")); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + + return false; +} + +// static +template +bool LLStringUtilBase::simpleReplacement(std::basic_string &replacement, std::basic_string token, const LLSD& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + if (substitutions.has(token)) + { + replacement = substitutions[token].asString(); + return true; + } + // if not, see if there's one WITH brackets + else if (substitutions.has(std::basic_string("[" + token + "]"))) + { + replacement = substitutions[std::basic_string("[" + token + "]")].asString(); + return true; + } + + return false; +} + +// static +template +void LLStringUtilBase::formatNumber(std::basic_string& numStr, std::basic_string decimals) +{ + typedef typename std::basic_string::size_type string_size_type_t; + std::basic_stringstream strStream; + S32 intDecimals = 0; + + convertToS32 (decimals, intDecimals); + if (!sLocale.empty()) + { + strStream.imbue (std::locale(sLocale.c_str())); + } + + if (!intDecimals) + { + S32 intStr; + + if (convertToS32(numStr, intStr)) + { + strStream << intStr; + numStr = strStream.str(); } } - return res; + else + { + F32 floatStr; + + if (convertToF32(numStr, floatStr)) + { + strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; + numStr = strStream.str(); + } + } +} + +// static +template +bool LLStringUtilBase::formatDatetime(std::basic_string& replacement, std::basic_string token, + std::basic_string param, S32 secFromEpoch) +{ + if (param == "local") // local + { + secFromEpoch -= LLStringOps::getLocalTimeOffset(); + } + else if (param != "utc") // slt + { + secFromEpoch -= LLStringOps::getSltOffset(); + } + + // if never fell into those two ifs above, param must be utc + if (secFromEpoch < 0) secFromEpoch = 0; + + LLDate * datetime = new LLDate((F64)secFromEpoch); + std::string code = LLStringOps::getDatetimeCode (token); + + // special case to handle timezone + if (code == "%Z") { + if (param == "utc") replacement = "GMT"; + else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST"; + return true; + } + + replacement = datetime->toHTTPDateString(code); + if (code.empty()) + { + return false; + } + else + { + return true; + } } // static @@ -917,11 +1190,22 @@ template void LLStringUtilBase::replaceChar( std::basic_string& string, T target, T replacement ) { size_type found_pos = 0; - for (found_pos = string.find(target, found_pos); - found_pos != std::basic_string::npos; - found_pos = string.find(target, found_pos)) + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) { string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } +} + +//static +template +void LLStringUtilBase::replaceString( std::basic_string& string, std::basic_string target, std::basic_string replacement ) +{ + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != std::basic_string::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index c8c9fd4eec..f25339f48d 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -35,7 +35,6 @@ #include "llapr.h" #include "llapp.h" -#include "llmemory.h" #include "apr_thread_cond.h" diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index fa6efaf38e..ea5b0c03ef 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -561,32 +561,27 @@ void secondsToTimecodeString(F32 current_time, std::string& tcstring) // ////////////////////////////////////////////////////////////////////////////// -std::list LLEventTimer::sActiveList; - LLEventTimer::LLEventTimer(F32 period) : mEventTimer() { mPeriod = period; - sActiveList.push_back(this); } LLEventTimer::LLEventTimer(const LLDate& time) : mEventTimer() { mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); - sActiveList.push_back(this); } -LLEventTimer::~LLEventTimer() +LLEventTimer::~LLEventTimer() { - sActiveList.remove(this); } void LLEventTimer::updateClass() { std::list completed_timers; - for (std::list::iterator iter = sActiveList.begin(); iter != sActiveList.end(); ) + for (instance_iter iter = beginInstances(); iter != endInstances(); ) { LLEventTimer* timer = *iter++; F32 et = timer->mEventTimer.getElapsedTimeF32(); diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index e2cf1c7689..0319bec45b 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -40,6 +40,7 @@ #include "stdtypes.h" #include "lldate.h" +#include "llinstancetracker.h" #include #include @@ -171,13 +172,13 @@ void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); void secondsToTimecodeString(F32 current_time, std::string& tcstring); // class for scheduling a function to be called at a given frequency (approximate, inprecise) -class LLEventTimer +class LLEventTimer : protected LLInstanceTracker { public: LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds LLEventTimer(const LLDate& time); virtual ~LLEventTimer(); - + //function to be called at the supplied frequency // Normally return FALSE; TRUE will delete the timer after the function returns. virtual BOOL tick() = 0; @@ -187,10 +188,6 @@ public: protected: LLTimer mEventTimer; F32 mPeriod; - -private: - //list of active timers - static std::list sActiveList; // TODO should this be a vector }; #endif diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h new file mode 100644 index 0000000000..c946566e84 --- /dev/null +++ b/indra/llcommon/lltreeiterators.h @@ -0,0 +1,711 @@ +/** + * @file lltreeiterators.h + * @author Nat Goodspeed + * @date 2008-08-19 + * @brief This file defines iterators useful for traversing arbitrary node + * classes, potentially polymorphic, linked into strict tree + * structures. + * + * Dereferencing any one of these iterators actually yields a @em + * pointer to the node in question. For example, given an + * LLLinkedIter li, *li gets you a pointer + * to MyNode, and **li gets you the MyNode instance itself. + * More commonly, instead of writing li->member, you write + * (*li)->member -- as you would if you were traversing an + * STL container of MyNode pointers. + * + * It would certainly be possible to build these iterators so that + * *iterator would return a reference to the node itself + * rather than a pointer to the node, and for many purposes it would + * even be more convenient. However, that would be insufficiently + * flexible. If you want to use an iterator range to (e.g.) initialize + * a std::vector collecting results -- you rarely want to actually @em + * copy the nodes in question. You're much more likely to want to copy + * pointers to the traversed nodes. Hence these iterators + * produce pointers. + * + * Though you specify the actual NODE class as the template parameter, + * these iterators internally use LLPtrTo<> to discover whether to + * store and return an LLPointer or a simple NODE*. + * + * By strict tree structures, we mean that each child must have + * exactly one parent. This forbids a child claiming any ancestor as a + * child of its own. Child nodes with multiple parents will be visited + * once for each parent. Cycles in the graph will result in either an + * infinite loop or an out-of-memory crash. You Have Been Warned. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLTREEITERATORS_H) +#define LL_LLTREEITERATORS_H + +#include "llptrto.h" +#include +#include +#include +#include +#include + +namespace LLTreeIter +{ + /// Discriminator between LLTreeUpIter and LLTreeDownIter + enum RootIter { UP, DOWN }; + /// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter + enum WalkIter { DFS_PRE, DFS_POST, BFS }; +} + +/** + * LLBaseIter defines some machinery common to all these iterators. We use + * boost::iterator_facade to define the iterator boilerplate: the conventional + * operators and methods necessary to implement a standards-conforming + * iterator. That allows us to specify the actual iterator semantics in terms + * of equal(), dereference() and increment() methods. + */ +template +class LLBaseIter: public boost::iterator_facade::type, + boost::forward_traversal_tag> +{ +protected: + /// LLPtrTo::type is either NODE* or LLPointer, as appropriate + typedef typename LLPtrTo::type ptr_type; + /// function that advances from this node to next accepts a node pointer + /// and returns another + typedef boost::function func_type; + typedef SELFTYPE self_type; +}; + +/// Functor returning NULL, suitable for an end-iterator's 'next' functor +template +typename LLPtrTo::type LLNullNextFunctor(const typename LLPtrTo::type&) +{ + return typename LLPtrTo::type(); +} + +/** + * LLLinkedIter is an iterator over an intrusive singly-linked list. The + * beginning of the list is represented by LLLinkedIter(list head); the end is + * represented by LLLinkedIter(). + * + * The begin LLLinkedIter must be instantiated with a functor to extract the + * 'next' pointer from the current node. Supposing that the link pointer is @c + * public, something like: + * + * @code + * NODE* mNext; + * @endcode + * + * you can use (e.g.) boost::bind(&NODE::mNext, _1) for the purpose. + * Alternatively, you can bind whatever accessor method is normally used to + * advance to the next node, e.g. for: + * + * @code + * NODE* next() const; + * @endcode + * + * you can use boost::bind(&NODE::next, _1). + */ +template +class LLLinkedIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, NODE> super; +protected: + /// some methods need to return a reference to self + typedef typename super::self_type self_type; + typedef typename super::ptr_type ptr_type; + typedef typename super::func_type func_type; +public: + /// Instantiate an LLLinkedIter to start a range, or to end a range before + /// a particular list entry. Pass a functor to extract the 'next' pointer + /// from the current node. + LLLinkedIter(const ptr_type& entry, const func_type& nextfunc): + mCurrent(entry), + mNextFunc(nextfunc) + {} + /// Instantiate an LLLinkedIter to end a range at the end of the list + LLLinkedIter(): + mCurrent(), + mNextFunc(LLNullNextFunctor) + {} + +private: + /// leverage boost::iterator_facade + friend class boost::iterator_core_access; + + /// advance + void increment() + { + mCurrent = mNextFunc(mCurrent); + } + /// equality + bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; } + /// dereference + ptr_type& dereference() const { return const_cast(mCurrent); } + + ptr_type mCurrent; + func_type mNextFunc; +}; + +/** + * LLTreeUpIter walks from the node in hand to the root of the tree. The term + * "up" is applied to a tree visualized with the root at the top. + * + * LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you + * can navigate that way at all contains parent pointers. + */ +template +class LLTreeUpIter: public LLLinkedIter +{ + typedef LLLinkedIter super; +public: + /// Instantiate an LLTreeUpIter to start from a particular tree node, or + /// to end a parent traversal before reaching a particular ancestor. Pass + /// a functor to extract the 'parent' pointer from the current node. + LLTreeUpIter(const typename super::ptr_type& node, + const typename super::func_type& parentfunc): + super(node, parentfunc) + {} + /// Instantiate an LLTreeUpIter to end a range at the root of the tree + LLTreeUpIter(): + super() + {} +}; + +/** + * LLTreeDownIter walks from the root of the tree to the node in hand. The + * term "down" is applied to a tree visualized with the root at the top. + * + * Though you instantiate the begin() LLTreeDownIter with a pointer to some + * node at an arbitrary location in the tree, the root will be the first node + * you dereference and the passed node will be the last node you dereference. + * + * On construction, LLTreeDownIter walks from the current node to the root, + * capturing the path. Then in use, it replays that walk in reverse. As with + * all traversals of interesting data structures, it is actively dangerous to + * modify the tree during an LLTreeDownIter walk. + */ +template +class LLTreeDownIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, NODE> super; + typedef typename super::self_type self_type; +protected: + typedef typename super::ptr_type ptr_type; + typedef typename super::func_type func_type; +private: + typedef std::vector list_type; +public: + /// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a + /// functor to extract the 'parent' pointer from the current node. + LLTreeDownIter(const ptr_type& node, + const func_type& parentfunc) + { + for (ptr_type n = node; n; n = parentfunc(n)) + mParents.push_back(n); + } + /// Instantiate an LLTreeDownIter representing "here", the end of the loop + LLTreeDownIter() {} + +private: + /// leverage boost::iterator_facade + friend class boost::iterator_core_access; + + /// advance + void increment() + { + mParents.pop_back(); + } + /// equality + bool equal(const self_type& that) const { return this->mParents == that.mParents; } + /// implement dereference/indirection operators + ptr_type& dereference() const { return const_cast(mParents.back()); } + + list_type mParents; +}; + +/** + * When you want to select between LLTreeUpIter and LLTreeDownIter with a + * compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter + * template arg. + */ +template +class LLTreeRootIter +{ + enum { use_a_valid_LLTreeIter_RootIter_value = false }; +public: + /// Bogus constructors for default (unrecognized discriminator) case + template + LLTreeRootIter(TYPE1, TYPE2) + { + BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value); + } + LLTreeRootIter() + { + BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value); + } +}; + +/// Specialize for LLTreeIter::UP +template +class LLTreeRootIter: public LLTreeUpIter +{ + typedef LLTreeUpIter super; +public: + /// forward begin ctor + LLTreeRootIter(const typename super::ptr_type& node, + const typename super::func_type& parentfunc): + super(node, parentfunc) + {} + /// forward end ctor + LLTreeRootIter(): + super() + {} +}; + +/// Specialize for LLTreeIter::DOWN +template +class LLTreeRootIter: public LLTreeDownIter +{ + typedef LLTreeDownIter super; +public: + /// forward begin ctor + LLTreeRootIter(const typename super::ptr_type& node, + const typename super::func_type& parentfunc): + super(node, parentfunc) + {} + /// forward end ctor + LLTreeRootIter(): + super() + {} +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens" + * a depth-first tree walk through that node and all its descendants. + * + * The begin() LLTreeDFSIter must be instantiated with functors to obtain from + * a given node begin() and end() iterators for that node's children. For this + * reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter. + * + * The end() LLTreeDFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeDFSIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, NODE> super; + typedef typename super::self_type self_type; +protected: + typedef typename super::ptr_type ptr_type; + // The func_type is different for this: from a NODE pointer, we must + // obtain a CHILDITER. + typedef boost::function func_type; +private: + typedef std::vector list_type; +public: + /// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass + /// functors to extract the 'child begin' and 'child end' iterators from + /// each node. + LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): + mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipChildren(false) + { + // Only push back this node if it's non-NULL! + if (node) + mPending.push_back(node); + } + /// Instantiate an LLTreeDFSIter to mark the end of the walk + LLTreeDFSIter() {} + + /// flags iterator logic to skip traversing children of current node on next increment + void skipDescendants(bool skip = true) { mSkipChildren = skip; } + +private: + /// leverage boost::iterator_facade + friend class boost::iterator_core_access; + + /// advance + /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search + void increment() + { + // Capture the node we were just looking at + ptr_type current = mPending.back(); + // Remove it from mPending so we don't process it again later + mPending.pop_back(); + if (!mSkipChildren) + { + // Add all its children to mPending + addChildren(current); + } + // reset flag after each step + mSkipChildren = false; + } + /// equality + bool equal(const self_type& that) const { return this->mPending == that.mPending; } + /// implement dereference/indirection operators + ptr_type& dereference() const { return const_cast(mPending.back()); } + + /// Add the direct children of the specified node to mPending + void addChildren(const ptr_type& node) + { + // If we just use push_back() for each child in turn, we'll end up + // processing children in reverse order. We don't want to assume + // CHILDITER is reversible: some of the linked trees we'll be + // processing manage their children using singly-linked lists. So + // figure out how many children there are, grow mPending by that size + // and reverse-copy the children into the new space. + CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node); + // grow mPending by the number of children + mPending.resize(mPending.size() + std::distance(chi, chend)); + // reverse-copy the children into the newly-expanded space + std::copy(chi, chend, mPending.rbegin()); + } + + /// list of the nodes yet to be processed + list_type mPending; + /// functor to extract begin() child iterator + func_type mBeginFunc; + /// functor to extract end() child iterator + func_type mEndFunc; + /// flag which controls traversal of children (skip children of current node if true) + bool mSkipChildren; +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeDFSPostIter + * "flattens" a depth-first tree walk through that node and all its + * descendants. Whereas LLTreeDFSIter visits each node before visiting any of + * its children, LLTreeDFSPostIter visits all of a node's children before + * visiting the node itself. + * + * The begin() LLTreeDFSPostIter must be instantiated with functors to obtain + * from a given node begin() and end() iterators for that node's children. For + * this reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter. + * + * The end() LLTreeDFSPostIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeDFSPostIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, NODE> super; + typedef typename super::self_type self_type; +protected: + typedef typename super::ptr_type ptr_type; + // The func_type is different for this: from a NODE pointer, we must + // obtain a CHILDITER. + typedef boost::function func_type; +private: + // Upon reaching a given node in our pending list, we need to know whether + // we've already pushed that node's children, so we must associate a bool + // with each node pointer. + typedef std::vector< std::pair > list_type; +public: + /// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass + /// functors to extract the 'child begin' and 'child end' iterators from + /// each node. + LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): + mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipAncestors(false) + { + if (! node) + return; + mPending.push_back(typename list_type::value_type(node, false)); + makeCurrent(); + } + /// Instantiate an LLTreeDFSPostIter to mark the end of the walk + LLTreeDFSPostIter() {} + + /// flags iterator logic to skip traversing ancestors of current node on next increment + void skipAncestors(bool skip = true) { mSkipAncestors = skip; } + +private: + /// leverage boost::iterator_facade + friend class boost::iterator_core_access; + + /// advance + /// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search + void increment() + { + // Pop the previous current node + mPending.pop_back(); + makeCurrent(); + } + /// equality + bool equal(const self_type& that) const { return this->mPending == that.mPending; } + /// implement dereference/indirection operators + ptr_type& dereference() const { return const_cast(mPending.back().first); } + + struct isOpen + { + bool operator()(const typename list_type::value_type& item) + { + return item.second; + } + }; + + /// Call this each time we change mPending.back() -- that is, every time + /// we're about to change the value returned by dereference(). If we + /// haven't yet pushed the new node's children, do so now. + void makeCurrent() + { + if (mSkipAncestors) + { + mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end()); + mSkipAncestors = false; + } + + // Once we've popped the last node, this becomes a no-op. + if (mPending.empty()) + return; + // Here mPending.back() holds the node pointer we're proposing to + // dereference next. Have we pushed that node's children yet? + if (mPending.back().second) + return; // if so, it's okay to visit this node now + // We haven't yet pushed this node's children. Do so now. Remember + // that we did -- while the node in question is still back(). + mPending.back().second = true; + addChildren(mPending.back().first); + // Now, because we've just changed mPending.back(), make that new node + // current. + makeCurrent(); + } + + /// Add the direct children of the specified node to mPending + void addChildren(const ptr_type& node) + { + // If we just use push_back() for each child in turn, we'll end up + // processing children in reverse order. We don't want to assume + // CHILDITER is reversible: some of the linked trees we'll be + // processing manage their children using singly-linked lists. So + // figure out how many children there are, grow mPending by that size + // and reverse-copy the children into the new space. + CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node); + // grow mPending by the number of children + mPending.resize(mPending.size() + std::distance(chi, chend)); + // Reverse-copy the children into the newly-expanded space. We can't + // just use std::copy() because the source is a ptr_type, whereas the + // dest is a pair of (ptr_type, bool). + for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi) + { + pi->first = *chi; // copy the child pointer + pi->second = false; // we haven't yet pushed this child's chldren + } + } + + /// list of the nodes yet to be processed + list_type mPending; + /// functor to extract begin() child iterator + func_type mBeginFunc; + /// functor to extract end() child iterator + func_type mEndFunc; + /// flags logic to skip traversal of ancestors of current node + bool mSkipAncestors; +}; + +/** + * Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens" + * a breadth-first tree walk through that node and all its descendants. + * + * The begin() LLTreeBFSIter must be instantiated with functors to obtain from + * a given node the begin() and end() iterators of that node's children. For + * this reason, you must specify the type of the node's child iterator as an + * additional template parameter. + * + * Specifically, the begin functor must return an iterator whose dereferenced + * value is a @em pointer to a child tree node. For instance, if each node + * tracks its children in an STL container of node* pointers, you can simply + * return that container's begin() iterator. + * + * Alternatively, if a node tracks its children with a classic linked list, + * write a functor returning LLLinkedIter. + * + * The end() LLTreeBFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeBFSIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, NODE> super; + typedef typename super::self_type self_type; +protected: + typedef typename super::ptr_type ptr_type; + // The func_type is different for this: from a NODE pointer, we must + // obtain a CHILDITER. + typedef boost::function func_type; +private: + // We need a FIFO queue rather than a LIFO stack. Use a deque rather than + // a vector, since vector can't implement pop_front() efficiently. + typedef std::deque list_type; +public: + /// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass + /// functors to extract the 'child begin' and 'child end' iterators from + /// each node. + LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc): + mBeginFunc(beginfunc), + mEndFunc(endfunc) + { + if (node) + mPending.push_back(node); + } + /// Instantiate an LLTreeBFSIter to mark the end of the walk + LLTreeBFSIter() {} + +private: + /// leverage boost::iterator_facade + friend class boost::iterator_core_access; + + /// advance + /// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search + void increment() + { + // Capture the node we were just looking at + ptr_type current = mPending.front(); + // Remove it from mPending so we don't process it again later + mPending.pop_front(); + // Add all its children to mPending + CHILDITER chend = mEndFunc(current); + for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi) + mPending.push_back(*chi); + } + /// equality + bool equal(const self_type& that) const { return this->mPending == that.mPending; } + /// implement dereference/indirection operators + ptr_type& dereference() const { return const_cast(mPending.front()); } + + /// list of the nodes yet to be processed + list_type mPending; + /// functor to extract begin() child iterator + func_type mBeginFunc; + /// functor to extract end() child iterator + func_type mEndFunc; +}; + +/** + * When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and + * LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an + * LLTreeIter::WalkIter template arg. + */ +template +class LLTreeWalkIter +{ + enum { use_a_valid_LLTreeIter_WalkIter_value = false }; +public: + /// Bogus constructors for default (unrecognized discriminator) case + template + LLTreeWalkIter(TYPE1, TYPE2) + { + BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value); + } + LLTreeWalkIter() + { + BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value); + } +}; + +/// Specialize for LLTreeIter::DFS_PRE +template +class LLTreeWalkIter: + public LLTreeDFSIter +{ + typedef LLTreeDFSIter super; +public: + /// forward begin ctor + LLTreeWalkIter(const typename super::ptr_type& node, + const typename super::func_type& beginfunc, + const typename super::func_type& endfunc): + super(node, beginfunc, endfunc) + {} + /// forward end ctor + LLTreeWalkIter(): + super() + {} +}; + +/// Specialize for LLTreeIter::DFS_POST +template +class LLTreeWalkIter: + public LLTreeDFSPostIter +{ + typedef LLTreeDFSPostIter super; +public: + /// forward begin ctor + LLTreeWalkIter(const typename super::ptr_type& node, + const typename super::func_type& beginfunc, + const typename super::func_type& endfunc): + super(node, beginfunc, endfunc) + {} + /// forward end ctor + LLTreeWalkIter(): + super() + {} +}; + +/// Specialize for LLTreeIter::BFS +template +class LLTreeWalkIter: + public LLTreeBFSIter +{ + typedef LLTreeBFSIter super; +public: + /// forward begin ctor + LLTreeWalkIter(const typename super::ptr_type& node, + const typename super::func_type& beginfunc, + const typename super::func_type& endfunc): + super(node, beginfunc, endfunc) + {} + /// forward end ctor + LLTreeWalkIter(): + super() + {} +}; + +#endif /* ! defined(LL_LLTREEITERATORS_H) */ diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 7e623d47d6..45810a101d 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -33,11 +33,11 @@ #ifndef LL_LLVERSIONVIEWER_H #define LL_LLVERSIONVIEWER_H -const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 24; -const S32 LL_VERSION_PATCH = 4; +const S32 LL_VERSION_MAJOR = 2; +const S32 LL_VERSION_MINOR = 0; +const S32 LL_VERSION_PATCH = 0; const S32 LL_VERSION_BUILD = 0; -const char * const LL_CHANNEL = "Second Life Release"; +const char * const LL_CHANNEL = "Second Life 2009"; #endif diff --git a/indra/llcommon/tests/llallocator_heap_profile_test.cpp b/indra/llcommon/tests/llallocator_heap_profile_test.cpp new file mode 100644 index 0000000000..7369fdc8bc --- /dev/null +++ b/indra/llcommon/tests/llallocator_heap_profile_test.cpp @@ -0,0 +1,150 @@ +/** + * @file llallocator_heap_profile_test.cpp + * @author Brad Kittenbrink + * @date 2008-02- + * @brief Test for llallocator_heap_profile.cpp. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llallocator_heap_profile.h" +#include "../test/lltut.h" + +namespace tut +{ + struct llallocator_heap_profile_data + { + LLAllocatorHeapProfile prof; + + static char const * const sample_win_profile; + // *TODO - get test output from mac/linux tcmalloc + static char const * const sample_mac_profile; + static char const * const sample_lin_profile; + + static char const * const crash_testcase; + }; + typedef test_group factory; + typedef factory::object object; +} +namespace +{ + tut::factory llallocator_heap_profile_test_factory("LLAllocatorHeapProfile"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + prof.parse(sample_win_profile); + + ensure_equals("count lines", prof.mLines.size() , 5); + ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 2131854U); + ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 2245710106ULL); + ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 14069198U); + ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 4295177308ULL); + ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0); + ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0); + ensure_equals("count markers", prof.mLines[2].mTrace.size(), 4); + ensure_equals("count markers", prof.mLines[3].mTrace.size(), 6); + ensure_equals("count markers", prof.mLines[4].mTrace.size(), 7); + + //prof.dump(std::cout); + } + + template<> template<> + void object::test<2>() + { + prof.parse(crash_testcase); + + ensure_equals("count lines", prof.mLines.size(), 2); + ensure_equals("alloc counts", prof.mLines[0].mLiveCount, 3U); + ensure_equals("alloc counts", prof.mLines[0].mLiveSize, 1049652ULL); + ensure_equals("alloc counts", prof.mLines[0].mTotalCount, 8U); + ensure_equals("alloc counts", prof.mLines[0].mTotalSize, 1049748ULL); + ensure_equals("count markers", prof.mLines[0].mTrace.size(), 0); + ensure_equals("count markers", prof.mLines[1].mTrace.size(), 0); + + //prof.dump(std::cout); + } + + template<> template<> + void object::test<3>() + { + // test that we don't crash on edge case data + prof.parse(""); + ensure("emtpy on error", prof.mLines.empty()); + + prof.parse("heap profile:"); + ensure("emtpy on error", prof.mLines.empty()); + } + +char const * const llallocator_heap_profile_data::sample_win_profile = +"heap profile: 2131854: 2245710106 [14069198: 4295177308] @\n" +"308592: 1073398388 [966564: 1280998739] @\n" +"462651: 375969538 [1177377: 753561247] @ 2 3 6 1\n" +"314744: 206611283 [2008722: 570934755] @ 2 3 3 7 21 32\n" +"277152: 82862770 [621961: 168503640] @ 2 3 3 7 21 32 87\n" +"\n" +"MAPPED_LIBRARIES:\n" +"00400000-02681000 r-xp 00000000 00:00 0 c:\\proj\\tcmalloc-eval-9\\indra\\build-vc80\\newview\\RelWithDebInfo\\secondlife-bin.exe\n" +"77280000-773a7000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\ntdll.dll\n" +"76df0000-76ecb000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\kernel32.dll\n" +"76000000-76073000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\comdlg32.dll\n" +"75ee0000-75f8a000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\msvcrt.dll\n" +"76c30000-76c88000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\SHLWAPI.dll\n" +"75f90000-75fdb000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\GDI32.dll\n" +"77420000-774bd000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\USER32.dll\n" +"75e10000-75ed6000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\ADVAPI32.dll\n" +"75b00000-75bc2000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\RPCRT4.dll\n" +"72ca0000-72d25000 r-xp 00000000 00:00 0 C:\\Windows\\WinSxS\\x86_microsoft.windows.common-controls_6595b64144ccf1df_5.82.6001.18000_none_886786f450a74a05\\COMCTL32.dll\n" +"76120000-76c30000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\SHELL32.dll\n" +"71ce0000-71d13000 r-xp 00000000 00:00 0 C:\\Windows\\system32\\DINPUT8.dll\n"; + + +char const * const llallocator_heap_profile_data::crash_testcase = +"heap profile: 3: 1049652 [ 8: 1049748] @\n" +" 3: 1049652 [ 8: 1049748] @\n" +"\n" +"MAPPED_LIBRARIES:\n" +"00400000-004d5000 r-xp 00000000 00:00 0 c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\llallocator_test.exe\n" +"7c900000-7c9af000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\ntdll.dll\n" +"7c800000-7c8f6000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\kernel32.dll\n" +"77dd0000-77e6b000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\ADVAPI32.dll\n" +"77e70000-77f02000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\RPCRT4.dll\n" +"77fe0000-77ff1000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\Secur32.dll\n" +"71ab0000-71ac7000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\WS2_32.dll\n" +"77c10000-77c68000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\msvcrt.dll\n" +"71aa0000-71aa8000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\WS2HELP.dll\n" +"76bf0000-76bfb000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\PSAPI.DLL\n" +"5b860000-5b8b5000 r-xp 00000000 00:00 0 C:\\WINDOWS\\system32\\NETAPI32.dll\n" +"10000000-10041000 r-xp 00000000 00:00 0 c:\\code\\linden\\tcmalloc\\indra\\build-vc80\\llcommon\\RelWithDebInfo\\libtcmalloc_minimal.dll\n" +"7c420000-7c4a7000 r-xp 00000000 00:00 0 C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCP80.dll\n" +"78130000-781cb000 r-xp 00000000 00:00 0 C:\\WINDOWS\\WinSxS\\x86_Microsoft.VC80.CRT_1fc8b3b9a1e18e3b_8.0.50727.1433_x-ww_5cf844d2\\MSVCR80.dll\n"; + +} diff --git a/indra/llcommon/tests/llallocator_test.cpp b/indra/llcommon/tests/llallocator_test.cpp new file mode 100644 index 0000000000..9db95f4273 --- /dev/null +++ b/indra/llcommon/tests/llallocator_test.cpp @@ -0,0 +1,86 @@ +/** + * @file llallocator_test.cpp + * @author Brad Kittenbrink + * @date 2008-02- + * @brief Test for llallocator.cpp. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llallocator.h" +#include "../test/lltut.h" + +namespace tut +{ + struct llallocator_data + { + LLAllocator llallocator; + }; + typedef test_group factory; + typedef factory::object object; +} +namespace +{ + tut::factory llallocator_test_factory("LLAllocator"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + llallocator.setProfilingEnabled(false); + ensure("Profiler disable", !llallocator.isProfiling()); + } + +#if LL_USE_TCMALLOC + template<> template<> + void object::test<2>() + { + llallocator.setProfilingEnabled(true); + ensure("Profiler enable", llallocator.isProfiling()); + } + + template <> template <> + void object::test<3>() + { + llallocator.setProfilingEnabled(true); + + char * test_alloc = new char[1024]; + + llallocator.getProfile(); + + delete [] test_alloc; + + llallocator.getProfile(); + + // *NOTE - this test isn't ensuring anything right now other than no + // exceptions are thrown. + } +#endif // LL_USE_TCMALLOC +}; diff --git a/indra/llcommon/tests/llmemtype_test.cpp b/indra/llcommon/tests/llmemtype_test.cpp new file mode 100644 index 0000000000..6cc5ce01ce --- /dev/null +++ b/indra/llcommon/tests/llmemtype_test.cpp @@ -0,0 +1,123 @@ +/** + * @file llmemtype_test.cpp + * @author Palmer Truelson + * @date 2008-03- + * @brief Test for llmemtype.cpp. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "../llmemtype.h" +#include "../test/lltut.h" +#include "../llallocator.h" + + +#include + +std::stack memTypeStack; + +void LLAllocator::pushMemType(S32 i) +{ + memTypeStack.push(i); +} + +S32 LLAllocator::popMemType(void) +{ + S32 ret = memTypeStack.top(); + memTypeStack.pop(); + return ret; +} + +namespace tut +{ + struct llmemtype_data + { + }; + + typedef test_group factory; + typedef factory::object object; +} +namespace +{ + tut::factory llmemtype_test_factory("LLMemType"); +} + +namespace tut +{ + template<> template<> + void object::test<1>() + { + ensure("Simplest test ever", true); + } + + // test with no scripts + template<> template<> + void object::test<2>() + { + { + LLMemType m1(LLMemType::MTYPE_INIT); + } + ensure("Test that you can construct and destruct the mem type"); + } + + // test creation and stack testing + template<> template<> + void object::test<3>() + { + { + ensure("Test that creation and destruction properly inc/dec the stack"); + ensure_equals(memTypeStack.size(), 0); + { + LLMemType m1(LLMemType::MTYPE_INIT); + ensure_equals(memTypeStack.size(), 1); + LLMemType m2(LLMemType::MTYPE_STARTUP); + ensure_equals(memTypeStack.size(), 2); + } + ensure_equals(memTypeStack.size(), 0); + } + } + + // test with no scripts + template<> template<> + void object::test<4>() + { + // catch the begining and end + std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); + ensure_equals("Init name", test_name, "Init"); + + std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); + ensure_equals("Volume name", test_name2, "Volume"); + + std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); + ensure_equals("Other name", test_name3, "Other"); + + std::string test_name4 = LLMemType::getNameFromID(-1); + ensure_equals("Invalid name", test_name4, "INVALID"); + } + +}; diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp index d83d9d18bf..c1022c1195 100755 --- a/indra/llcrashlogger/llcrashlogger.cpp +++ b/indra/llcrashlogger/llcrashlogger.cpp @@ -86,6 +86,7 @@ void LLCrashLoggerText::updateApplication(const std::string& message) LLCrashLogger::LLCrashLogger() : mCrashBehavior(CRASH_BEHAVIOR_ASK), mCrashInPreviousExec(false), + mCrashSettings("CrashSettings"), mSentCrashLogs(false), mCrashHost("") { diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp index 93ddc65f32..488f3bf78d 100644 --- a/indra/llimage/llimage.cpp +++ b/indra/llimage/llimage.cpp @@ -152,7 +152,7 @@ void LLImageBase::deleteData() // virtual U8* LLImageBase::allocateData(S32 size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); if (size < 0) { @@ -188,7 +188,7 @@ U8* LLImageBase::allocateData(S32 size) // virtual U8* LLImageBase::reallocateData(S32 size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); U8 *new_datap = new U8[size]; if (!new_datap) { @@ -332,7 +332,7 @@ BOOL LLImageRaw::resize(U16 width, U16 height, S8 components) U8 * LLImageRaw::getSubImage(U32 x_pos, U32 y_pos, U32 width, U32 height) const { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); U8 *data = new U8[width*height*getComponents()]; // Should do some simple bounds checking @@ -415,7 +415,7 @@ void LLImageRaw::clear(U8 r, U8 g, U8 b, U8 a) // Reverses the order of the rows in the image void LLImageRaw::verticalFlip() { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); S32 row_bytes = getWidth() * getComponents(); llassert(row_bytes > 0); std::vector line_buffer(row_bytes); @@ -548,7 +548,7 @@ void LLImageRaw::composite( LLImageRaw* src ) // Src and dst can be any size. Src has 4 components. Dst has 3 components. void LLImageRaw::compositeScaled4onto3(LLImageRaw* src) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); llinfos << "compositeScaled4onto3" << llendl; LLImageRaw* dst = this; // Just for clarity. @@ -787,7 +787,7 @@ void LLImageRaw::copyUnscaled3onto4( LLImageRaw* src ) // Src and dst can be any size. Src and dst have same number of components. void LLImageRaw::copyScaled( LLImageRaw* src ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); LLImageRaw* dst = this; // Just for clarity. llassert_always( (1 == src->getComponents()) || (3 == src->getComponents()) || (4 == src->getComponents()) ); @@ -819,7 +819,7 @@ void LLImageRaw::copyScaled( LLImageRaw* src ) BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); llassert((1 == getComponents()) || (3 == getComponents()) || (4 == getComponents()) ); S32 old_width = getWidth(); diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index bd609b638c..8108553107 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -35,8 +35,9 @@ #include "lluuid.h" #include "llstring.h" -#include "llmemory.h" +//#include "llmemory.h" #include "llthread.h" +#include "llmemtype.h" const S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 const S32 MAX_IMAGE_MIP = 11; // 2048x2048 @@ -155,7 +156,7 @@ private: BOOL mBadBufferAllocation ; public: - S16 mMemType; // debug + LLMemType::DeclareMemType& mMemType; // debug static BOOL sSizeOverride; }; diff --git a/indra/llimage/llimagedxt.h b/indra/llimage/llimagedxt.h index bc2d6522d2..1a297536b4 100644 --- a/indra/llimage/llimagedxt.h +++ b/indra/llimage/llimagedxt.h @@ -33,6 +33,7 @@ #define LL_LLIMAGEDXT_H #include "llimage.h" +#include "llpointer.h" // This class decodes and encodes LL DXT files (which may unclude uncompressed RGB or RGBA mipped data) diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp index 900652d06d..2352c8edd7 100644 --- a/indra/llimage/llimagej2c.cpp +++ b/indra/llimage/llimagej2c.cpp @@ -285,7 +285,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time) BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count ) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); BOOL res = TRUE; @@ -335,7 +335,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, F32 encode_time) BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text, F32 encode_time) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); resetLastError(); BOOL res = mImpl->encodeImpl(*this, *raw_imagep, comment_text, encode_time, mReversible); if (!mLastError.empty()) @@ -504,7 +504,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename) BOOL LLImageJ2C::validate(U8 *data, U32 file_size) { - LLMemType mt1((LLMemType::EMemType)mMemType); + LLMemType mt1(mMemType); resetLastError(); diff --git a/indra/llimage/llimagetga.cpp b/indra/llimage/llimagetga.cpp index a6721bfa0f..d8f8003593 100644 --- a/indra/llimage/llimagetga.cpp +++ b/indra/llimage/llimagetga.cpp @@ -31,10 +31,12 @@ #include "linden_common.h" -#include "lldir.h" #include "llimagetga.h" + +#include "lldir.h" #include "llerror.h" #include "llmath.h" +#include "llpointer.h" // For expanding 5-bit pixel values to 8-bit with best rounding // static diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h index 879fcf5565..0d66695d6e 100644 --- a/indra/llimage/llimageworker.h +++ b/indra/llimage/llimageworker.h @@ -34,6 +34,7 @@ #define LL_LLIMAGEWORKER_H #include "llimage.h" +#include "llpointer.h" #include "llworkerthread.h" class LLImageWorker : public LLWorkerClass diff --git a/indra/llimagej2coj/llimagej2coj.cpp b/indra/llimagej2coj/llimagej2coj.cpp index be6b6c817b..ec6264dcf5 100644 --- a/indra/llimagej2coj/llimagej2coj.cpp +++ b/indra/llimagej2coj/llimagej2coj.cpp @@ -37,7 +37,7 @@ #include "openjpeg.h" #include "lltimer.h" -#include "llmemory.h" +//#include "llmemory.h" const char* fallbackEngineInfoLLImageJ2CImpl() { diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h index 2e2adc4d45..e480085453 100644 --- a/indra/llinventory/lleconomy.h +++ b/indra/llinventory/lleconomy.h @@ -32,7 +32,7 @@ #ifndef LL_LLECONOMY_H #define LL_LLECONOMY_H -#include "llmemory.h" +#include "llsingleton.h" class LLMessageSystem; class LLVector3; diff --git a/indra/llinventory/llinventory.cpp b/indra/llinventory/llinventory.cpp index 76de357e2b..5d3fbe5128 100644 --- a/indra/llinventory/llinventory.cpp +++ b/indra/llinventory/llinventory.cpp @@ -133,6 +133,11 @@ LLAssetType::EType LLInventoryObject::getActualType() const return mType; } +BOOL LLInventoryObject::getIsLinkType() const +{ + return LLAssetType::lookupIsLinkType(mType); +} + // See LLInventoryItem override. // virtual const LLUUID& LLInventoryObject::getLinkedUUID() const @@ -1170,109 +1175,8 @@ fail: } -LLXMLNode *LLInventoryItem::exportFileXML(BOOL include_asset_key) const -{ - LLMemType m1(LLMemType::MTYPE_INVENTORY); - LLXMLNode *ret = new LLXMLNode("item", FALSE); - - ret->createChild("uuid", TRUE)->setUUIDValue(1, &mUUID); - ret->createChild("parent_uuid", TRUE)->setUUIDValue(1, &mParentUUID); - - mPermissions.exportFileXML()->setParent(ret); - - // Check for permissions to see the asset id, and if so write it - // out as an asset id. Otherwise, apply our cheesy encryption. - if(include_asset_key) - { - U32 mask = mPermissions.getMaskBase(); - if(((mask & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - || (mAssetUUID.isNull())) - { - ret->createChild("asset_id", FALSE)->setUUIDValue(1, &mAssetUUID); - } - else - { - LLUUID shadow_id(mAssetUUID); - LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); - cipher.encrypt(shadow_id.mData, UUID_BYTES); - - ret->createChild("shadow_id", FALSE)->setUUIDValue(1, &shadow_id); - } - } - - std::string type_str = LLAssetType::lookup(mType); - std::string inv_type_str = LLInventoryType::lookup(mInventoryType); - - ret->createChild("asset_type", FALSE)->setStringValue(type_str); - ret->createChild("inventory_type", FALSE)->setStringValue(inv_type_str); - S32 tmp_flags = (S32) mFlags; - ret->createChild("flags", FALSE)->setByteValue(4, (U8*)(&tmp_flags), LLXMLNode::ENCODING_HEX); - - mSaleInfo.exportFileXML()->setParent(ret); - - std::string temp; - temp.assign(mName); - ret->createChild("name", FALSE)->setStringValue(temp); - temp.assign(mDescription); - ret->createChild("description", FALSE)->setStringValue(temp); - S32 date = mCreationDate; - ret->createChild("creation_date", FALSE)->setIntValue(1, &date); - - return ret; -} - -BOOL LLInventoryItem::importXML(LLXMLNode* node) -{ - BOOL success = FALSE; - if (node) - { - success = TRUE; - LLXMLNodePtr sub_node; - if (node->getChild("uuid", sub_node)) - success = (1 == sub_node->getUUIDValue(1, &mUUID)); - if (node->getChild("parent_uuid", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mParentUUID)); - if (node->getChild("permissions", sub_node)) - success = success && mPermissions.importXML(sub_node); - if (node->getChild("asset_id", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID)); - if (node->getChild("shadow_id", sub_node)) - { - success = success && (1 == sub_node->getUUIDValue(1, &mAssetUUID)); - LLXORCipher cipher(MAGIC_ID.mData, UUID_BYTES); - cipher.decrypt(mAssetUUID.mData, UUID_BYTES); - } - if (node->getChild("asset_type", sub_node)) - mType = LLAssetType::lookup(sub_node->getValue()); - if (node->getChild("inventory_type", sub_node)) - mInventoryType = LLInventoryType::lookup(sub_node->getValue()); - if (node->getChild("flags", sub_node)) - { - S32 tmp_flags = 0; - success = success && (1 == sub_node->getIntValue(1, &tmp_flags)); - mFlags = (U32) tmp_flags; - } - if (node->getChild("sale_info", sub_node)) - success = success && mSaleInfo.importXML(sub_node); - if (node->getChild("name", sub_node)) - mName = sub_node->getValue(); - if (node->getChild("description", sub_node)) - mDescription = sub_node->getValue(); - if (node->getChild("creation_date", sub_node)) - { - S32 date = 0; - success = success && (1 == sub_node->getIntValue(1, &date)); - mCreationDate = date; - } - - if (!success) - { - lldebugs << "LLInventory::importXML() failed for node named '" - << node->getName() << "'" << llendl; - } - } - return success; -} +// Deleted LLInventoryItem::exportFileXML() and LLInventoryItem::importXML() +// because I can't find any non-test code references to it. 2009-05-04 JC S32 LLInventoryItem::packBinaryBucket(U8* bin_bucket, LLPermissions* perm_override) const { diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index 08e3958533..b953e91309 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -40,6 +40,7 @@ #include "llinventorytype.h" #include "llmemtype.h" #include "llpermissions.h" +#include "llrefcount.h" #include "llsaleinfo.h" #include "llsd.h" #include "lluuid.h" @@ -92,11 +93,14 @@ public: virtual const LLUUID& getUUID() const; const LLUUID& getParentUUID() const; virtual const LLUUID& getLinkedUUID() const; // get the inventoryID that this item points to, else this item's inventoryID - virtual const std::string& getName() const; virtual LLAssetType::EType getType() const; LLAssetType::EType getActualType() const; // bypasses indirection for linked items + virtual const std::string& getName() const; + virtual LLAssetType::EType getType() const; + LLAssetType::EType getActualType() const; // bypasses indirection for linked items + BOOL getIsLinkType() const; // mutators - will not call updateServer(); void setUUID(const LLUUID& new_uuid); void rename(const std::string& new_name); @@ -219,6 +223,7 @@ protected: ~LLInventoryItem(); // ref counted public: + MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY); LLInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid, @@ -265,6 +270,10 @@ public: // Check for changes in permissions masks and sale info // and set the corresponding bits in mFlags void accumulatePermissionSlamBits(const LLInventoryItem& old_item); + + // This is currently only used in the Viewer to handle calling cards + // where the creator is actually used to store the target. + void setCreator(const LLUUID& creator) { mPermissions.setCreator(creator); } // Put this inventory item onto the current outgoing mesage. It // assumes you have already called nextBlock(). @@ -281,9 +290,6 @@ public: virtual BOOL importLegacyStream(std::istream& input_stream); virtual BOOL exportLegacyStream(std::ostream& output_stream, BOOL include_asset_key = TRUE) const; - virtual LLXMLNode *exportFileXML(BOOL include_asset_key = TRUE) const; - BOOL importXML(LLXMLNode* node); - // helper functions // pack all information needed to reconstruct this item into the given binary bucket. diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 866d6722a0..a445466b26 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -35,6 +35,7 @@ #include "llinventorytype.h" #include "lldictionary.h" #include "llmemory.h" +#include "llsingleton.h" static const std::string empty_string; diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h index 8961ff96e7..14b28bfe4b 100644 --- a/indra/llinventory/llinventorytype.h +++ b/indra/llinventory/llinventorytype.h @@ -92,11 +92,10 @@ private: ~LLInventoryType( void ); }; -// helper function which returns true if inventory type and asset type +// helper function that returns true if inventory type and asset type // are potentially compatible. For example, an attachment must be an // object, but a wearable can be a bodypart or clothing asset. -bool inventory_and_asset_types_match( - LLInventoryType::EType inventory_type, - LLAssetType::EType asset_type); +bool inventory_and_asset_types_match(LLInventoryType::EType inventory_type, + LLAssetType::EType asset_type); #endif diff --git a/indra/llinventory/lllandmark.cpp b/indra/llinventory/lllandmark.cpp index 13a63bc7d6..83b6392ca8 100644 --- a/indra/llinventory/lllandmark.cpp +++ b/indra/llinventory/lllandmark.cpp @@ -40,7 +40,7 @@ std::pair LLLandmark::mLocalRegion; LLLandmark::region_map_t LLLandmark::mRegions; -LLLandmark::region_callback_t LLLandmark::mRegionCallback; +LLLandmark::region_callback_map_t LLLandmark::sRegionCallbackMap; LLLandmark::LLLandmark() : mGlobalPositionKnown(false) @@ -177,7 +177,7 @@ void LLLandmark::requestRegionHandle( LLMessageSystem* msg, const LLHost& upstream_host, const LLUUID& region_id, - LLRegionHandleCallback* callback) + region_handle_callback_t callback) { if(region_id.isNull()) { @@ -186,7 +186,7 @@ void LLLandmark::requestRegionHandle( if(callback) { const U64 U64_ZERO = 0; - callback->dataReady(region_id, U64_ZERO); + callback(region_id, U64_ZERO); } } else @@ -196,7 +196,7 @@ void LLLandmark::requestRegionHandle( lldebugs << "requestRegionHandle: local" << llendl; if(callback) { - callback->dataReady(region_id, mLocalRegion.second); + callback(region_id, mLocalRegion.second); } } else @@ -207,8 +207,8 @@ void LLLandmark::requestRegionHandle( lldebugs << "requestRegionHandle: upstream" << llendl; if(callback) { - region_callback_t::value_type vt(region_id, callback); - mRegionCallback.insert(vt); + region_callback_map_t::value_type vt(region_id, callback); + sRegionCallbackMap.insert(vt); } lldebugs << "Landmark requesting information about: " << region_id << llendl; @@ -221,7 +221,7 @@ void LLLandmark::requestRegionHandle( { // we have the answer locally - just call the callack. lldebugs << "requestRegionHandle: ready" << llendl; - callback->dataReady(region_id, (*it).second.mRegionHandle); + callback(region_id, (*it).second.mRegionHandle); } } } @@ -259,11 +259,11 @@ void LLLandmark::processRegionIDAndHandle(LLMessageSystem* msg, void**) #endif // make all the callbacks here. - region_callback_t::iterator it; - while((it = mRegionCallback.find(region_id)) != mRegionCallback.end()) + region_callback_map_t::iterator it; + while((it = sRegionCallbackMap.find(region_id)) != sRegionCallbackMap.end()) { - (*it).second->dataReady(region_id, info.mRegionHandle); - mRegionCallback.erase(it); + (*it).second(region_id, info.mRegionHandle); + sRegionCallbackMap.erase(it); } } diff --git a/indra/llinventory/lllandmark.h b/indra/llinventory/lllandmark.h index cb0c11ab87..feaf1a0e9c 100644 --- a/indra/llinventory/lllandmark.h +++ b/indra/llinventory/lllandmark.h @@ -35,6 +35,7 @@ #define LL_LLLANDMARK_H #include +#include #include "llframetimer.h" #include "lluuid.h" #include "v3dmath.h" @@ -42,24 +43,12 @@ class LLMessageSystem; class LLHost; -// virutal base class used for calling back interested parties when a -// region handle comes back. -class LLRegionHandleCallback -{ -public: - LLRegionHandleCallback() {} - virtual ~LLRegionHandleCallback() {} - virtual bool dataReady( - const LLUUID& region_id, - const U64& region_handle) - { - return true; - } -}; - class LLLandmark { public: + // for calling back interested parties when a region handle comes back. + typedef boost::function region_handle_callback_t; + ~LLLandmark() {} // returns true if the position is known. @@ -90,7 +79,7 @@ public: LLMessageSystem* msg, const LLHost& upstream_host, const LLUUID& region_id, - LLRegionHandleCallback* callback); + region_handle_callback_t callback); // Call this method to create a lookup for this region. This // simplifies a lot of the code. @@ -118,8 +107,8 @@ private: static std::pair mLocalRegion; typedef std::map region_map_t; static region_map_t mRegions; - typedef std::multimap region_callback_t; - static region_callback_t mRegionCallback; + typedef std::multimap region_callback_map_t; + static region_callback_map_t sRegionCallbackMap; }; #endif diff --git a/indra/llinventory/llnotecard.h b/indra/llinventory/llnotecard.h index b903f1fdb0..092ab2ce35 100644 --- a/indra/llinventory/llnotecard.h +++ b/indra/llinventory/llnotecard.h @@ -33,7 +33,7 @@ #ifndef LL_NOTECARD_H #define LL_NOTECARD_H -#include "llmemory.h" +#include "llpointer.h" #include "llinventory.h" class LLNotecard diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index a0b27c788f..e48690908e 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -85,13 +85,13 @@ static const std::string PARCEL_CATEGORY_UI_STRING[LLParcel::C_COUNT + 1] = "None", "Linden Location", "Adult", - "Arts & Culture", + "Arts and Culture", "Business", "Educational", "Gaming", "Hangout", "Newcomer Friendly", - "Parks & Nature", + "Parks and Nature", "Residential", "Shopping", "Stage", @@ -199,6 +199,12 @@ void LLParcel::init(const LLUUID &owner_id, mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; + setMediaCurrentURL(LLStringUtil::null); + mMediaURLFilterEnable = FALSE; + mMediaURLFilterList = LLSD::emptyArray(); + mMediaAllowNavigate = TRUE; + mMediaURLTimeout = 0.0f; + mMediaPreventCameraZoom = FALSE; mGroupID.setNull(); @@ -314,6 +320,56 @@ void LLParcel::setMediaHeight(S32 height) { mMediaHeight = height; } + +void LLParcel::setMediaCurrentURL(const std::string& url) +{ + mMediaCurrentURL = url; + // The escaping here must match the escaping in the database + // abstraction layer if it's ever added. + // This should really filter the url in some way. Other than + // simply requiring non-printable. + LLStringFn::replace_nonprintable_in_ascii(mMediaCurrentURL, LL_UNKNOWN_CHAR); + +} + +void LLParcel::setMediaURLResetTimer(F32 time) +{ + mMediaResetTimer.start(); + mMediaResetTimer.setTimerExpirySec(time); +} + +void LLParcel::setMediaURLFilterList(LLSD list) +{ + // sanity check LLSD + // must be array of strings + if (!list.isArray()) + { + return; + } + + for (S32 i = 0; i < list.size(); i++) + { + if (!list[i].isString()) + return; + } + + // can't be too big + const S32 MAX_SIZE = 50; + if (list.size() > MAX_SIZE) + { + LLSD new_list = LLSD::emptyArray(); + + for (S32 i = 0; i < llmin(list.size(), MAX_SIZE); i++) + { + new_list.append(list[i]); + } + + list = new_list; + } + + mMediaURLFilterList = list; +} + // virtual void LLParcel::setLocalID(S32 local_id) { @@ -568,6 +624,34 @@ BOOL LLParcel::importAccessEntry(std::istream& input_stream, LLAccessEntry* entr return input_stream.good(); } +BOOL LLParcel::importMediaURLFilter(std::istream& input_stream, std::string& url) +{ + skip_to_end_of_next_keyword("{", input_stream); + + while(input_stream.good()) + { + skip_comments_and_emptyspace(input_stream); + std::string line, keyword, value; + get_line(line, input_stream, MAX_STRING); + get_keyword_and_value(keyword, value, line); + + if ("}" == keyword) + { + break; + } + else if ("url" == keyword) + { + url = value; + } + else + { + llwarns << "Unknown keyword in parcel media url filter section: <" + << keyword << ">" << llendl; + } + } + return input_stream.good(); +} + // Assumes we are in a block "ParcelData" void LLParcel::packMessage(LLMessageSystem* msg) { @@ -593,6 +677,7 @@ void LLParcel::packMessage(LLMessageSystem* msg) // Assumes we are in a block "ParcelData" void LLParcel::packMessage(LLSD& msg) { + // used in the viewer, the sim uses it's own packer msg["local_id"] = getLocalID(); msg["parcel_flags"] = ll_sd_from_U32(getParcelFlags()); msg["sale_price"] = getSalePrice(); @@ -606,9 +691,15 @@ void LLParcel::packMessage(LLSD& msg) msg["media_height"] = getMediaHeight(); msg["auto_scale"] = getMediaAutoScale(); msg["media_loop"] = getMediaLoop(); + msg["media_current_url"] = getMediaCurrentURL(); msg["obscure_media"] = getObscureMedia(); msg["obscure_music"] = getObscureMusic(); msg["media_id"] = getMediaID(); + msg["media_allow_navigate"] = getMediaAllowNavigate(); + msg["media_prevent_camera_zoom"] = getMediaPreventCameraZoom(); + msg["media_url_timeout"] = getMediaURLTimeout(); + msg["media_url_filter_enable"] = getMediaURLFilterEnable(); + msg["media_url_filter_list"] = getMediaURLFilterList(); msg["group_id"] = getGroupID(); msg["pass_price"] = mPassPrice; msg["pass_hours"] = mPassHours; @@ -678,6 +769,21 @@ void LLParcel::unpackMessage(LLMessageSystem* msg) mObscureMedia = true; mObscureMusic = true; } + + if(msg->getNumberOfBlocks("MediaLinkSharing") > 0) + { + msg->getString("MediaLinkSharing", "MediaCurrentURL", buffer); + setMediaCurrentURL(buffer); + msg->getU8 ( "MediaLinkSharing", "MediaAllowNavigate", mMediaAllowNavigate ); + msg->getU8 ( "MediaLinkSharing", "MediaURLFilterEnable", mMediaURLFilterEnable ); + msg->getU8 ( "MediaLinkSharing", "MediaPreventCameraZoom", mMediaPreventCameraZoom ); + msg->getF32( "MediaLinkSharing", "MediaURLTimeout", mMediaURLTimeout); + } + else + { + setMediaCurrentURL(LLStringUtil::null); + } + } void LLParcel::packAccessEntries(LLMessageSystem* msg, @@ -994,6 +1100,20 @@ BOOL LLParcel::isSaleTimerExpired(const U64& time) return expired; } +BOOL LLParcel::isMediaResetTimerExpired(const U64& time) +{ + if (mMediaResetTimer.getStarted() == FALSE) + { + return FALSE; + } + BOOL expired = mMediaResetTimer.checkExpirationAndReset(0.0); + if (expired) + { + mMediaResetTimer.stop(); + } + return expired; +} + void LLParcel::startSale(const LLUUID& buyer_id, BOOL is_buyer_group) { @@ -1117,6 +1237,12 @@ void LLParcel::clearParcel() mObscureMusic = 1; mMediaWidth = 0; mMediaHeight = 0; + setMediaCurrentURL(LLStringUtil::null); + setMediaURLFilterList(LLSD::emptyArray()); + setMediaURLFilterEnable(FALSE); + setMediaAllowNavigate(TRUE); + setMediaPreventCameraZoom(FALSE); + setMediaURLTimeout(0.0f); setMusicURL(LLStringUtil::null); setInEscrow(FALSE); setAuthorizedBuyerID(LLUUID::null); diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 5a865d27ba..2a9a596912 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -38,6 +38,7 @@ #include "lluuid.h" #include "llparcelflags.h" #include "llpermissions.h" +#include "lltimer.h" #include "v3math.h" @@ -247,6 +248,14 @@ public: void setObscureMusic( U8 flagIn ) { mObscureMusic = flagIn; } void setMediaWidth(S32 width); void setMediaHeight(S32 height); + void setMediaCurrentURL(const std::string& url); + void setMediaURLFilterEnable(U8 enable) { mMediaURLFilterEnable = enable; } + void setMediaURLFilterList(LLSD list); + void setMediaAllowNavigate(U8 enable) { mMediaAllowNavigate = enable; } + void setMediaURLTimeout(F32 timeout) { mMediaURLTimeout = timeout; } + void setMediaPreventCameraZoom(U8 enable) { mMediaPreventCameraZoom = enable; } + + void setMediaURLResetTimer(F32 time); virtual void setLocalID(S32 local_id); // blow away all the extra crap lurking in parcels, including urls, access lists, etc @@ -299,7 +308,8 @@ public: // BOOL importStream(std::istream& input_stream); BOOL importAccessEntry(std::istream& input_stream, LLAccessEntry* entry); -// BOOL exportStream(std::ostream& output_stream); + BOOL importMediaURLFilter(std::istream& input_stream, std::string& url); + // BOOL exportStream(std::ostream& output_stream); void packMessage(LLMessageSystem* msg); void packMessage(LLSD& msg); @@ -341,8 +351,15 @@ public: S32 getMediaHeight() const { return mMediaHeight; } U8 getMediaAutoScale() const { return mMediaAutoScale; } U8 getMediaLoop() const { return mMediaLoop; } + const std::string& getMediaCurrentURL() const { return mMediaCurrentURL; } U8 getObscureMedia() const { return mObscureMedia; } U8 getObscureMusic() const { return mObscureMusic; } + U8 getMediaURLFilterEnable() const { return mMediaURLFilterEnable; } + LLSD getMediaURLFilterList() const { return mMediaURLFilterList; } + U8 getMediaAllowNavigate() const { return mMediaAllowNavigate; } + F32 getMediaURLTimeout() const { return mMediaURLTimeout; } + U8 getMediaPreventCameraZoom() const { return mMediaPreventCameraZoom; } + S32 getLocalID() const { return mLocalID; } const LLUUID& getOwnerID() const { return mOwnerID; } const LLUUID& getGroupID() const { return mGroupID; } @@ -413,6 +430,10 @@ public: void completeSale(U32& type, U8& flags, LLUUID& to_id); void clearSale(); + + BOOL isMediaResetTimerExpired(const U64& time); + + // more accessors U32 getParcelFlags() const { return mParcelFlags; } @@ -591,6 +612,8 @@ protected: LLVector3 mUserLookAt; ELandingType mLandingType; LLTimer mSaleTimerExpires; + LLTimer mMediaResetTimer; + S32 mGraceExtension; // This value is non-zero if there is an auction associated with @@ -618,9 +641,15 @@ protected: S32 mMediaHeight; U8 mMediaAutoScale; U8 mMediaLoop; + std::string mMediaCurrentURL; U8 mObscureMedia; U8 mObscureMusic; LLUUID mMediaID; + U8 mMediaURLFilterEnable; + LLSD mMediaURLFilterList; + U8 mMediaAllowNavigate; + U8 mMediaPreventCameraZoom; + F32 mMediaURLTimeout; S32 mPassPrice; F32 mPassHours; LLVector3 mAABBMin; @@ -650,6 +679,7 @@ public: std::map mBanList; std::map mTempBanList; std::map mTempAccessList; + }; diff --git a/indra/llinventory/llpermissions.cpp b/indra/llinventory/llpermissions.cpp index 036231ccf8..d2e5034734 100644 --- a/indra/llinventory/llpermissions.cpp +++ b/indra/llinventory/llpermissions.cpp @@ -853,67 +853,8 @@ BOOL LLPermissions::exportLegacyStream(std::ostream& output_stream) const return TRUE; } - -LLXMLNode *LLPermissions::exportFileXML() const -{ - LLXMLNode *ret = new LLXMLNode("permissions", FALSE); - - ret->createChild("group_owned", TRUE)->setBoolValue(mIsGroupOwned); - - ret->createChild("base_mask", FALSE)->setByteValue(4, (U8*)&mMaskBase, LLXMLNode::ENCODING_HEX); - ret->createChild("owner_mask", FALSE)->setByteValue(4, (U8*)&mMaskOwner, LLXMLNode::ENCODING_HEX); - ret->createChild("group_mask", FALSE)->setByteValue(4, (U8*)&mMaskGroup, LLXMLNode::ENCODING_HEX); - ret->createChild("everyone_mask", FALSE)->setByteValue(4, (U8*)&mMaskEveryone, LLXMLNode::ENCODING_HEX); - ret->createChild("next_owner_mask", FALSE)->setByteValue(4, (U8*)&mMaskNextOwner, LLXMLNode::ENCODING_HEX); - - ret->createChild("creator_id", FALSE)->setUUIDValue(1, &mCreator); - ret->createChild("owner_id", FALSE)->setUUIDValue(1, &mOwner); - ret->createChild("last_owner_id", FALSE)->setUUIDValue(1, &mLastOwner); - ret->createChild("group_id", FALSE)->setUUIDValue(1, &mGroup); - - return ret; -} - -bool LLPermissions::importXML(LLXMLNode* node) -{ - bool success = false; - if (node) - { - success = true; - LLXMLNodePtr sub_node; - if (node->getChild("base_mask", sub_node)) - success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskBase)); - if (node->getChild("owner_mask", sub_node)) - success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskOwner)); - if (node->getChild("group_mask", sub_node)) - success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskGroup)); - if (node->getChild("everyone_mask", sub_node)) - success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskEveryone)); - if (node->getChild("next_owner_mask", sub_node)) - success = success && (4 == sub_node->getByteValue(4, (U8*)&mMaskNextOwner)); - - if (node->getChild("creator_id", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mCreator)); - if (node->getChild("owner_id", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mOwner)); - if (node->getChild("last_owner_id", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mLastOwner)); - if (node->getChild("group_id", sub_node)) - success = success && (1 == sub_node->getUUIDValue(1, &mGroup)); - if (node->getChild("group_owned", sub_node)) - { - BOOL tmpbool = FALSE; - success = success && (1 == sub_node->getBoolValue(1, &tmpbool)); - mIsGroupOwned = (bool)tmpbool; - } - if (!success) - { - lldebugs << "LLPermissions::importXML() failed for node named '" - << node->getName() << "'" << llendl; - } - } - return success; -} +// Deleted LLPermissions::exportFileXML() and LLPermissions::importXML() +// because I can't find any non-test code references to it. 2009-05-04 JC bool LLPermissions::operator==(const LLPermissions &rhs) const { diff --git a/indra/llinventory/llpermissions.h b/indra/llinventory/llpermissions.h index f03045e265..d5a0881c8f 100644 --- a/indra/llinventory/llpermissions.h +++ b/indra/llinventory/llpermissions.h @@ -256,7 +256,11 @@ public: BOOL setGroupBits( const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits); BOOL setEveryoneBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits); BOOL setNextOwnerBits(const LLUUID& agent, const LLUUID& group, BOOL set, PermissionMask bits); - + + // This is currently only used in the Viewer to handle calling cards + // where the creator is actually used to store the target. Use with care. + void setCreator(const LLUUID& creator) { mCreator = creator; } + // // METHODS // @@ -321,9 +325,6 @@ public: BOOL importLegacyStream(std::istream& input_stream); BOOL exportLegacyStream(std::ostream& output_stream) const; - LLXMLNode *exportFileXML() const; - bool importXML(LLXMLNode* node); - bool operator==(const LLPermissions &rhs) const; bool operator!=(const LLPermissions &rhs) const; diff --git a/indra/llinventory/llpermissionsflags.h b/indra/llinventory/llpermissionsflags.h index afa2adbd90..f810929d68 100644 --- a/indra/llinventory/llpermissionsflags.h +++ b/indra/llinventory/llpermissionsflags.h @@ -32,9 +32,6 @@ #ifndef LL_LLPERMISSIONSFLAGS_H #define LL_LLPERMISSIONSFLAGS_H -// llpermissionsflags.h -// Copyright 2002, Linden Research, Inc. -// // Flags for various permissions bits. // Shared between viewer and simulator. diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index b7afb28adf..930901f309 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -135,38 +135,8 @@ bool LLSaleInfo::fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask) return true; } -LLXMLNode *LLSaleInfo::exportFileXML() const -{ - LLXMLNode *ret = new LLXMLNode("sale_info", FALSE); - std::string type_str = ll_safe_string( lookup(mSaleType)); - ret->createChild("type", TRUE)->setStringValue(1, &type_str); - ret->createChild("price", TRUE)->setIntValue(1, &mSalePrice); - return ret; -} - -BOOL LLSaleInfo::importXML(LLXMLNode* node) -{ - BOOL success = FALSE; - if (node) - { - success = TRUE; - LLXMLNodePtr sub_node; - if (node->getChild("type", sub_node)) - { - mSaleType = lookup(sub_node->getValue().c_str()); - } - if (node->getChild("price", sub_node)) - { - success &= (1 == sub_node->getIntValue(1, &mSalePrice)); - } - if (!success) - { - lldebugs << "LLSaleInfo::importXML() failed for node named '" - << node->getName() << "'" << llendl; - } - } - return success; -} +// Deleted LLSaleInfo::exportFileXML() and LLSaleInfo::importXML() +// because I can't find any non-test code references to it. 2009-05-04 JC BOOL LLSaleInfo::importFile(LLFILE* fp, BOOL& has_perm_mask, U32& perm_mask) { diff --git a/indra/llinventory/llsaleinfo.h b/indra/llinventory/llsaleinfo.h index d546c49fd7..3461a128be 100644 --- a/indra/llinventory/llsaleinfo.h +++ b/indra/llinventory/llsaleinfo.h @@ -101,9 +101,6 @@ public: bool fromLLSD(const LLSD& sd, BOOL& has_perm_mask, U32& perm_mask); BOOL importLegacyStream(std::istream& input_stream, BOOL& has_perm_mask, U32& perm_mask); - LLXMLNode *exportFileXML() const; - BOOL importXML(LLXMLNode* node); - LLSD packMessage() const; void unpackMessage(LLSD sales); diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt index 075d3b3af0..d287a5063a 100644 --- a/indra/llmath/CMakeLists.txt +++ b/indra/llmath/CMakeLists.txt @@ -10,6 +10,7 @@ include_directories( ) set(llmath_SOURCE_FILES + llbbox.cpp llbboxlocal.cpp llcamera.cpp llcoordframe.cpp @@ -39,6 +40,7 @@ set(llmath_HEADER_FILES camera.h coordframe.h + llbbox.h llbboxlocal.h llcamera.h llcoord.h diff --git a/indra/llmath/llbbox.cpp b/indra/llmath/llbbox.cpp new file mode 100644 index 0000000000..acf93a2a38 --- /dev/null +++ b/indra/llmath/llbbox.cpp @@ -0,0 +1,160 @@ +/** + * @file llbbox.cpp + * @brief General purpose bounding box class (Not axis aligned) + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// self include +#include "llbbox.h" + +// library includes +#include "m4math.h" + +void LLBBox::addPointLocal(const LLVector3& p) +{ + if (mEmpty) + { + mMinLocal = p; + mMaxLocal = p; + mEmpty = FALSE; + } + else + { + mMinLocal.mV[VX] = llmin( p.mV[VX], mMinLocal.mV[VX] ); + mMinLocal.mV[VY] = llmin( p.mV[VY], mMinLocal.mV[VY] ); + mMinLocal.mV[VZ] = llmin( p.mV[VZ], mMinLocal.mV[VZ] ); + mMaxLocal.mV[VX] = llmax( p.mV[VX], mMaxLocal.mV[VX] ); + mMaxLocal.mV[VY] = llmax( p.mV[VY], mMaxLocal.mV[VY] ); + mMaxLocal.mV[VZ] = llmax( p.mV[VZ], mMaxLocal.mV[VZ] ); + } +} + +void LLBBox::addPointAgent( LLVector3 p) +{ + p -= mPosAgent; + p.rotVec( ~mRotation ); + addPointLocal( p ); +} + + +void LLBBox::addBBoxAgent(const LLBBox& b) +{ + if (mEmpty) + { + mPosAgent = b.mPosAgent; + mRotation = b.mRotation; + mMinLocal.clearVec(); + mMaxLocal.clearVec(); + } + LLVector3 vertex[8]; + vertex[0].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[1].setVec( b.mMinLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[2].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[3].setVec( b.mMinLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[4].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[5].setVec( b.mMaxLocal.mV[VX], b.mMinLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + vertex[6].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMinLocal.mV[VZ] ); + vertex[7].setVec( b.mMaxLocal.mV[VX], b.mMaxLocal.mV[VY], b.mMaxLocal.mV[VZ] ); + + LLMatrix4 m( b.mRotation ); + m.translate( b.mPosAgent ); + m.translate( -mPosAgent ); + m.rotate( ~mRotation ); + + for( S32 i=0; i<8; i++ ) + { + addPointLocal( vertex[i] * m ); + } +} + + +void LLBBox::expand( F32 delta ) +{ + mMinLocal.mV[VX] -= delta; + mMinLocal.mV[VY] -= delta; + mMinLocal.mV[VZ] -= delta; + mMaxLocal.mV[VX] += delta; + mMaxLocal.mV[VY] += delta; + mMaxLocal.mV[VZ] += delta; +} + +LLVector3 LLBBox::localToAgent(const LLVector3& v) const +{ + LLMatrix4 m( mRotation ); + m.translate( mPosAgent ); + return v * m; +} + +LLVector3 LLBBox::agentToLocal(const LLVector3& v) const +{ + LLMatrix4 m; + m.translate( -mPosAgent ); + m.rotate( ~mRotation ); // inverse rotation + return v * m; +} + +LLVector3 LLBBox::localToAgentBasis(const LLVector3& v) const +{ + LLMatrix4 m( mRotation ); + return v * m; +} + +LLVector3 LLBBox::agentToLocalBasis(const LLVector3& v) const +{ + LLMatrix4 m( ~mRotation ); // inverse rotation + return v * m; +} + +BOOL LLBBox::containsPointLocal(const LLVector3& p) const +{ + if ( (p.mV[VX] < mMinLocal.mV[VX]) + ||(p.mV[VX] > mMaxLocal.mV[VX]) + ||(p.mV[VY] < mMinLocal.mV[VY]) + ||(p.mV[VY] > mMaxLocal.mV[VY]) + ||(p.mV[VZ] < mMinLocal.mV[VZ]) + ||(p.mV[VZ] > mMaxLocal.mV[VZ])) + { + return FALSE; + } + return TRUE; +} + +BOOL LLBBox::containsPointAgent(const LLVector3& p) const +{ + LLVector3 point_local = agentToLocal(p); + return containsPointLocal(point_local); +} + + +/* +LLBBox operator*(const LLBBox &a, const LLMatrix4 &b) +{ + return LLBBox( a.mMin * b, a.mMax * b ); +} +*/ diff --git a/indra/llmath/llbbox.h b/indra/llmath/llbbox.h new file mode 100644 index 0000000000..cd29551b01 --- /dev/null +++ b/indra/llmath/llbbox.h @@ -0,0 +1,103 @@ +/** + * @file llbbox.h + * @brief General purpose bounding box class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_BBOX_H +#define LL_BBOX_H + +#include "v3math.h" +#include "llquaternion.h" + +// Note: "local space" for an LLBBox is defined relative to agent space in terms of +// a translation followed by a rotation. There is no scale term since the LLBBox's min and +// max are not necessarily symetrical and define their own extents. + +class LLBBox +{ +public: + LLBBox() {mEmpty = TRUE;} + LLBBox( const LLVector3& pos_agent, + const LLQuaternion& rot, + const LLVector3& min_local, + const LLVector3& max_local ) + : + mMinLocal( min_local ), mMaxLocal( max_local ), mPosAgent(pos_agent), mRotation( rot), mEmpty( TRUE ) + {} + + // Default copy constructor is OK. + + const LLVector3& getPositionAgent() const { return mPosAgent; } + const LLQuaternion& getRotation() const { return mRotation; } + + const LLVector3& getMinLocal() const { return mMinLocal; } + void setMinLocal( const LLVector3& min ) { mMinLocal = min; } + + const LLVector3& getMaxLocal() const { return mMaxLocal; } + void setMaxLocal( const LLVector3& max ) { mMaxLocal = max; } + + LLVector3 getCenterLocal() const { return (mMaxLocal - mMinLocal) * 0.5f + mMinLocal; } + LLVector3 getCenterAgent() const { return localToAgent( getCenterLocal() ); } + + LLVector3 getExtentLocal() const { return mMaxLocal - mMinLocal; } + + BOOL containsPointLocal(const LLVector3& p) const; + BOOL containsPointAgent(const LLVector3& p) const; + + void addPointAgent(LLVector3 p); + void addBBoxAgent(const LLBBox& b); + + void addPointLocal(const LLVector3& p); + void addBBoxLocal(const LLBBox& b) { addPointLocal( b.mMinLocal ); addPointLocal( b.mMaxLocal ); } + + void expand( F32 delta ); + + LLVector3 localToAgent( const LLVector3& v ) const; + LLVector3 agentToLocal( const LLVector3& v ) const; + + // Changes rotation but not position + LLVector3 localToAgentBasis(const LLVector3& v) const; + LLVector3 agentToLocalBasis(const LLVector3& v) const; + + +// friend LLBBox operator*(const LLBBox& a, const LLMatrix4& b); + +private: + LLVector3 mMinLocal; + LLVector3 mMaxLocal; + LLVector3 mPosAgent; // Position relative to Agent's Region + LLQuaternion mRotation; + BOOL mEmpty; // Nothing has been added to this bbox yet +}; + +//LLBBox operator*(const LLBBox &a, const LLMatrix4 &b); + + +#endif // LL_BBOX_H diff --git a/indra/llmath/llbboxlocal.h b/indra/llmath/llbboxlocal.h index d69028e3aa..0d1e5a3ae5 100644 --- a/indra/llmath/llbboxlocal.h +++ b/indra/llmath/llbboxlocal.h @@ -53,9 +53,6 @@ public: LLVector3 getCenter() const { return (mMax - mMin) * 0.5f + mMin; } LLVector3 getExtent() const { return mMax - mMin; } - BOOL containsPoint(const LLVector3& p) const; - BOOL intersects(const LLBBoxLocal& b) const; - void addPoint(const LLVector3& p); void addBBox(const LLBBoxLocal& b) { addPoint( b.mMin ); addPoint( b.mMax ); } diff --git a/indra/llmath/llmath.h b/indra/llmath/llmath.h index 66451b1a27..f85c4f39f4 100644 --- a/indra/llmath/llmath.h +++ b/indra/llmath/llmath.h @@ -36,8 +36,8 @@ #include #include #include "lldefs.h" -#include "llstl.h" // *TODO: Remove when LLString is gone -#include "llstring.h" // *TODO: Remove when LLString is gone +//#include "llstl.h" // *TODO: Remove when LLString is gone +//#include "llstring.h" // *TODO: Remove when LLString is gone // lltut.h uses is_approx_equal_fraction(). This was moved to its own header // file in llcommon so we can use lltut.h for llcommon tests without making // llcommon depend on llmath. diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h index bced84cb1c..ba8776690a 100644 --- a/indra/llmath/lloctree.h +++ b/indra/llmath/lloctree.h @@ -65,11 +65,10 @@ public: }; template -class LLOctreeTraveler : public LLTreeTraveler +class LLOctreeTraveler { public: - virtual void traverse(const LLTreeNode* node); - virtual void visit(const LLTreeNode* state) { } + virtual void traverse(const LLOctreeNode* node); virtual void visit(const LLOctreeNode* branch) = 0; }; @@ -700,19 +699,16 @@ public: } }; - //======================== // LLOctreeTraveler //======================== template -void LLOctreeTraveler::traverse(const LLTreeNode* tree_node) +void LLOctreeTraveler::traverse(const LLOctreeNode* node) { - const LLOctreeNode* node = (const LLOctreeNode*) tree_node; node->accept(this); for (U32 i = 0; i < node->getChildCount(); i++) { traverse(node->getChild(i)); } } - #endif diff --git a/indra/llmath/llrect.h b/indra/llmath/llrect.h index 9eb58dbbe9..c03a331aff 100644 --- a/indra/llmath/llrect.h +++ b/indra/llmath/llrect.h @@ -64,23 +64,17 @@ public: mLeft(left), mTop(top), mRight(right), mBottom(bottom) {} - LLRectBase(const LLSD& sd) + explicit LLRectBase(const LLSD& sd) { setValue(sd); } - const LLRectBase& operator=(const LLSD& sd) - { - setValue(sd); - return *this; - } - void setValue(const LLSD& sd) { - mLeft = sd[0].asInteger(); - mTop = sd[1].asInteger(); - mRight = sd[2].asInteger(); - mBottom = sd[3].asInteger(); + mLeft = (Type)sd[0].asInteger(); + mTop = (Type)sd[1].asInteger(); + mRight = (Type)sd[2].asInteger(); + mBottom = (Type)sd[3].asInteger(); } LLSD getValue() const @@ -147,10 +141,20 @@ public: // Note: Does NOT follow GL_QUAD conventions: the top and right edges ARE considered part of the rect // returns TRUE if any part of rect is is inside this LLRect - BOOL rectInRect(const LLRectBase* rect) const + BOOL overlaps(const LLRectBase& rect) const { - return mLeft <= rect->mRight && rect->mLeft <= mRight && - mBottom <= rect->mTop && rect->mBottom <= mTop ; + return !(mLeft > rect.mRight + || mRight < rect.mLeft + || mBottom > rect.mTop + || mTop < rect.mBottom); + } + + BOOL contains(const LLRectBase& rect) const + { + return mLeft <= rect.mLeft + && mRight >= rect.mRight + && mBottom <= rect.mBottom + && mTop >= rect.mTop; } LLRectBase& set(Type left, Type top, Type right, Type bottom) @@ -229,26 +233,25 @@ public: return mLeft <= mRight && mBottom <= mTop; } - bool isNull() const + bool isEmpty() const { return mLeft == mRight || mBottom == mTop; } - bool notNull() const + bool notEmpty() const { - return !isNull(); + return !isEmpty(); } - LLRectBase& unionWith(const LLRectBase &other) + void unionWith(const LLRectBase &other) { mLeft = llmin(mLeft, other.mLeft); mRight = llmax(mRight, other.mRight); mBottom = llmin(mBottom, other.mBottom); mTop = llmax(mTop, other.mTop); - return *this; } - LLRectBase& intersectWith(const LLRectBase &other) + void intersectWith(const LLRectBase &other) { mLeft = llmax(mLeft, other.mLeft); mRight = llmin(mRight, other.mRight); @@ -262,7 +265,6 @@ public: { mBottom = mTop; } - return *this; } friend std::ostream &operator<<(std::ostream &s, const LLRectBase &rect) @@ -271,8 +273,8 @@ public: << " W " << rect.getWidth() << " H " << rect.getHeight() << " }"; return s; } - - bool operator==(const LLRectBase &b) + + bool operator==(const LLRectBase &b) const { return ((mLeft == b.mLeft) && (mTop == b.mTop) && @@ -280,7 +282,7 @@ public: (mBottom == b.mBottom)); } - bool operator!=(const LLRectBase &b) + bool operator!=(const LLRectBase &b) const { return ((mLeft != b.mLeft) || (mTop != b.mTop) || diff --git a/indra/llmath/llsdutil_math.cpp b/indra/llmath/llsdutil_math.cpp index 073cb2e3bd..c5176681ce 100644 --- a/indra/llmath/llsdutil_math.cpp +++ b/indra/llmath/llsdutil_math.cpp @@ -165,9 +165,6 @@ LLSD ll_sd_from_color4(const LLColor4& c) LLColor4 ll_color4_from_sd(const LLSD& sd) { LLColor4 c; - c.mV[0] = (F32)sd[0].asReal(); - c.mV[1] = (F32)sd[1].asReal(); - c.mV[2] = (F32)sd[2].asReal(); - c.mV[3] = (F32)sd[3].asReal(); + c.setValue(sd); return c; } diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp index 1250f539f5..a0357a32cc 100644 --- a/indra/llmath/llvolume.cpp +++ b/indra/llmath/llvolume.cpp @@ -3370,7 +3370,8 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, std::vector &segments, const LLVector3& obj_cam_vec, const LLMatrix4& mat, - const LLMatrix3& norm_mat) + const LLMatrix3& norm_mat, + S32 face_mask) { LLMemType m1(LLMemType::MTYPE_VOLUME); @@ -3378,12 +3379,17 @@ void LLVolume::generateSilhouetteVertices(std::vector &vertices, normals.clear(); segments.clear(); + S32 cur_index = 0; //for each face for (face_list_t::iterator iter = mVolumeFaces.begin(); iter != mVolumeFaces.end(); ++iter) { const LLVolumeFace& face = *iter; + if (!(face_mask & (0x1 << cur_index++))) + { + continue; + } if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) { } diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h index e55fe52c91..871b334452 100644 --- a/indra/llmath/llvolume.h +++ b/indra/llmath/llvolume.h @@ -52,7 +52,7 @@ class LLVolume; #include "llquaternion.h" #include "llstrider.h" #include "v4coloru.h" -#include "llmemory.h" +#include "llrefcount.h" #include "llfile.h" //============================================================================ @@ -902,9 +902,13 @@ public: // returns number of triangle indeces required for path/profile mesh S32 getNumTriangleIndices() const; - void generateSilhouetteVertices(std::vector &vertices, std::vector &normals, std::vector &segments, const LLVector3& view_vec, - const LLMatrix4& mat, - const LLMatrix3& norm_mat); + void generateSilhouetteVertices(std::vector &vertices, + std::vector &normals, + std::vector &segments, + const LLVector3& view_vec, + const LLMatrix4& mat, + const LLMatrix3& norm_mat, + S32 face_index); //get the face index of the face that intersects with the given line segment at the point //closest to start. Moves end to the point of intersection. Returns -1 if no intersection. diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h index e10ad94dba..a78ea76a1a 100644 --- a/indra/llmath/llvolumemgr.h +++ b/indra/llmath/llvolumemgr.h @@ -36,7 +36,7 @@ #include #include "llvolume.h" -#include "llmemory.h" +#include "llpointer.h" #include "llthread.h" class LLVolumeParams; @@ -92,8 +92,8 @@ public: // whatever calls getVolume() never owns the LLVolume* and // cannot keep references for long since it may be deleted // later. For best results hold it in an LLPointer. - LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail); - void unrefVolume(LLVolume *volumep); + virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail); + virtual void unrefVolume(LLVolume *volumep); void dump(); diff --git a/indra/llmath/v3color.cpp b/indra/llmath/v3color.cpp index fa7b61cd75..e76607a91f 100644 --- a/indra/llmath/v3color.cpp +++ b/indra/llmath/v3color.cpp @@ -75,6 +75,42 @@ std::ostream& operator<<(std::ostream& s, const LLColor3 &a) return s; } +static F32 hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) +{ + if ( valHUeIn < 0.0f ) valHUeIn += 1.0f; + if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f; + if ( ( 6.0f * valHUeIn ) < 1.0f ) return ( val1In + ( val2In - val1In ) * 6.0f * valHUeIn ); + if ( ( 2.0f * valHUeIn ) < 1.0f ) return ( val2In ); + if ( ( 3.0f * valHUeIn ) < 2.0f ) return ( val1In + ( val2In - val1In ) * ( ( 2.0f / 3.0f ) - valHUeIn ) * 6.0f ); + return ( val1In ); +} + +void LLColor3::setHSL ( F32 hValIn, F32 sValIn, F32 lValIn) +{ + if ( sValIn < 0.00001f ) + { + mV[VRED] = lValIn; + mV[VGREEN] = lValIn; + mV[VBLUE] = lValIn; + } + else + { + F32 interVal1; + F32 interVal2; + + if ( lValIn < 0.5f ) + interVal2 = lValIn * ( 1.0f + sValIn ); + else + interVal2 = ( lValIn + sValIn ) - ( sValIn * lValIn ); + + interVal1 = 2.0f * lValIn - interVal2; + + mV[VRED] = hueToRgb ( interVal1, interVal2, hValIn + ( 1.f / 3.f ) ); + mV[VGREEN] = hueToRgb ( interVal1, interVal2, hValIn ); + mV[VBLUE] = hueToRgb ( interVal1, interVal2, hValIn - ( 1.f / 3.f ) ); + } +} + void LLColor3::calcHSL(F32* hue, F32* saturation, F32* luminance) const { F32 var_R = mV[VRED]; diff --git a/indra/llmath/v3color.h b/indra/llmath/v3color.h index 179687a32e..1915d80502 100644 --- a/indra/llmath/v3color.h +++ b/indra/llmath/v3color.h @@ -79,6 +79,7 @@ public: mV[2] = (F32) sd[2].asReal();; } + void setHSL(F32 hue, F32 saturation, F32 luminance); void calcHSL(F32* hue, F32* saturation, F32* luminance) const; const LLColor3& setToBlack(); // Clears LLColor3 to (0, 0, 0) diff --git a/indra/llmath/v3dmath.h b/indra/llmath/v3dmath.h index a99bf5b4a6..6ab31e8a41 100644 --- a/indra/llmath/v3dmath.h +++ b/indra/llmath/v3dmath.h @@ -53,7 +53,7 @@ class LLVector3d inline LLVector3d(const F64 x, const F64 y, const F64 z); // Initializes LLVector3d to (x. y, z) inline explicit LLVector3d(const F64 *vec); // Initializes LLVector3d to (vec[0]. vec[1], vec[2]) inline explicit LLVector3d(const LLVector3 &vec); - LLVector3d(const LLSD& sd) + explicit LLVector3d(const LLSD& sd) { setValue(sd); } @@ -65,12 +65,6 @@ class LLVector3d mdV[2] = sd[2].asReal(); } - const LLVector3d& operator=(const LLSD& sd) - { - setValue(sd); - return *this; - } - LLSD getValue() const { LLSD ret; diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp index 101e9d075a..f392ac448b 100644 --- a/indra/llmath/v3math.cpp +++ b/indra/llmath/v3math.cpp @@ -314,12 +314,6 @@ void LLVector3::setValue(const LLSD& sd) mV[2] = (F32) sd[2].asReal(); } -const LLVector3& LLVector3::operator=(const LLSD& sd) -{ - setValue(sd); - return *this; -} - const LLVector3& operator*=(LLVector3 &a, const LLQuaternion &rot) { const F32 rw = - rot.mQ[VX] * a.mV[VX] - rot.mQ[VY] * a.mV[VY] - rot.mQ[VZ] * a.mV[VZ]; diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h index 7f96800e21..805d7e6384 100644 --- a/indra/llmath/v3math.h +++ b/indra/llmath/v3math.h @@ -67,14 +67,12 @@ class LLVector3 explicit LLVector3(const LLVector2 &vec); // Initializes LLVector3 to (vec[0]. vec[1], 0) explicit LLVector3(const LLVector3d &vec); // Initializes LLVector3 to (vec[0]. vec[1], vec[2]) explicit LLVector3(const LLVector4 &vec); // Initializes LLVector4 to (vec[0]. vec[1], vec[2]) - LLVector3(const LLSD& sd); + explicit LLVector3(const LLSD& sd); LLSD getValue() const; void setValue(const LLSD& sd); - const LLVector3& operator=(const LLSD& sd); - inline BOOL isFinite() const; // checks to see if all values of LLVector3 are finite BOOL clamp(F32 min, F32 max); // Clamps all values to (min,max), returns TRUE if data changed BOOL clampLength( F32 length_limit ); // Scales vector to limit length to a value diff --git a/indra/llmath/v4color.cpp b/indra/llmath/v4color.cpp index 0cbfce07c9..219b06ec74 100644 --- a/indra/llmath/v4color.cpp +++ b/indra/llmath/v4color.cpp @@ -227,6 +227,40 @@ const LLColor4& LLColor4::setVec(const LLColor3 &vec, F32 a) return (*this); } +void LLColor4::setValue(const LLSD& sd) +{ +#if 0 + // Clamping on setValue from LLSD is inconsistent with other set behavior + F32 val; + bool out_of_range = false; + val = sd[0].asReal(); + mV[0] = llclamp(val, 0.f, 1.f); + out_of_range = mV[0] != val; + + val = sd[1].asReal(); + mV[1] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[1] != val; + + val = sd[2].asReal(); + mV[2] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[2] != val; + + val = sd[3].asReal(); + mV[3] = llclamp(val, 0.f, 1.f); + out_of_range |= mV[3] != val; + + if (out_of_range) + { + llwarns << "LLSD color value out of range!" << llendl; + } +#else + mV[0] = (F32) sd[0].asReal(); + mV[1] = (F32) sd[1].asReal(); + mV[2] = (F32) sd[2].asReal(); + mV[3] = (F32) sd[3].asReal(); +#endif +} + const LLColor4& LLColor4::operator=(const LLColor3 &a) { mV[VX] = a.mV[VX]; @@ -271,6 +305,42 @@ LLColor4 vec3to4(const LLColor3 &vec) return temp; } +static F32 hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) +{ + if ( valHUeIn < 0.0f ) valHUeIn += 1.0f; + if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f; + if ( ( 6.0f * valHUeIn ) < 1.0f ) return ( val1In + ( val2In - val1In ) * 6.0f * valHUeIn ); + if ( ( 2.0f * valHUeIn ) < 1.0f ) return ( val2In ); + if ( ( 3.0f * valHUeIn ) < 2.0f ) return ( val1In + ( val2In - val1In ) * ( ( 2.0f / 3.0f ) - valHUeIn ) * 6.0f ); + return ( val1In ); +} + +void LLColor4::setHSL ( F32 hValIn, F32 sValIn, F32 lValIn) +{ + if ( sValIn < 0.00001f ) + { + mV[VRED] = lValIn; + mV[VGREEN] = lValIn; + mV[VBLUE] = lValIn; + } + else + { + F32 interVal1; + F32 interVal2; + + if ( lValIn < 0.5f ) + interVal2 = lValIn * ( 1.0f + sValIn ); + else + interVal2 = ( lValIn + sValIn ) - ( sValIn * lValIn ); + + interVal1 = 2.0f * lValIn - interVal2; + + mV[VRED] = hueToRgb ( interVal1, interVal2, hValIn + ( 1.f / 3.f ) ); + mV[VGREEN] = hueToRgb ( interVal1, interVal2, hValIn ); + mV[VBLUE] = hueToRgb ( interVal1, interVal2, hValIn - ( 1.f / 3.f ) ); + } +} + void LLColor4::calcHSL(F32* hue, F32* saturation, F32* luminance) const { F32 var_R = mV[VRED]; diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h index 785b47dd37..d6fbdec61e 100644 --- a/indra/llmath/v4color.h +++ b/indra/llmath/v4color.h @@ -58,7 +58,7 @@ class LLColor4 LLColor4(U32 clr); // Initializes LLColor4 to (r=clr>>24, etc)) LLColor4(const F32 *vec); // Initializes LLColor4 to (vec[0]. vec[1], vec[2], 1) LLColor4(const LLColor3 &vec, F32 a = 1.f); // Initializes LLColor4 to (vec, a) - LLColor4(const LLSD& sd); + explicit LLColor4(const LLSD& sd); explicit LLColor4(const LLColor4U& color4u); // "explicit" to avoid automatic conversion explicit LLColor4(const LLVector4& vector4); // "explicit" to avoid automatic conversion @@ -72,14 +72,9 @@ class LLColor4 return ret; } - void setValue(const LLSD& sd) - { - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); - mV[2] = (F32) sd[2].asReal(); - mV[3] = (F32) sd[3].asReal(); - } + void setValue(const LLSD& sd); + void setHSL(F32 hue, F32 saturation, F32 luminance); void calcHSL(F32* hue, F32* saturation, F32* luminance) const; const LLColor4& setToBlack(); // zero LLColor4 to (0, 0, 0, 1) @@ -118,7 +113,6 @@ class LLColor4 F32 &operator[](int idx) { return mV[idx]; } const LLColor4& operator=(const LLColor3 &a); // Assigns vec3 to vec4 and returns vec4 - const LLColor4& operator=(const LLSD& sd); friend std::ostream& operator<<(std::ostream& s, const LLColor4 &a); // Print a friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b); // Return vector a + b @@ -249,7 +243,7 @@ inline LLColor4::LLColor4(void) inline LLColor4::LLColor4(const LLSD& sd) { - *this = sd; + this->setValue(sd); } inline LLColor4::LLColor4(F32 r, F32 g, F32 b) @@ -639,15 +633,5 @@ void LLColor4::clamp() } } -inline const LLColor4& LLColor4::operator=(const LLSD& sd) -{ - mV[0] = (F32) sd[0].asReal(); - mV[1] = (F32) sd[1].asReal(); - mV[2] = (F32) sd[2].asReal(); - mV[3] = (F32) sd[3].asReal(); - - return *this; -} - #endif diff --git a/indra/llmath/v4coloru.h b/indra/llmath/v4coloru.h index 082d0efbb1..4ec5a345eb 100644 --- a/indra/llmath/v4coloru.h +++ b/indra/llmath/v4coloru.h @@ -66,7 +66,7 @@ public: LLColor4U(U8 r, U8 g, U8 b); // Initializes LLColor4U to (r, g, b, 1) LLColor4U(U8 r, U8 g, U8 b, U8 a); // Initializes LLColor4U to (r. g, b, a) LLColor4U(const U8 *vec); // Initializes LLColor4U to (vec[0]. vec[1], vec[2], 1) - LLColor4U(const LLSD& sd) + explicit LLColor4U(const LLSD& sd) { setValue(sd); } @@ -79,12 +79,6 @@ public: mV[3] = sd[3].asInteger(); } - const LLColor4U& operator=(const LLSD& sd) - { - setValue(sd); - return *this; - } - LLSD getValue() const { LLSD ret; @@ -138,6 +132,12 @@ public: static BOOL parseColor4U(const std::string& buf, LLColor4U* value); + // conversion + operator const LLColor4() const + { + return LLColor4(*this); + } + static LLColor4U white; static LLColor4U black; static LLColor4U red; diff --git a/indra/llmath/xform.h b/indra/llmath/xform.h index d3be28f41d..5b7b1900bc 100644 --- a/indra/llmath/xform.h +++ b/indra/llmath/xform.h @@ -173,7 +173,7 @@ BOOL LLXform::setParent(LLXform* parent) { if (cur_par == this) { - llwarns << "LLXform::setParent Creating loop when setting parent!" << llendl; + //llwarns << "LLXform::setParent Creating loop when setting parent!" << llendl; return FALSE; } cur_par = cur_par->mParent; diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt index 81e518cf6e..4eb4a72ae7 100644 --- a/indra/llmessage/CMakeLists.txt +++ b/indra/llmessage/CMakeLists.txt @@ -223,6 +223,23 @@ IF (NOT LINUX AND VIEWER) lltemplatemessagedispatcher.cpp llregionpresenceverifier.cpp ) +# set(TEST_DEBUG on) + set(test_libs + ${LLMESSAGE_LIBRARIES} + ${WINDOWS_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ) + + LL_ADD_INTEGRATION_TEST( + llsdmessage + "llsdmessage.cpp" + "${test_libs}" + ${PYTHON_EXECUTABLE} + "${CMAKE_CURRENT_SOURCE_DIR}/tests/test_llsdmessage_peer.py" + ) + LL_ADD_PROJECT_UNIT_TESTS(llmessage "${llmessage_TEST_SOURCE_FILES}") # Commented out - see rationale at bottom of newview's build file + poppy 2009-06-05 diff --git a/indra/llmessage/llares.h b/indra/llmessage/llares.h index 96d7f6dd31..c709a08499 100644 --- a/indra/llmessage/llares.h +++ b/indra/llmessage/llares.h @@ -45,7 +45,8 @@ # include #endif -#include "llmemory.h" +#include "llpointer.h" +#include "llrefcount.h" #include "lluri.h" class LLQueryResponder; diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp index 2966b602d7..b3087bcc3f 100644 --- a/indra/llmessage/llassetstorage.cpp +++ b/indra/llmessage/llassetstorage.cpp @@ -1025,12 +1025,12 @@ LLSD LLAssetStorage::getPendingDetails(LLAssetStorage::ERequestType rt, { const request_list_t* requests = getRequestList(rt); LLSD sd; - sd["requests"] = getPendingDetails(requests, asset_type, detail_prefix); + sd["requests"] = getPendingDetailsImpl(requests, asset_type, detail_prefix); return sd; } // virtual -LLSD LLAssetStorage::getPendingDetails(const LLAssetStorage::request_list_t* requests, +LLSD LLAssetStorage::getPendingDetailsImpl(const LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const std::string& detail_prefix) const { @@ -1113,11 +1113,11 @@ LLSD LLAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt, const LLUUID& asset_id) const { const request_list_t* requests = getRequestList(rt); - return getPendingRequest(requests, asset_type, asset_id); + return getPendingRequestImpl(requests, asset_type, asset_id); } // virtual -LLSD LLAssetStorage::getPendingRequest(const LLAssetStorage::request_list_t* requests, +LLSD LLAssetStorage::getPendingRequestImpl(const LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) const { @@ -1136,7 +1136,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, const LLUUID& asset_id) { request_list_t* requests = getRequestList(rt); - if (deletePendingRequest(requests, asset_type, asset_id)) + if (deletePendingRequestImpl(requests, asset_type, asset_id)) { llinfos << "Asset " << getRequestName(rt) << " request for " << asset_id << "." << LLAssetType::lookup(asset_type) @@ -1147,7 +1147,7 @@ bool LLAssetStorage::deletePendingRequest(LLAssetStorage::ERequestType rt, } // virtual -bool LLAssetStorage::deletePendingRequest(LLAssetStorage::request_list_t* requests, +bool LLAssetStorage::deletePendingRequestImpl(LLAssetStorage::request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) { diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h index f01ee6a8e8..56adbd5ccf 100644 --- a/indra/llmessage/llassetstorage.h +++ b/indra/llmessage/llassetstorage.h @@ -306,15 +306,15 @@ public: void markAssetToxic( const LLUUID& uuid ); protected: - virtual LLSD getPendingDetails(const request_list_t* requests, + virtual LLSD getPendingDetailsImpl(const request_list_t* requests, LLAssetType::EType asset_type, const std::string& detail_prefix) const; - virtual LLSD getPendingRequest(const request_list_t* requests, + virtual LLSD getPendingRequestImpl(const request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id) const; - virtual bool deletePendingRequest(request_list_t* requests, + virtual bool deletePendingRequestImpl(request_list_t* requests, LLAssetType::EType asset_type, const LLUUID& asset_id); diff --git a/indra/llmessage/llcachename.cpp b/indra/llmessage/llcachename.cpp index 82186fc503..a4304596de 100644 --- a/indra/llmessage/llcachename.cpp +++ b/indra/llmessage/llcachename.cpp @@ -42,11 +42,7 @@ #include "llsdserialize.h" #include "lluuid.h" #include "message.h" - -// Constants -static const std::string CN_WAITING("(Loading...)"); // *TODO: translate -static const std::string CN_NOBODY("(nobody)"); // *TODO: translate -static const std::string CN_NONE("(none)"); // *TODO: translate +#include "llmemtype.h" // llsd serialization constants static const std::string AGENTS("agents"); @@ -65,6 +61,7 @@ const S32 CN_FILE_VERSION = 2; // Globals LLCacheName* gCacheName = NULL; +std::map LLCacheName::sCacheName; /// --------------------------------------------------------------------------- /// class LLCacheNameEntry @@ -76,13 +73,11 @@ public: LLCacheNameEntry(); public: - bool isUnknown() { return (mFirstName.empty() - || mFirstName == std::string("(???)")); }; - - bool mIsGroup; // true if this is a group ID/name - U32 mCreateTime; // unix time_t - std::string mFirstName; // Doubles as the group name - std::string mLastName; // Will be "" for groups + bool mIsGroup; + U32 mCreateTime; // unix time_t + std::string mFirstName; + std::string mLastName; + std::string mGroupName; }; LLCacheNameEntry::LLCacheNameEntry() @@ -94,17 +89,19 @@ class PendingReply { public: LLUUID mID; - LLCacheNameCallback mCallback; + LLCacheNameSignal mSignal; LLHost mHost; - void* mData; - PendingReply(const LLUUID& id, LLCacheNameCallback callback, void* data = NULL) - : mID(id), mCallback(callback), mData(data) - { } - + PendingReply(const LLUUID& id, const LLHost& host) - : mID(id), mCallback(0), mHost(host) - { } - + : mID(id), mHost(host) + { + } + + boost::signals2::connection setCallback(const LLCacheNameCallback& cb) + { + return mSignal.connect(cb); + } + void done() { mID.setNull(); } bool isDone() const { return mID.isNull() != FALSE; } }; @@ -164,7 +161,7 @@ void ReplySender::send(const LLUUID& id, mMsg->addUUIDFast(_PREHASH_ID, id); if(mCurrIsGroup) { - mMsg->addStringFast(_PREHASH_GroupName, entry.mFirstName); + mMsg->addStringFast(_PREHASH_GroupName, entry.mGroupName); } else { @@ -189,10 +186,9 @@ void ReplySender::flush() typedef std::set AskQueue; -typedef std::vector ReplyQueue; +typedef std::list ReplyQueue; typedef std::map PendingQueue; typedef std::map Cache; -typedef std::vector Observers; class LLCacheName::Impl { @@ -213,18 +209,20 @@ public: ReplyQueue mReplyQueue; // requests awaiting replies from us - Observers mObservers; + LLCacheNameSignal mSignal; LLFrameTimer mProcessTimer; Impl(LLMessageSystem* msg); ~Impl(); - + + boost::signals2::connection addPending(const LLUUID& id, const LLCacheNameCallback& callback); + void addPending(const LLUUID& id, const LLHost& host); + void processPendingAsks(); void processPendingReplies(); void sendRequest(const char* msg_name, const AskQueue& queue); bool isRequestPending(const LLUUID& id); - void makeNameRequestForID(const LLUUID& id, bool isGroup, LLHost & fromHost); // Message system callbacks. void processUUIDRequest(LLMessageSystem* msg, bool isGroup); @@ -234,8 +232,6 @@ public: static void handleUUIDNameReply(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameRequest(LLMessageSystem* msg, void** userdata); static void handleUUIDGroupNameReply(LLMessageSystem* msg, void** userdata); - - void notifyObservers(const LLUUID& id, const std::string& first, const std::string& last, BOOL group); }; @@ -250,6 +246,9 @@ LLCacheName::LLCacheName(LLMessageSystem* msg) LLCacheName::LLCacheName(LLMessageSystem* msg, const LLHost& upstream_host) : impl(* new Impl(msg)) { + sCacheName["waiting"] = "(Loading...)"; + sCacheName["nobody"] = "(nobody)"; + sCacheName["none"] = "(none)"; setUpstream(upstream_host); } @@ -275,52 +274,31 @@ LLCacheName::Impl::Impl(LLMessageSystem* msg) LLCacheName::Impl::~Impl() { for_each(mCache.begin(), mCache.end(), DeletePairedPointer()); + for_each(mReplyQueue.begin(), mReplyQueue.end(), DeletePointer()); } +boost::signals2::connection LLCacheName::Impl::addPending(const LLUUID& id, const LLCacheNameCallback& callback) +{ + PendingReply* reply = new PendingReply(id, LLHost()); + boost::signals2::connection res = reply->setCallback(callback); + mReplyQueue.push_back(reply); + return res; +} + +void LLCacheName::Impl::addPending(const LLUUID& id, const LLHost& host) +{ + PendingReply* reply = new PendingReply(id, host); + mReplyQueue.push_back(reply); +} void LLCacheName::setUpstream(const LLHost& upstream_host) { impl.mUpstreamHost = upstream_host; } -void LLCacheName::addObserver(LLCacheNameCallback callback) +boost::signals2::connection LLCacheName::addObserver(const LLCacheNameCallback& callback) { - impl.mObservers.push_back(callback); -} - -void LLCacheName::removeObserver(LLCacheNameCallback callback) -{ - Observers::iterator it = impl.mObservers.begin(); - Observers::iterator end = impl.mObservers.end(); - - for ( ; it != end; ++it) - { - const LLCacheNameCallback& cb = (*it); - if (cb == callback) - { - impl.mObservers.erase(it); - return; - } - } -} - -void LLCacheName::cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data) -{ - ReplyQueue::iterator it = impl.mReplyQueue.begin(); - ReplyQueue::iterator end = impl.mReplyQueue.end(); - - for(; it != end; ++it) - { - const PendingReply& reply = (*it); - - if ((callback == reply.mCallback) - && (id == reply.mID) - && (user_data == reply.mData) ) - { - impl.mReplyQueue.erase(it); - return; - } - } + return impl.mSignal.connect(callback); } void LLCacheName::importFile(LLFILE* fp) @@ -392,7 +370,6 @@ void LLCacheName::importFile(LLFILE* fp) entry->mCreateTime = create_time; entry->mFirstName = firstname; entry->mLastName = lastname; - //llinfos << "Adding entry from file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl; impl.mCache[id] = entry; count++; @@ -429,7 +406,6 @@ bool LLCacheName::importFile(std::istream& istr) entry->mCreateTime = ctime; entry->mFirstName = agent[FIRST].asString(); entry->mLastName = agent[LAST].asString(); - //llinfos << "Adding name entry from XML file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl; impl.mCache[id] = entry; ++count; @@ -450,9 +426,7 @@ bool LLCacheName::importFile(std::istream& istr) LLCacheNameEntry* entry = new LLCacheNameEntry(); entry->mIsGroup = true; entry->mCreateTime = ctime; - entry->mFirstName = group[NAME].asString(); - entry->mLastName = ""; - //llinfos << "Adding group entry from XML file for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl; + entry->mGroupName = group[NAME].asString(); impl.mCache[id] = entry; ++count; } @@ -470,37 +444,37 @@ void LLCacheName::exportFile(std::ostream& ostr) // Only write entries for which we have valid data. LLCacheNameEntry* entry = iter->second; if(!entry - || entry->isUnknown()) - { // No entry, or user or group name is unknown + || (std::string::npos != entry->mFirstName.find('?')) + || (std::string::npos != entry->mGroupName.find('?'))) + { continue; } // store it LLUUID id = iter->first; std::string id_str = id.asString(); - if(entry->mIsGroup) - { // Save group name and ID - data[GROUPS][id_str][NAME] = entry->mFirstName; - data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; - } - else if(!entry->mLastName.empty()) - { // Save user names and ID + if(!entry->mFirstName.empty() && !entry->mLastName.empty()) + { data[AGENTS][id_str][FIRST] = entry->mFirstName; data[AGENTS][id_str][LAST] = entry->mLastName; data[AGENTS][id_str][CTIME] = (S32)entry->mCreateTime; } + else if(entry->mIsGroup && !entry->mGroupName.empty()) + { + data[GROUPS][id_str][NAME] = entry->mGroupName; + data[GROUPS][id_str][CTIME] = (S32)entry->mCreateTime; + } } LLSDSerialize::toPrettyXML(data, ostr); } -// DO NOT CALL THIS FOR GROUP NAMES BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& last) { if(id.isNull()) { - first = CN_NOBODY; + first = sCacheName["nobody"]; last.clear(); return FALSE; } @@ -514,15 +488,23 @@ BOOL LLCacheName::getName(const LLUUID& id, std::string& first, std::string& las } else { - first = CN_WAITING; + first = sCacheName["waiting"]; last.clear(); if (!impl.isRequestPending(id)) { - //llinfos << "**** adding name req for " << id << llendl; impl.mAskNameQueue.insert(id); } + return FALSE; } - return FALSE; + +} +// static +void LLCacheName::LocalizeCacheName(std::string key, std::string value) +{ + if (key!="" && value!= "" ) + sCacheName[key]=value; + else + llwarns<< " Error localizing cache key " << key << " To "<< value<mFirstName.empty()) + if (entry && entry->mGroupName.empty()) { // COUNTER-HACK to combat James' HACK in exportFile()... // this group name was loaded from a name cache that did not @@ -553,12 +535,12 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) if (entry) { - group = entry->mFirstName; + group = entry->mGroupName; return TRUE; } else { - group = CN_WAITING; + group = sCacheName["waiting"]; if (!impl.isRequestPending(id)) { impl.mAskGroupQueue.insert(id); @@ -566,22 +548,39 @@ BOOL LLCacheName::getGroupName(const LLUUID& id, std::string& group) return FALSE; } } - -// TODO: Make the cache name callback take a SINGLE std::string, -// not a separate first and last name. -void LLCacheName::getNameFromUUID(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data) +// This is a little bit kludgy. LLCacheNameCallback is a slot instead of a function pointer. +// The reason it is a slot is so that the legacy get() function below can bind an old callback +// and pass it as a slot. The reason it isn't a boost::function is so that trackable behavior +// deson't get lost. As a result, we have to bind the slot to a signal to call it, even when +// we call it immediately. -Steve +// NOTE: Even though passing first and last name is a bit of extra overhead, it eliminates the +// potential need for any parsing should any code need to handle first and last name independently. +boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback) { + boost::signals2::connection res; + if(id.isNull()) { - callback(id, CN_NOBODY, "", is_group, user_data); - return; + LLCacheNameSignal signal; + signal.connect(callback); + signal(id, sCacheName["nobody"], "", is_group); + return res; } LLCacheNameEntry* entry = get_ptr_in_map(impl.mCache, id ); if (entry) { - // id found in map therefore we can call the callback immediately. mLastName will be empty for groups - callback(id, entry->mFirstName, entry->mLastName, entry->mIsGroup, user_data); + LLCacheNameSignal signal; + signal.connect(callback); + // id found in map therefore we can call the callback immediately. + if (entry->mIsGroup) + { + signal(id, entry->mGroupName, "", entry->mIsGroup); + } + else + { + signal(id, entry->mFirstName, entry->mLastName, entry->mIsGroup); + } } else { @@ -590,23 +589,26 @@ void LLCacheName::getNameFromUUID(const LLUUID& id, BOOL is_group, LLCacheNameCa { if (is_group) { - //llinfos << "Group queued for " << id << llendl; impl.mAskGroupQueue.insert(id); } else { - //llinfos << "Name queued for " << id << llendl; impl.mAskNameQueue.insert(id); } } - - // There may be multiple replies for the same ID request - impl.mReplyQueue.push_back(PendingReply(id, callback, user_data)); + res = impl.addPending(id, callback); } + return res; +} + +boost::signals2::connection LLCacheName::get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data) +{ + return get(id, is_group, boost::bind(callback, _1, _2, _3, _4, user_data)); } void LLCacheName::processPending() { + LLMemType mt_pp(LLMemType::MTYPE_CACHE_PROCESS_PENDING); const F32 SECS_BETWEEN_PROCESS = 0.1f; if(!impl.mProcessTimer.checkExpirationAndReset(SECS_BETWEEN_PROCESS)) { @@ -665,7 +667,7 @@ void LLCacheName::dump() { llinfos << iter->first << " = (group) " - << entry->mFirstName + << entry->mGroupName << " @ " << entry->mCreateTime << llendl; } @@ -688,18 +690,19 @@ void LLCacheName::dumpStats() << " AskGroup=" << impl.mAskGroupQueue.size() << " Pending=" << impl.mPendingQueue.size() << " Reply=" << impl.mReplyQueue.size() - << " Observers=" << impl.mObservers.size() +// << " Observers=" << impl.mSignal.size() << llendl; } //static std::string LLCacheName::getDefaultName() { - return CN_WAITING; + return sCacheName["waiting"]; } void LLCacheName::Impl::processPendingAsks() { + LLMemType mt_ppa(LLMemType::MTYPE_CACHE_PROCESS_PENDING_ASKS); sendRequest(_PREHASH_UUIDNameRequest, mAskNameQueue); sendRequest(_PREHASH_UUIDGroupNameRequest, mAskGroupQueue); mAskNameQueue.clear(); @@ -708,40 +711,50 @@ void LLCacheName::Impl::processPendingAsks() void LLCacheName::Impl::processPendingReplies() { - ReplyQueue::iterator it = mReplyQueue.begin(); - ReplyQueue::iterator end = mReplyQueue.end(); - + LLMemType mt_ppr(LLMemType::MTYPE_CACHE_PROCESS_PENDING_REPLIES); // First call all the callbacks, because they might send messages. - for(; it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mCallback) + if (!entry->mIsGroup) { - (it->mCallback)(it->mID, entry->mFirstName, entry->mLastName, entry->mIsGroup, it->mData); + (reply->mSignal)(reply->mID, entry->mFirstName, entry->mLastName, FALSE); + } + else + { + (reply->mSignal)(reply->mID, entry->mGroupName, "", TRUE); } } // Forward on all replies, if needed. ReplySender sender(mMsg); - for (it = mReplyQueue.begin(); it != end; ++it) + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ++it) { - LLCacheNameEntry* entry = get_ptr_in_map(mCache, it->mID); + PendingReply* reply = *it; + LLCacheNameEntry* entry = get_ptr_in_map(mCache, reply->mID); if(!entry) continue; - if (it->mHost.isOk()) + if (reply->mHost.isOk()) { - sender.send(it->mID, *entry, it->mHost); + sender.send(reply->mID, *entry, reply->mHost); } - it->done(); + reply->done(); + } + + for(ReplyQueue::iterator it = mReplyQueue.begin(); it != mReplyQueue.end(); ) + { + ReplyQueue::iterator curit = it++; + PendingReply* reply = *curit; + if (reply->isDone()) + { + delete reply; + mReplyQueue.erase(curit); + } } - - mReplyQueue.erase( - remove_if(mReplyQueue.begin(), mReplyQueue.end(), - std::mem_fun_ref(&PendingReply::isDone)), - mReplyQueue.end()); } @@ -762,12 +775,10 @@ void LLCacheName::Impl::sendRequest( if(start_new_message) { start_new_message = false; - //llinfos << "newMessageFast : " << msg_name << llendl; mMsg->newMessageFast(msg_name); } mMsg->nextBlockFast(_PREHASH_UUIDNameBlock); mMsg->addUUIDFast(_PREHASH_ID, (*it)); - //llinfos << " asking for ID: " << (*it) << llendl; if(mMsg->isSendFullFast(_PREHASH_UUIDNameBlock)) { @@ -781,18 +792,6 @@ void LLCacheName::Impl::sendRequest( } } -void LLCacheName::Impl::notifyObservers(const LLUUID& id, - const std::string& first, const std::string& last, BOOL is_group) -{ - for (Observers::const_iterator i = mObservers.begin(), - end = mObservers.end(); - i != end; - ++i) - { - (**i)(id, first, last, is_group, NULL); - } -} - bool LLCacheName::Impl::isRequestPending(const LLUUID& id) { U32 now = (U32)time(NULL); @@ -833,102 +832,38 @@ void LLCacheName::Impl::processUUIDRequest(LLMessageSystem* msg, bool isGroup) { if (isGroup != entry->mIsGroup) { - if (entry->isUnknown()) - { - Cache::iterator doomediter = mCache.find(id); - if (doomediter != mCache.end()) - { // Kill existing unknown entry - llwarns << "LLCacheName - Asked for " - << (isGroup ? "group" : "user") << " name, " - << "but found unknown " - << (entry->mIsGroup ? "group" : "user") - << " entry for: " << id - << ", deleting bad entry" - << llendl; - - delete entry; - entry = NULL; - mCache.erase(doomediter); - - // Request it with (hopefully) the correct type - makeNameRequestForID(id,isGroup,fromHost); - } - } - else if (isGroup) - { - llwarns << "LLCacheName - Asked for group name, but found user: " - << id - << " named " - << entry->mFirstName << " " << entry->mLastName - << llendl; - } - else - { - llwarns << "LLCacheName - Asked for user name, but found group: " - << id - << " named " - << entry->mFirstName - << llendl; - } + llwarns << "LLCacheName - Asked for " + << (isGroup ? "group" : "user") << " name, " + << "but found " + << (entry->mIsGroup ? "group" : "user") + << ": " << id << llendl; } else { // ...it's in the cache, so send it as the reply sender.send(id, *entry, fromHost); - - /* + } + } + else + { + if (!isRequestPending(id)) + { if (isGroup) { - llinfos << "Group ID " << id - << " name " << entry->mFirstName - << " was already in cache" << llendl; + mAskGroupQueue.insert(id); } else { - llinfos << "Agent ID " << id - << " name " << entry->mFirstName << " " << entry->mLastName - << " was already in cache" << llendl; + mAskNameQueue.insert(id); } - */ } - } - else - { /* - if (isGroup) - { - llinfos << "Group ID " << id << " is not in cache" << llendl; - } - else - { - llinfos << "Agent ID " << id << " is not in cache" << llendl; - } - */ - makeNameRequestForID(id,isGroup,fromHost); + + addPending(id, fromHost); } } } -void LLCacheName::Impl::makeNameRequestForID(const LLUUID& id, bool isGroup, LLHost & fromHost) -{ - if (!isRequestPending(id)) - { - if (isGroup) - { - //llinfos << "Adding group request for " << id << llendl; - mAskGroupQueue.insert(id); - } - else - { - //llinfos << "Adding name request for " << id << llendl; - mAskNameQueue.insert(id); - } - } - - // There may be multiple replys for the same ID request - mReplyQueue.push_back(PendingReply(id, fromHost)); -} - void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) { @@ -938,53 +873,35 @@ void LLCacheName::Impl::processUUIDReply(LLMessageSystem* msg, bool isGroup) LLUUID id; msg->getUUIDFast(_PREHASH_UUIDNameBlock, _PREHASH_ID, id, i); LLCacheNameEntry* entry = get_ptr_in_map(mCache, id); - bool add_new_entry_to_cache = false; if (!entry) { entry = new LLCacheNameEntry; - add_new_entry_to_cache = true; - } - - // Remove ID from pending queue - mPendingQueue.erase(id); - - std::string first_name; - std::string last_name; - if (isGroup) - { // Group - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, first_name, i); - LLStringFn::replace_ascii_controlchars(first_name, LL_UNKNOWN_CHAR); - } - else - { // User - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, first_name, i); - msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, last_name, i); - } - - if (!add_new_entry_to_cache && - (entry->mFirstName != first_name || - entry->mLastName != last_name || - entry->mIsGroup != isGroup)) - { // Hmmm, we already had an different entry for this ID. Let's see what happened... - llwarns << "Replacing existing entry in name cache for id " << id - << " first name was " << entry->mFirstName << ", now " << first_name - << " last name was " << entry->mLastName << ", now " << last_name - << " group flag was " << (S32) entry->mIsGroup << ", now " << (S32) isGroup - << llendl; - } - - entry->mFirstName = first_name; - entry->mLastName = last_name; - entry->mIsGroup = isGroup; - entry->mCreateTime = (U32)time(NULL); - - if (add_new_entry_to_cache) - { - //llinfos << "Adding entry for " << entry->mFirstName << " " << entry->mLastName << ", id " << id << llendl; mCache[id] = entry; } - notifyObservers(id, entry->mFirstName, entry->mLastName, isGroup); + mPendingQueue.erase(id); + + entry->mIsGroup = isGroup; + entry->mCreateTime = (U32)time(NULL); + if (!isGroup) + { + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_FirstName, entry->mFirstName, i); + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_LastName, entry->mLastName, i); + } + else + { // is group + msg->getStringFast(_PREHASH_UUIDNameBlock, _PREHASH_GroupName, entry->mGroupName, i); + LLStringFn::replace_ascii_controlchars(entry->mGroupName, LL_UNKNOWN_CHAR); + } + + if (!isGroup) + { + mSignal(id, entry->mFirstName, entry->mLastName, FALSE); + } + else + { + mSignal(id, entry->mGroupName, "", TRUE); + } } } diff --git a/indra/llmessage/llcachename.h b/indra/llmessage/llcachename.h index bfa116ad4a..c044b3d80d 100644 --- a/indra/llmessage/llcachename.h +++ b/indra/llmessage/llcachename.h @@ -33,12 +33,22 @@ #ifndef LL_LLCACHENAME_H #define LL_LLCACHENAME_H +#include +#include + class LLMessageSystem; class LLHost; class LLUUID; -// agent_id/group_id, first_name, last_name, is_group, user_data -typedef void (*LLCacheNameCallback)(const LLUUID&, const std::string&, const std::string&, BOOL, void*); + +typedef boost::signals2::signal LLCacheNameSignal; +typedef LLCacheNameSignal::slot_type LLCacheNameCallback; + +// Old callback with user data for compatability +typedef void (*old_callback_t)(const LLUUID&, const std::string&, const std::string&, BOOL, void*); // Here's the theory: // If you request a name that isn't in the cache, it returns "waiting" @@ -59,10 +69,7 @@ public: // for simulators, this is the data server void setUpstream(const LLHost& upstream_host); - void addObserver(LLCacheNameCallback callback); - void removeObserver(LLCacheNameCallback callback); - - void cancelCallback(const LLUUID& id, LLCacheNameCallback callback, void* user_data = NULL); + boost::signals2::connection addObserver(const LLCacheNameCallback& callback); // janky old format. Remove after a while. Phoenix. 2008-01-30 void importFile(LLFILE* fp); @@ -89,8 +96,10 @@ public: // If the data is currently available, may call the callback immediatly // otherwise, will request the data, and will call the callback when // available. There is no garuntee the callback will ever be called. - void getNameFromUUID(const LLUUID& id, BOOL is_group, LLCacheNameCallback callback, void* user_data = NULL); + boost::signals2::connection get(const LLUUID& id, BOOL is_group, const LLCacheNameCallback& callback); + // LEGACY + boost::signals2::connection get(const LLUUID& id, BOOL is_group, old_callback_t callback, void* user_data); // This method needs to be called from time to time to send out // requests. void processPending(); @@ -103,7 +112,8 @@ public: void dumpStats(); // Dumps the sizes of the cache and associated queues. static std::string getDefaultName(); - + static void LocalizeCacheName(std::string key, std::string value); + static std::map sCacheName; private: class Impl; diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp index 1a432cd7df..a4af8e989b 100644 --- a/indra/llmessage/llcurl.cpp +++ b/indra/llmessage/llcurl.cpp @@ -120,7 +120,7 @@ LLCurl::Responder::~Responder() } // virtual -void LLCurl::Responder::error( +void LLCurl::Responder::errorWithContent( U32 status, const std::string& reason, const LLSD&) @@ -161,7 +161,7 @@ void LLCurl::Responder::completed(U32 status, const std::string& reason, const L } else { - error(status, reason, content); + errorWithContent(status, reason, content); } } diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h index ff63904c91..fbd3077cbf 100644 --- a/indra/llmessage/llcurl.h +++ b/indra/llmessage/llcurl.h @@ -85,7 +85,7 @@ public: return((200 <= status) && (status < 300)); } - virtual void error( + virtual void errorWithContent( U32 status, const std::string& reason, const LLSD& content); diff --git a/indra/llmessage/llhttpassetstorage.cpp b/indra/llmessage/llhttpassetstorage.cpp index dfdad59e2a..49dbdbd56d 100644 --- a/indra/llmessage/llhttpassetstorage.cpp +++ b/indra/llmessage/llhttpassetstorage.cpp @@ -626,7 +626,7 @@ LLSD LLHTTPAssetStorage::getPendingRequest(LLAssetStorage::ERequestType rt, const request_list_t* running = getRunningList(rt); if (running) { - LLSD sd = LLAssetStorage::getPendingRequest(running, asset_type, asset_id); + LLSD sd = LLAssetStorage::getPendingRequestImpl(running, asset_type, asset_id); if (sd) { sd["is_running"] = true; diff --git a/indra/llmessage/llhttpassetstorage.h b/indra/llmessage/llhttpassetstorage.h index 5786c5df32..231437dad4 100644 --- a/indra/llmessage/llhttpassetstorage.h +++ b/indra/llmessage/llhttpassetstorage.h @@ -62,6 +62,8 @@ public: virtual ~LLHTTPAssetStorage(); + using LLAssetStorage::storeAssetData; // Unhiding virtuals... + virtual void storeAssetData( const LLUUID& uuid, LLAssetType::EType atype, diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp index 5236a52164..9d3c83f828 100644 --- a/indra/llmessage/llhttpclientadapter.cpp +++ b/indra/llmessage/llhttpclientadapter.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llmessage/llhttpclientadapter.h b/indra/llmessage/llhttpclientadapter.h index c489dca32d..a205a2f260 100644 --- a/indra/llmessage/llhttpclientadapter.h +++ b/indra/llmessage/llhttpclientadapter.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2001-2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -33,7 +34,7 @@ #define LL_HTTPCLIENTADAPTER_H #include "llhttpclientinterface.h" -#include "llmemory.h" // LLSingleton<> +#include "llsingleton.h" // LLSingleton<> class LLHTTPClientAdapter : public LLHTTPClientInterface, public LLSingleton { diff --git a/indra/llmessage/llhttpclientinterface.h b/indra/llmessage/llhttpclientinterface.h index 61826cc4b4..085a59cf27 100644 --- a/indra/llmessage/llhttpclientinterface.h +++ b/indra/llmessage/llhttpclientinterface.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2001-2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp index 2ba900a533..440b91fcfa 100644 --- a/indra/llmessage/llhttpnode.cpp +++ b/indra/llmessage/llhttpnode.cpp @@ -98,19 +98,19 @@ namespace { } // virtual -LLSD LLHTTPNode::get() const +LLSD LLHTTPNode::simpleGet() const { throw NotImplemented(); } // virtual -LLSD LLHTTPNode::put(const LLSD& input) const +LLSD LLHTTPNode::simplePut(const LLSD& input) const { throw NotImplemented(); } // virtual -LLSD LLHTTPNode::post(const LLSD& input) const +LLSD LLHTTPNode::simplePost(const LLSD& input) const { throw NotImplemented(); } @@ -121,7 +121,7 @@ void LLHTTPNode::get(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { try { - response->result(get()); + response->result(simpleGet()); } catch (NotImplemented) { @@ -134,7 +134,7 @@ void LLHTTPNode::put(LLHTTPNode::ResponsePtr response, const LLSD& context, cons { try { - response->result(put(input)); + response->result(simplePut(input)); } catch (NotImplemented) { @@ -147,7 +147,7 @@ void LLHTTPNode::post(LLHTTPNode::ResponsePtr response, const LLSD& context, con { try { - response->result(post(input)); + response->result(simplePost(input)); } catch (NotImplemented) { @@ -160,7 +160,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons { try { - response->result(del(context)); + response->result(simpleDel(context)); } catch (NotImplemented) { @@ -170,7 +170,7 @@ void LLHTTPNode::del(LLHTTPNode::ResponsePtr response, const LLSD& context) cons } // virtual -LLSD LLHTTPNode::del(const LLSD&) const +LLSD LLHTTPNode::simpleDel(const LLSD&) const { throw NotImplemented(); } @@ -388,7 +388,7 @@ LLHTTPNode::Response::~Response() { } -void LLHTTPNode::Response::status(S32 code) +void LLHTTPNode::Response::statusUnknownError(S32 code) { status(code, "Unknown Error"); } diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h index 17ffd66e8f..915aacb7cc 100644 --- a/indra/llmessage/llhttpnode.h +++ b/indra/llmessage/llhttpnode.h @@ -33,7 +33,8 @@ #ifndef LL_LLHTTPNODE_H #define LL_LLHTTPNODE_H -#include "llmemory.h" +#include "llpointer.h" +#include "llrefcount.h" #include "llsd.h" class LLChainIOFactory; @@ -83,10 +84,10 @@ public: //@{ public: - virtual LLSD get() const; - virtual LLSD put(const LLSD& input) const; - virtual LLSD post(const LLSD& input) const; - virtual LLSD del(const LLSD& context) const; + virtual LLSD simpleGet() const; + virtual LLSD simplePut(const LLSD& input) const; + virtual LLSD simplePost(const LLSD& input) const; + virtual LLSD simpleDel(const LLSD& context) const; /** * @brief Abstract Base Class declaring Response interface. @@ -116,7 +117,7 @@ public: /** * @brief Return no body, just status code and 'UNKNOWN ERROR'. */ - virtual void status(S32 code); + virtual void statusUnknownError(S32 code); virtual void notFound(const std::string& message); virtual void notFound(); @@ -292,6 +293,7 @@ public: void result(const LLSD& result); void extendedResult(S32 code, const std::string& body, const LLSD& headers); + void status(S32 code, const std::string& message); void print(std::ostream& out) const; diff --git a/indra/llmessage/llhttpnodeadapter.h b/indra/llmessage/llhttpnodeadapter.h index 08b5664162..7c3e9d81d1 100644 --- a/indra/llmessage/llhttpnodeadapter.h +++ b/indra/llmessage/llhttpnodeadapter.h @@ -3,26 +3,27 @@ * @brief Declaration of llhttpnode adapter classes * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * + * * Copyright (c) 2009, Linden Research, Inc. - * + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/llinstantmessage.cpp b/indra/llmessage/llinstantmessage.cpp index 3205ddfaeb..7c63625004 100644 --- a/indra/llmessage/llinstantmessage.cpp +++ b/indra/llmessage/llinstantmessage.cpp @@ -41,7 +41,7 @@ #include "llsd.h" #include "llsdserialize.h" #include "llsdutil.h" -#include "llmemory.h" +#include "llpointer.h" #include "message.h" #include "message.h" diff --git a/indra/llmessage/llinstantmessage.h b/indra/llmessage/llinstantmessage.h index 9ce6a10c80..272e753f3c 100644 --- a/indra/llmessage/llinstantmessage.h +++ b/indra/llmessage/llinstantmessage.h @@ -36,7 +36,8 @@ #include "llhost.h" #include "lluuid.h" #include "llsd.h" -#include "llmemory.h" +#include "llrefcount.h" +#include "llpointer.h" #include "v3math.h" class LLMessageSystem; diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp index ce815cc85b..97134bd336 100644 --- a/indra/llmessage/lliohttpserver.cpp +++ b/indra/llmessage/lliohttpserver.cpp @@ -105,6 +105,7 @@ private: // from LLHTTPNode::Response virtual void result(const LLSD&); virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers); + virtual void status(S32 code, const std::string& message); void nullPipe(); diff --git a/indra/llmessage/llmessagesenderinterface.h b/indra/llmessage/llmessagesenderinterface.h index d98d891563..af6733fa05 100644 --- a/indra/llmessage/llmessagesenderinterface.h +++ b/indra/llmessage/llmessagesenderinterface.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2001-2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp index 3e3f0b37a7..5e9dfd81fa 100644 --- a/indra/llmessage/llpumpio.cpp +++ b/indra/llmessage/llpumpio.cpp @@ -444,11 +444,13 @@ void LLPumpIO::pump() pump(DEFAULT_POLL_TIMEOUT); } +static LLFastTimer::DeclareTimer FTM_PUMP("Pump"); + //timeout is in microseconds void LLPumpIO::pump(const S32& poll_timeout) { LLMemType m1(LLMemType::MTYPE_IO_PUMP); - LLFastTimer t1(LLFastTimer::FTM_PUMP); + LLFastTimer t1(FTM_PUMP); //llinfos << "LLPumpIO::pump()" << llendl; // Run any pending runners. diff --git a/indra/llmessage/llregionpresenceverifier.cpp b/indra/llmessage/llregionpresenceverifier.cpp index 08c12f90da..4faad4468b 100644 --- a/indra/llmessage/llregionpresenceverifier.cpp +++ b/indra/llmessage/llregionpresenceverifier.cpp @@ -4,14 +4,25 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * - * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of - * this source code is governed by the Linden Lab Source Code Disclosure - * Agreement ("Agreement") previously entered between you and Linden - * Lab. By accessing, using, copying, modifying or distributing this - * software, you acknowledge that you have been informed of your - * obligations under the Agreement and agree to abide by those obligations. + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, diff --git a/indra/llmessage/llregionpresenceverifier.h b/indra/llmessage/llregionpresenceverifier.h index f11eeef50c..f57a62a731 100644 --- a/indra/llmessage/llregionpresenceverifier.h +++ b/indra/llmessage/llregionpresenceverifier.h @@ -4,14 +4,25 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * - * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of - * this source code is governed by the Linden Lab Source Code Disclosure - * Agreement ("Agreement") previously entered between you and Linden - * Lab. By accessing, using, copying, modifying or distributing this - * software, you acknowledge that you have been informed of your - * obligations under the Agreement and agree to abide by those obligations. + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, @@ -72,6 +83,7 @@ public: const LLSD& content, S32 retry_count); virtual ~VerifiedDestinationResponder(); virtual void result(const LLSD& content); + virtual void error(U32 status, const std::string& reason); private: diff --git a/indra/llmessage/llsdappservices.cpp b/indra/llmessage/llsdappservices.cpp index dc135c51b2..b87c0cd6b7 100644 --- a/indra/llmessage/llsdappservices.cpp +++ b/indra/llmessage/llsdappservices.cpp @@ -56,7 +56,7 @@ public: desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { LLSD result; LLApp* app = LLApp::instance(); @@ -82,7 +82,7 @@ public: desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { return LLApp::instance()->getOptionData( LLApp::PRIORITY_RUNTIME_OVERRIDE); diff --git a/indra/llmessage/llsdhttpserver.cpp b/indra/llmessage/llsdhttpserver.cpp index 00fc170c59..704c375ffc 100644 --- a/indra/llmessage/llsdhttpserver.cpp +++ b/indra/llmessage/llsdhttpserver.cpp @@ -62,7 +62,7 @@ public: desc.source(__FILE__, __LINE__); } - virtual LLSD get() const + virtual LLSD simpleGet() const { LLSD result = "hello"; return result; @@ -86,7 +86,7 @@ public: desc.source(__FILE__, __LINE__); } - virtual LLSD post(const LLSD& params) const + virtual LLSD simplePost(const LLSD& params) const { return params; } diff --git a/indra/llmessage/llsdmessage.cpp b/indra/llmessage/llsdmessage.cpp index f663268466..9967a6197f 100644 --- a/indra/llmessage/llsdmessage.cpp +++ b/indra/llmessage/llsdmessage.cpp @@ -91,7 +91,7 @@ void LLSDMessage::EventResponder::result(const LLSD& data) } } -void LLSDMessage::EventResponder::error(U32 status, const std::string& reason, const LLSD& content) +void LLSDMessage::EventResponder::errorWithContent(U32 status, const std::string& reason, const LLSD& content) { // If our caller passed an empty errorPump name, they're not // listening: "default error handling is acceptable." Only post to an @@ -135,7 +135,7 @@ bool LLSDMessage::ResponderAdapter::listener(const LLSD& payload, bool success) } else { - mResponder->error(payload["status"].asInteger(), payload["reason"], payload["content"]); + mResponder->errorWithContent(payload["status"].asInteger(), payload["reason"], payload["content"]); } /*---------------- MUST BE LAST STATEMENT BEFORE RETURN ----------------*/ diff --git a/indra/llmessage/llsdmessage.h b/indra/llmessage/llsdmessage.h index 8ae9451243..65503756a8 100644 --- a/indra/llmessage/llsdmessage.h +++ b/indra/llmessage/llsdmessage.h @@ -131,7 +131,7 @@ private: {} virtual void result(const LLSD& data); - virtual void error(U32 status, const std::string& reason, const LLSD& content); + virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content); private: LLEventPumps& mPumps; diff --git a/indra/llmessage/llstoredmessage.cpp b/indra/llmessage/llstoredmessage.cpp index da6d1c84a8..d6b2f45d04 100644 --- a/indra/llmessage/llstoredmessage.cpp +++ b/indra/llmessage/llstoredmessage.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab diff --git a/indra/llmessage/llstoredmessage.h b/indra/llmessage/llstoredmessage.h index 6a27698b03..359e4c5aea 100644 --- a/indra/llmessage/llstoredmessage.h +++ b/indra/llmessage/llstoredmessage.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2009&license=viewergpl$ * - * Copyright (c) 2001-2009, Linden Research, Inc. + * Copyright (c) 2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab diff --git a/indra/llmessage/lltemplatemessagedispatcher.cpp b/indra/llmessage/lltemplatemessagedispatcher.cpp index 3bbf3a058d..ab1beb362b 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.cpp +++ b/indra/llmessage/lltemplatemessagedispatcher.cpp @@ -3,26 +3,27 @@ * @brief LLTemplateMessageDispatcher class * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/lltemplatemessagedispatcher.h b/indra/llmessage/lltemplatemessagedispatcher.h index b1e74f47bb..fa861e4e42 100644 --- a/indra/llmessage/lltemplatemessagedispatcher.h +++ b/indra/llmessage/lltemplatemessagedispatcher.h @@ -3,26 +3,27 @@ * @brief LLTemplateMessageDispatcher class * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/lltemplatemessagereader.cpp b/indra/llmessage/lltemplatemessagereader.cpp index 80ea6ce96b..8c9eb7ed42 100644 --- a/indra/llmessage/lltemplatemessagereader.cpp +++ b/indra/llmessage/lltemplatemessagereader.cpp @@ -531,6 +531,8 @@ void LLTemplateMessageReader::logRanOffEndOfPacket( const LLHost& host, const S3 gMessageSystem->callExceptionFunc(MX_RAN_OFF_END_OF_PACKET); } +static LLFastTimer::DeclareTimer FTM_PROCESS_MESSAGES("Process Messages"); + // decode a given message BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender ) { @@ -714,7 +716,7 @@ BOOL LLTemplateMessageReader::decodeData(const U8* buffer, const LLHost& sender } { - LLFastTimer t(LLFastTimer::FTM_PROCESS_MESSAGES); + LLFastTimer t(FTM_PROCESS_MESSAGES); if( !mCurrentRMessageTemplate->callHandlerFunc(gMessageSystem) ) { llwarns << "Message from " << sender << " with no handler function received: " << mCurrentRMessageTemplate->mName << llendl; diff --git a/indra/llmessage/lltrustedmessageservice.cpp b/indra/llmessage/lltrustedmessageservice.cpp index c1a6c437a7..505ece57b0 100644 --- a/indra/llmessage/lltrustedmessageservice.cpp +++ b/indra/llmessage/lltrustedmessageservice.cpp @@ -3,26 +3,27 @@ * @brief LLTrustedMessageService implementation * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/lltrustedmessageservice.h b/indra/llmessage/lltrustedmessageservice.h index bc824565f1..dc37702471 100644 --- a/indra/llmessage/lltrustedmessageservice.h +++ b/indra/llmessage/lltrustedmessageservice.h @@ -3,26 +3,27 @@ * @brief LLTrustedMessageService class * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/message.cpp b/indra/llmessage/message.cpp index 78af35bf65..e56d818d65 100644 --- a/indra/llmessage/message.cpp +++ b/indra/llmessage/message.cpp @@ -86,6 +86,7 @@ #include "v3math.h" #include "v4math.h" #include "lltransfertargetvfile.h" +#include "llmemtype.h" // Constants //const char* MESSAGE_LOG_FILENAME = "message.log"; @@ -794,6 +795,7 @@ S32 LLMessageSystem::getReceiveBytes() const void LLMessageSystem::processAcks() { + LLMemType mt_pa(LLMemType::MTYPE_MESSAGE_PROCESS_ACKS); F64 mt_sec = getMessageTimeSeconds(); { gTransferManager.updateTransfers(); @@ -4020,6 +4022,7 @@ void LLMessageSystem::setTimeDecodesSpamThreshold( F32 seconds ) // TODO: babbage: move gServicePump in to LLMessageSystem? bool LLMessageSystem::checkAllMessages(S64 frame_count, LLPumpIO* http_pump) { + LLMemType mt_cam(LLMemType::MTYPE_MESSAGE_CHECK_ALL); if(checkMessages(frame_count)) { return true; diff --git a/indra/llmessage/message.h b/indra/llmessage/message.h index 0f3576732d..27482ca1af 100644 --- a/indra/llmessage/message.h +++ b/indra/llmessage/message.h @@ -59,10 +59,10 @@ #include "llhttpclient.h" #include "llhttpnode.h" #include "llpacketack.h" +#include "llsingleton.h" #include "message_prehash.h" #include "llstl.h" #include "llmsgvariabletype.h" -#include "llmsgvariabletype.h" #include "llmessagesenderinterface.h" #include "llstoredmessage.h" diff --git a/indra/llmessage/message_prehash.cpp b/indra/llmessage/message_prehash.cpp index 30af58e430..9e3986f257 100644 --- a/indra/llmessage/message_prehash.cpp +++ b/indra/llmessage/message_prehash.cpp @@ -406,7 +406,7 @@ char* _PREHASH_GlobalX = LLMessageStringTable::getInstance()->getString("GlobalX char* _PREHASH_GlobalY = LLMessageStringTable::getInstance()->getString("GlobalY"); char* _PREHASH_CopyRotates = LLMessageStringTable::getInstance()->getString("CopyRotates"); char* _PREHASH_KickUserAck = LLMessageStringTable::getInstance()->getString("KickUserAck"); -char* _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); +char* _PREHASH_TopPick = LLMessageStringTable::getInstance()->getString("TopPick"); //legacy var need to be deleted -angela char* _PREHASH_SessionID = LLMessageStringTable::getInstance()->getString("SessionID"); char* _PREHASH_GlobalZ = LLMessageStringTable::getInstance()->getString("GlobalZ"); char* _PREHASH_DeclineFriendship = LLMessageStringTable::getInstance()->getString("DeclineFriendship"); diff --git a/indra/llmessage/tests/commtest.h b/indra/llmessage/tests/commtest.h index 7360230451..cf1461ed2b 100644 --- a/indra/llmessage/tests/commtest.h +++ b/indra/llmessage/tests/commtest.h @@ -5,7 +5,30 @@ * @brief * * $LicenseInfo:firstyear=2009&license=viewergpl$ + * * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp index 93653e345e..5dc5932fde 100644 --- a/indra/llmessage/tests/llcurl_stub.cpp +++ b/indra/llmessage/tests/llcurl_stub.cpp @@ -3,16 +3,16 @@ * @brief stub class to allow unit testing * * $LicenseInfo:firstyear=2008&license=viewergpl$ - * - * Copyright (c) 2008, Linden Research, Inc. - * + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of * this source code is governed by the Linden Lab Source Code Disclosure - * Agreement ("Agreement") { } + * Agreement ("Agreement") previously entered between you and Linden * Lab. By accessing, using, copying, modifying or distributing this * software, you acknowledge that you have been informed of your * obligations under the Agreement and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. @@ -34,7 +34,7 @@ void LLCurl::Responder::completed(U32 status, std::basic_string, std::allocator > const&, LLSD const&) { diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp index bde76db08b..250fa100b6 100644 --- a/indra/llmessage/tests/llhttpclientadapter_test.cpp +++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2001-2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp index a6f5659352..d57f17f270 100644 --- a/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp +++ b/indra/llmessage/tests/lltemplatemessagedispatcher_test.cpp @@ -3,26 +3,27 @@ * @brief LLTrustedMessageService unit tests * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/tests/lltesthttpclientadapter.cpp b/indra/llmessage/tests/lltesthttpclientadapter.cpp index 41ce36f345..0cea4b57c2 100644 --- a/indra/llmessage/tests/lltesthttpclientadapter.cpp +++ b/indra/llmessage/tests/lltesthttpclientadapter.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of * this source code is governed by the Linden Lab Source Code Disclosure diff --git a/indra/llmessage/tests/lltesthttpclientadapter.h b/indra/llmessage/tests/lltesthttpclientadapter.h index cd93bcc8c1..6f252e8510 100644 --- a/indra/llmessage/tests/lltesthttpclientadapter.h +++ b/indra/llmessage/tests/lltesthttpclientadapter.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of * this source code is governed by the Linden Lab Source Code Disclosure diff --git a/indra/llmessage/tests/lltestmessagesender.cpp b/indra/llmessage/tests/lltestmessagesender.cpp index 240813a4a3..3d1876ec36 100644 --- a/indra/llmessage/tests/lltestmessagesender.cpp +++ b/indra/llmessage/tests/lltestmessagesender.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of * this source code is governed by the Linden Lab Source Code Disclosure diff --git a/indra/llmessage/tests/lltestmessagesender.h b/indra/llmessage/tests/lltestmessagesender.h index 00641d1913..d3aaee8f69 100644 --- a/indra/llmessage/tests/lltestmessagesender.h +++ b/indra/llmessage/tests/lltestmessagesender.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of * this source code is governed by the Linden Lab Source Code Disclosure diff --git a/indra/llmessage/tests/lltrustedmessageservice_test.cpp b/indra/llmessage/tests/lltrustedmessageservice_test.cpp index 44595391df..0a3da4b467 100644 --- a/indra/llmessage/tests/lltrustedmessageservice_test.cpp +++ b/indra/llmessage/tests/lltrustedmessageservice_test.cpp @@ -3,26 +3,27 @@ * @brief LLTrustedMessageService unit tests * * $LicenseInfo:firstyear=2009&license=viewergpl$ - * - * Copyright (c) 2001-2009, Linden Research, Inc. - * + * + * Copyright (c) 2009, Linden Research, Inc. + * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab * to you under the terms of the GNU General Public License, version 2.0 * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 - * + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception - * + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. - * + * * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, * COMPLETENESS OR PERFORMANCE. diff --git a/indra/llmessage/tests/networkio.h b/indra/llmessage/tests/networkio.h index 11c5cc07fc..0ebe369ea2 100644 --- a/indra/llmessage/tests/networkio.h +++ b/indra/llmessage/tests/networkio.h @@ -5,7 +5,30 @@ * @brief * * $LicenseInfo:firstyear=2009&license=viewergpl$ + * * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ diff --git a/indra/llplugin/CMakeLists.txt b/indra/llplugin/CMakeLists.txt new file mode 100644 index 0000000000..6706775d4f --- /dev/null +++ b/indra/llplugin/CMakeLists.txt @@ -0,0 +1,55 @@ +# -*- cmake -*- + +project(llplugin) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLMath) +include(LLMessage) +include(LLRender) +include(LLXML) +include(LLWindow) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLXML_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ) + +set(llplugin_SOURCE_FILES + llpluginclassmedia.cpp + llplugininstance.cpp + llpluginmessage.cpp + llpluginmessagepipe.cpp + llpluginprocesschild.cpp + llpluginprocessparent.cpp + llpluginsharedmemory.cpp + ) + +set(llplugin_HEADER_FILES + CMakeLists.txt + + llpluginclassmedia.h + llpluginclassmediaowner.h + llplugininstance.h + llpluginmessage.h + llpluginmessageclasses.h + llpluginmessagepipe.h + llpluginprocesschild.h + llpluginprocessparent.h + llpluginsharedmemory.h + ) + +set_source_files_properties(${llplugin_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llplugin_SOURCE_FILES ${llplugin_HEADER_FILES}) + +add_library (llplugin ${llplugin_SOURCE_FILES}) + +add_subdirectory(slplugin) diff --git a/indra/llplugin/llpluginclassmedia.cpp b/indra/llplugin/llpluginclassmedia.cpp new file mode 100644 index 0000000000..54f153d182 --- /dev/null +++ b/indra/llplugin/llpluginclassmedia.cpp @@ -0,0 +1,1042 @@ +/** + * @file llpluginclassmedia.cpp + * @brief LLPluginClassMedia handles a plugin which knows about the "media" message class. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "indra_constants.h" + +#include "llpluginclassmedia.h" +#include "llpluginmessageclasses.h" + +static int LOW_PRIORITY_TEXTURE_SIZE_DEFAULT = 256; + +static int nextPowerOf2( int value ) +{ + int next_power_of_2 = 1; + while ( next_power_of_2 < value ) + { + next_power_of_2 <<= 1; + } + + return next_power_of_2; +} + +LLPluginClassMedia::LLPluginClassMedia(LLPluginClassMediaOwner *owner) +{ + mOwner = owner; + mPlugin = NULL; + reset(); +} + + +LLPluginClassMedia::~LLPluginClassMedia() +{ + reset(); +} + +bool LLPluginClassMedia::init(const std::string &launcher_filename, const std::string &plugin_filename) +{ + LL_DEBUGS("Plugin") << "launcher: " << launcher_filename << LL_ENDL; + LL_DEBUGS("Plugin") << "plugin: " << plugin_filename << LL_ENDL; + + mPlugin = new LLPluginProcessParent(this); + mPlugin->setSleepTime(mSleepTime); + mPlugin->init(launcher_filename, plugin_filename); + + return true; +} + + +void LLPluginClassMedia::reset() +{ + if(mPlugin != NULL) + { + delete mPlugin; + mPlugin = NULL; + } + + mTextureParamsReceived = false; + mRequestedTextureDepth = 0; + mRequestedTextureInternalFormat = 0; + mRequestedTextureFormat = 0; + mRequestedTextureType = 0; + mRequestedTextureSwapBytes = false; + mRequestedTextureCoordsOpenGL = false; + mTextureSharedMemorySize = 0; + mTextureSharedMemoryName.clear(); + mDefaultMediaWidth = 0; + mDefaultMediaHeight = 0; + mNaturalMediaWidth = 0; + mNaturalMediaHeight = 0; + mSetMediaWidth = -1; + mSetMediaHeight = -1; + mRequestedMediaWidth = 0; + mRequestedMediaHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mMediaWidth = 0; + mMediaHeight = 0; + mDirtyRect = LLRect::null; + mAutoScaleMedia = false; + mRequestedVolume = 1.0f; + mPriority = PRIORITY_NORMAL; + mLowPrioritySizeLimit = LOW_PRIORITY_TEXTURE_SIZE_DEFAULT; + mAllowDownsample = false; + mPadding = 0; + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + mSleepTime = 1.0f / 100.0f; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; + mMediaName.clear(); + mMediaDescription.clear(); + + // media_browser class + mNavigateURI.clear(); + mNavigateResultCode = -1; + mNavigateResultString.clear(); + mHistoryBackAvailable = false; + mHistoryForwardAvailable = false; + mStatusText.clear(); + mProgressPercent = 0; + + // media_time class + mCurrentTime = 0.0f; + mDuration = 0.0f; + mCurrentRate = 0.0f; +} + +void LLPluginClassMedia::idle(void) +{ + if(mPlugin) + { + mPlugin->idle(); + } + + if((mMediaWidth == -1) || (!mTextureParamsReceived) || (mPlugin == NULL)) + { + // Can't process a size change at this time + } + else if((mRequestedMediaWidth != mMediaWidth) || (mRequestedMediaHeight != mMediaHeight)) + { + // Calculate the correct size for the media texture + mRequestedTextureHeight = mRequestedMediaHeight; + if(mPadding < 0) + { + // negative values indicate the plugin wants a power of 2 + mRequestedTextureWidth = nextPowerOf2(mRequestedMediaWidth); + } + else + { + mRequestedTextureWidth = mRequestedMediaWidth; + + if(mPadding > 1) + { + // Pad up to a multiple of the specified number of bytes per row + int rowbytes = mRequestedTextureWidth * mRequestedTextureDepth; + int pad = rowbytes % mPadding; + if(pad != 0) + { + rowbytes += mPadding - pad; + } + + if(rowbytes % mRequestedTextureDepth == 0) + { + mRequestedTextureWidth = rowbytes / mRequestedTextureDepth; + } + else + { + LL_WARNS("Plugin") << "Unable to pad texture width, padding size " << mPadding << "is not a multiple of pixel size " << mRequestedTextureDepth << LL_ENDL; + } + } + } + + + // Size change has been requested but not initiated yet. + size_t newsize = mRequestedTextureWidth * mRequestedTextureHeight * mRequestedTextureDepth; + + // Add an extra line for padding, just in case. + newsize += mRequestedTextureWidth * mRequestedTextureDepth; + + if(newsize != mTextureSharedMemorySize) + { + if(!mTextureSharedMemoryName.empty()) + { + // Tell the plugin to remove the old memory segment + mPlugin->removeSharedMemory(mTextureSharedMemoryName); + mTextureSharedMemoryName.clear(); + } + + mTextureSharedMemorySize = newsize; + mTextureSharedMemoryName = mPlugin->addSharedMemory(mTextureSharedMemorySize); + if(!mTextureSharedMemoryName.empty()) + { + void *addr = mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + + // clear texture memory to avoid random screen visual fuzz from uninitialized texture data + memset( addr, 0x00, newsize ); + + // We could do this to force an update, but textureValid() will still be returning false until the first roundtrip to the plugin, + // so it may not be worthwhile. + // mDirtyRect.setOriginAndSize(0, 0, mRequestedMediaWidth, mRequestedMediaHeight); + } + } + + // This is our local indicator that a change is in progress. + mTextureWidth = -1; + mTextureHeight = -1; + mMediaWidth = -1; + mMediaHeight = -1; + + // This invalidates any existing dirty rect. + resetDirty(); + + // Send a size change message to the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change"); + message.setValue("name", mTextureSharedMemoryName); + message.setValueS32("width", mRequestedMediaWidth); + message.setValueS32("height", mRequestedMediaHeight); + message.setValueS32("texture_width", mRequestedTextureWidth); + message.setValueS32("texture_height", mRequestedTextureHeight); + mPlugin->sendMessage(message); // DO NOT just use sendMessage() here -- we want this to jump ahead of the queue. + + LL_DEBUGS("Plugin") << "Sending size_change" << LL_ENDL; + } + } + + if(mPlugin && mPlugin->isRunning()) + { + // Send queued messages + while(!mSendQueue.empty()) + { + LLPluginMessage message = mSendQueue.front(); + mSendQueue.pop(); + mPlugin->sendMessage(message); + } + } +} + +int LLPluginClassMedia::getTextureWidth() const +{ + return nextPowerOf2(mTextureWidth); +} + +int LLPluginClassMedia::getTextureHeight() const +{ + return nextPowerOf2(mTextureHeight); +} + +unsigned char* LLPluginClassMedia::getBitsData() +{ + unsigned char *result = NULL; + if((mPlugin != NULL) && !mTextureSharedMemoryName.empty()) + { + result = (unsigned char*)mPlugin->getSharedMemoryAddress(mTextureSharedMemoryName); + } + return result; +} + +void LLPluginClassMedia::setSize(int width, int height) +{ + mSetMediaWidth = width; + mSetMediaHeight = height; + + setSizeInternal(); +} + +void LLPluginClassMedia::setSizeInternal(void) +{ + if((mSetMediaWidth > 0) && (mSetMediaHeight > 0)) + { + mRequestedMediaWidth = mSetMediaWidth; + mRequestedMediaHeight = mSetMediaHeight; + } + else + { + mRequestedMediaWidth = mDefaultMediaWidth; + mRequestedMediaHeight = mDefaultMediaHeight; + } + + if(mAllowDownsample) + { + switch(mPriority) + { + case PRIORITY_LOW: + // Reduce maximum texture dimension to (or below) mLowPrioritySizeLimit + while((mRequestedMediaWidth > mLowPrioritySizeLimit) || (mRequestedMediaHeight > mLowPrioritySizeLimit)) + { + mRequestedMediaWidth /= 2; + mRequestedMediaHeight /= 2; + } + break; + + default: + // Don't adjust texture size + break; + } + } + + if(mAutoScaleMedia) + { + mRequestedMediaWidth = nextPowerOf2(mRequestedMediaWidth); + mRequestedMediaHeight = nextPowerOf2(mRequestedMediaHeight); + } +} + +void LLPluginClassMedia::setAutoScale(bool auto_scale) +{ + if(auto_scale != mAutoScaleMedia) + { + mAutoScaleMedia = auto_scale; + setSizeInternal(); + } +} + +bool LLPluginClassMedia::textureValid(void) +{ + if( + !mTextureParamsReceived || + mTextureWidth <= 0 || + mTextureHeight <= 0 || + mMediaWidth <= 0 || + mMediaHeight <= 0 || + mRequestedMediaWidth != mMediaWidth || + mRequestedMediaHeight != mMediaHeight || + getBitsData() == NULL + ) + return false; + + return true; +} + +bool LLPluginClassMedia::getDirty(LLRect *dirty_rect) +{ + bool result = !mDirtyRect.isEmpty(); + + if(dirty_rect != NULL) + { + *dirty_rect = mDirtyRect; + } + + return result; +} + +void LLPluginClassMedia::resetDirty(void) +{ + mDirtyRect = LLRect::null; +} + +std::string LLPluginClassMedia::translateModifiers(MASK modifiers) +{ + std::string result; + + + if(modifiers & MASK_CONTROL) + { + result += "control|"; + } + + if(modifiers & MASK_ALT) + { + result += "alt|"; + } + + if(modifiers & MASK_SHIFT) + { + result += "shift|"; + } + + // TODO: should I deal with platform differences here or in callers? + // TODO: how do we deal with the Mac "command" key? +/* + if(modifiers & MASK_SOMETHING) + { + result += "meta|"; + } +*/ + return result; +} + +void LLPluginClassMedia::mouseEvent(EMouseEventType type, int x, int y, MASK modifiers) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "mouse_event"); + std::string temp; + switch(type) + { + case MOUSE_EVENT_DOWN: temp = "down"; break; + case MOUSE_EVENT_UP: temp = "up"; break; + case MOUSE_EVENT_MOVE: temp = "move"; break; + case MOUSE_EVENT_DOUBLE_CLICK: temp = "double_click"; break; + } + message.setValue("event", temp); + + message.setValueS32("x", x); + + // Incoming coordinates are OpenGL-style ((0,0) = lower left), so flip them here if the plugin has requested it. + if(!mRequestedTextureCoordsOpenGL) + { + // TODO: Should I use mMediaHeight or mRequestedMediaHeight here? + y = mMediaHeight - y; + } + message.setValueS32("y", y); + + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::keyEvent(EKeyEventType type, int key_code, MASK modifiers) +{ + bool result = true; + + // FIXME: + // HACK: we don't have an easy way to tell if the plugin is going to handle a particular keycode. + // For now, return false for the ones the webkit plugin won't handle properly. + + switch(key_code) + { + case KEY_BACKSPACE: + case KEY_TAB: + case KEY_RETURN: + case KEY_PAD_RETURN: + case KEY_SHIFT: + case KEY_CONTROL: + case KEY_ALT: + case KEY_CAPSLOCK: + case KEY_ESCAPE: + case KEY_PAGE_UP: + case KEY_PAGE_DOWN: + case KEY_END: + case KEY_HOME: + case KEY_LEFT: + case KEY_UP: + case KEY_RIGHT: + case KEY_DOWN: + case KEY_INSERT: + case KEY_DELETE: + // These will be handled + break; + + default: + // regular ASCII characters will also be handled + if(key_code >= KEY_SPECIAL) + { + // Other "special" codes will not work properly. + result = false; + } + break; + } + + if(result) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "key_event"); + std::string temp; + switch(type) + { + case KEY_EVENT_DOWN: temp = "down"; break; + case KEY_EVENT_UP: temp = "up"; break; + case KEY_EVENT_REPEAT: temp = "repeat"; break; + } + message.setValue("event", temp); + + message.setValueS32("key", key_code); + + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); + } + + return result; +} + +void LLPluginClassMedia::scrollEvent(int x, int y, MASK modifiers) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "scroll_event"); + + message.setValueS32("x", x); + message.setValueS32("y", y); + message.setValue("modifiers", translateModifiers(modifiers)); + + sendMessage(message); +} + +bool LLPluginClassMedia::textInput(const std::string &text) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "text_event"); + + message.setValue("text", text); + + sendMessage(message); + + return true; +} + +void LLPluginClassMedia::loadURI(const std::string &uri) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "load_uri"); + + message.setValue("uri", uri); + + sendMessage(message); +} + +void LLPluginClassMedia::setPriority(EPriority priority) +{ + if(mPriority != priority) + { + mPriority = priority; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "set_priority"); + + std::string priority_string; + switch(priority) + { + case PRIORITY_STOPPED: + priority_string = "stopped"; + mSleepTime = 1.0f; + break; + case PRIORITY_HIDDEN: + priority_string = "hidden"; + mSleepTime = 1.0f; + break; + case PRIORITY_LOW: + priority_string = "low"; + mSleepTime = 1.0f / 50.0f; + break; + case PRIORITY_NORMAL: + priority_string = "normal"; + mSleepTime = 1.0f / 100.0f; + break; + case PRIORITY_HIGH: + priority_string = "high"; + mSleepTime = 1.0f / 100.0f; + break; + } + + message.setValue("priority", priority_string); + + sendMessage(message); + + if(mPlugin) + { + mPlugin->setSleepTime(mSleepTime); + } + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + +void LLPluginClassMedia::setLowPrioritySizeLimit(int size) +{ + if(mLowPrioritySizeLimit != size) + { + mLowPrioritySizeLimit = size; + + // This may affect the calculated size, so recalculate it here. + setSizeInternal(); + } +} + + +void LLPluginClassMedia::cut() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_cut"); + sendMessage(message); +} + +void LLPluginClassMedia::copy() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_copy"); + sendMessage(message); +} + +void LLPluginClassMedia::paste() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_paste"); + sendMessage(message); +} + +/* virtual */ +void LLPluginClassMedia::receivePluginMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + + if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + std::string message_name = message.getName(); + if(message_name == "texture_params") + { + mRequestedTextureDepth = message.getValueS32("depth"); + mRequestedTextureInternalFormat = message.getValueU32("internalformat"); + mRequestedTextureFormat = message.getValueU32("format"); + mRequestedTextureType = message.getValueU32("type"); + mRequestedTextureSwapBytes = message.getValueBoolean("swap_bytes"); + mRequestedTextureCoordsOpenGL = message.getValueBoolean("coords_opengl"); + + // These two are optional, and will default to 0 if they're not specified. + mDefaultMediaWidth = message.getValueS32("default_width"); + mDefaultMediaHeight = message.getValueS32("default_height"); + + mAllowDownsample = message.getValueBoolean("allow_downsample"); + mPadding = message.getValueS32("padding"); + + setSizeInternal(); + + mTextureParamsReceived = true; + } + else if(message_name == "updated") + { + if(message.hasValue("left")) + { + LLRect newDirtyRect; + newDirtyRect.mLeft = message.getValueS32("left"); + newDirtyRect.mTop = message.getValueS32("top"); + newDirtyRect.mRight = message.getValueS32("right"); + newDirtyRect.mBottom = message.getValueS32("bottom"); + + // The plugin is likely to have top and bottom switched, due to vertical flip and OpenGL coordinate confusion. + // If they're backwards, swap them. + if(newDirtyRect.mTop < newDirtyRect.mBottom) + { + S32 temp = newDirtyRect.mTop; + newDirtyRect.mTop = newDirtyRect.mBottom; + newDirtyRect.mBottom = temp; + } + + if(mDirtyRect.isEmpty()) + { + mDirtyRect = newDirtyRect; + } + else + { + mDirtyRect.unionWith(newDirtyRect); + } + + LL_DEBUGS("Plugin") << "adjusted incoming rect is: (" + << newDirtyRect.mLeft << ", " + << newDirtyRect.mTop << ", " + << newDirtyRect.mRight << ", " + << newDirtyRect.mBottom << "), new dirty rect is: (" + << mDirtyRect.mLeft << ", " + << mDirtyRect.mTop << ", " + << mDirtyRect.mRight << ", " + << mDirtyRect.mBottom << ")" + << LL_ENDL; + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CONTENT_UPDATED); + } + + + bool time_duration_updated = false; + + if(message.hasValue("current_time")) + { + mCurrentTime = message.getValueReal("current_time"); + time_duration_updated = true; + } + if(message.hasValue("duration")) + { + mDuration = message.getValueReal("duration"); + time_duration_updated = true; + } + + if(message.hasValue("current_rate")) + { + mCurrentRate = message.getValueReal("current_rate"); + } + + if(time_duration_updated) + { + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_TIME_DURATION_UPDATED); + } + + } + else if(message_name == "media_status") + { + std::string status = message.getValue("status"); + + LL_DEBUGS("Plugin") << "Status changed to: " << status << LL_ENDL; + + if(status == "loading") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADING; + } + else if(status == "loaded") + { + mStatus = LLPluginClassMediaOwner::MEDIA_LOADED; + } + else if(status == "error") + { + mStatus = LLPluginClassMediaOwner::MEDIA_ERROR; + } + else if(status == "playing") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PLAYING; + } + else if(status == "paused") + { + mStatus = LLPluginClassMediaOwner::MEDIA_PAUSED; + } + else + { + // empty string or any unknown string + mStatus = LLPluginClassMediaOwner::MEDIA_NONE; + } + } + else if(message_name == "size_change_request") + { + S32 width = message.getValueS32("width"); + S32 height = message.getValueS32("height"); + std::string name = message.getValue("name"); + + // TODO: check that name matches? + mNaturalMediaWidth = width; + mNaturalMediaHeight = height; + + setSize(width, height); + } + else if(message_name == "size_change_response") + { + std::string name = message.getValue("name"); + + // TODO: check that name matches? + + mTextureWidth = message.getValueS32("texture_width"); + mTextureHeight = message.getValueS32("texture_height"); + mMediaWidth = message.getValueS32("width"); + mMediaHeight = message.getValueS32("height"); + + // This invalidates any existing dirty rect. + resetDirty(); + + // TODO: should we verify that the plugin sent back the right values? + // Two size changes in a row may cause them to not match, due to queueing, etc. + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_SIZE_CHANGED); + } + else if(message_name == "cursor_changed") + { + mCursorName = message.getValue("name"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CURSOR_CHANGED); + } + else if(message_name == "edit_state") + { + if(message.hasValue("cut")) + { + mCanCut = message.getValueBoolean("cut"); + } + if(message.hasValue("copy")) + { + mCanCopy = message.getValueBoolean("copy"); + } + if(message.hasValue("paste")) + { + mCanPaste = message.getValueBoolean("paste"); + } + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + std::string message_name = message.getName(); + if(message_name == "navigate_begin") + { + mNavigateURI = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_BEGIN); + } + else if(message_name == "navigate_complete") + { + mNavigateURI = message.getValue("uri"); + mNavigateResultCode = message.getValueS32("result_code"); + mNavigateResultString = message.getValue("result_string"); + mHistoryBackAvailable = message.getValueBoolean("history_back_available"); + mHistoryForwardAvailable = message.getValueBoolean("history_forward_available"); + + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_NAVIGATE_COMPLETE); + } + else if(message_name == "progress") + { + mProgressPercent = message.getValueS32("percent"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PROGRESS_UPDATED); + } + else if(message_name == "status_text") + { + mStatusText = message.getValue("status"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_STATUS_TEXT_CHANGED); + } + else if(message_name == "location_changed") + { + mLocation = message.getValue("uri"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_LOCATION_CHANGED); + } + else if(message_name == "click_href") + { + mClickURL = message.getValue("uri"); + mClickTarget = message.getValue("target"); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_HREF); + } + else if(message_name == "click_nofollow") + { + mClickURL = message.getValue("uri"); + mClickTarget.clear(); + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_CLICK_LINK_NOFOLLOW); + } + else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + std::string message_name = message.getName(); + + // This class hasn't defined any incoming messages yet. +// if(message_name == "message_name") +// { +// } +// else + { + LL_WARNS("Plugin") << "Unknown " << message_name << " class message: " << message_name << LL_ENDL; + } + } + +} + +/* virtual */ +void LLPluginClassMedia::pluginDied() +{ + mediaEvent(LLPluginClassMediaOwner::MEDIA_EVENT_PLUGIN_FAILED); +} + +void LLPluginClassMedia::mediaEvent(LLPluginClassMediaOwner::EMediaEvent event) +{ + if(mOwner) + { + mOwner->handleMediaEvent(this, event); + } +} + +void LLPluginClassMedia::sendMessage(const LLPluginMessage &message) +{ + if(mPlugin && mPlugin->isRunning()) + { + mPlugin->sendMessage(message); + } + else + { + // The plugin isn't set up yet -- queue this message to be sent after initialization. + mSendQueue.push(message); + } +} + +//////////////////////////////////////////////////////////// +// MARK: media_browser class functions +bool LLPluginClassMedia::pluginSupportsMediaBrowser(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER); + return !version.empty(); +} + +void LLPluginClassMedia::focus(bool focused) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "focus"); + + message.setValueBoolean("focused", focused); + + sendMessage(message); +} + +void LLPluginClassMedia::clear_cache() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cache"); + sendMessage(message); +} + +void LLPluginClassMedia::clear_cookies() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "clear_cookies"); + sendMessage(message); +} + +void LLPluginClassMedia::enable_cookies(bool enable) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "enable_cookies"); + sendMessage(message); +} + +void LLPluginClassMedia::proxy_setup(bool enable, const std::string &host, int port) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "proxy_setup"); + + message.setValueBoolean("enable", enable); + message.setValue("host", host); + message.setValueS32("port", port); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_stop"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_reload(bool ignore_cache) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_reload"); + + message.setValueBoolean("ignore_cache", ignore_cache); + + sendMessage(message); +} + +void LLPluginClassMedia::browse_forward() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_forward"); + sendMessage(message); +} + +void LLPluginClassMedia::browse_back() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "browse_back"); + sendMessage(message); +} + +void LLPluginClassMedia::set_status_redirect(int code, const std::string &url) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_status_redirect"); + + message.setValueS32("code", code); + message.setValue("url", url); + + sendMessage(message); +} + +void LLPluginClassMedia::setBrowserUserAgent(const std::string& user_agent) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "set_user_agent"); + + message.setValue("user_agent", user_agent); + + sendMessage(message); +} + +void LLPluginClassMedia::crashPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "crash"); + + sendMessage(message); +} + +void LLPluginClassMedia::hangPlugin() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hang"); + + sendMessage(message); +} + + +//////////////////////////////////////////////////////////// +// MARK: media_time class functions +bool LLPluginClassMedia::pluginSupportsMediaTime(void) +{ + std::string version = mPlugin->getMessageClassVersion(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME); + return !version.empty(); +} + +void LLPluginClassMedia::stop() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "stop"); + sendMessage(message); +} + +void LLPluginClassMedia::start(float rate) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "start"); + + message.setValueReal("rate", rate); + + sendMessage(message); +} + +void LLPluginClassMedia::pause() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "pause"); + sendMessage(message); +} + +void LLPluginClassMedia::seek(float time) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "seek"); + + message.setValueReal("time", time); + + sendMessage(message); +} + +void LLPluginClassMedia::setLoop(bool loop) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_loop"); + + message.setValueBoolean("loop", loop); + + sendMessage(message); +} + +void LLPluginClassMedia::setVolume(float volume) +{ + if(volume != mRequestedVolume) + { + mRequestedVolume = volume; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME, "set_volume"); + + message.setValueReal("volume", volume); + + sendMessage(message); + } +} + +void LLPluginClassMedia::initializeUrlHistory(const LLSD& url_history) +{ + // Send URL history to plugin + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "init_history"); + message.setValueLLSD("history", url_history); + sendMessage(message); + + LL_DEBUGS("Plugin") << "Sending history" << LL_ENDL; +} + diff --git a/indra/llplugin/llpluginclassmedia.h b/indra/llplugin/llpluginclassmedia.h new file mode 100644 index 0000000000..7a8586fe2f --- /dev/null +++ b/indra/llplugin/llpluginclassmedia.h @@ -0,0 +1,333 @@ +/** + * @file llpluginclassmedia.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINCLASSMEDIA_H +#define LL_LLPLUGINCLASSMEDIA_H + +#include "llgl.h" +#include "llpluginprocessparent.h" +#include "llrect.h" +#include "llpluginclassmediaowner.h" +#include + + +class LLPluginClassMedia : public LLPluginProcessParentOwner +{ + LOG_CLASS(LLPluginClassMedia); +public: + LLPluginClassMedia(LLPluginClassMediaOwner *owner); + virtual ~LLPluginClassMedia(); + + // local initialization, called by the media manager when creating a source + virtual bool init(const std::string &launcher_filename, const std::string &plugin_filename); + + // undoes everything init() didm called by the media manager when destroying a source + virtual void reset(); + + void idle(void); + + // All of these may return 0 or an actual valid value. + // Callers need to check the return for 0, and not use the values in that case. + int getWidth() const { return (mMediaWidth > 0) ? mMediaWidth : 0; }; + int getHeight() const { return (mMediaHeight > 0) ? mMediaHeight : 0; }; + int getNaturalWidth() const { return mNaturalMediaWidth; }; + int getNaturalHeight() const { return mNaturalMediaHeight; }; + int getSetWidth() const { return mSetMediaWidth; }; + int getSetHeight() const { return mSetMediaHeight; }; + int getBitsWidth() const { return (mTextureWidth > 0) ? mTextureWidth : 0; }; + int getBitsHeight() const { return (mTextureHeight > 0) ? mTextureHeight : 0; }; + int getTextureWidth() const; + int getTextureHeight() const; + + // This may return NULL. Callers need to check for and handle this case. + unsigned char* getBitsData(); + + // gets the format details of the texture data + // These may return 0 if they haven't been set up yet. The caller needs to detect this case. + int getTextureDepth() const { return mRequestedTextureDepth; }; + int getTextureFormatInternal() const { return mRequestedTextureInternalFormat; }; + int getTextureFormatPrimary() const { return mRequestedTextureFormat; }; + int getTextureFormatType() const { return mRequestedTextureType; }; + bool getTextureFormatSwapBytes() const { return mRequestedTextureSwapBytes; }; + bool getTextureCoordsOpenGL() const { return mRequestedTextureCoordsOpenGL; }; + + void setSize(int width, int height); + void setAutoScale(bool auto_scale); + + // Returns true if all of the texture parameters (depth, format, size, and texture size) are set up and consistent. + // This will initially be false, and will also be false for some time after setSize while the resize is processed. + // Note that if this returns true, it is safe to use all the get() functions above without checking for invalid return values + // until you call idle() again. + bool textureValid(void); + + bool getDirty(LLRect *dirty_rect = NULL); + void resetDirty(void); + + typedef enum + { + MOUSE_EVENT_DOWN, + MOUSE_EVENT_UP, + MOUSE_EVENT_MOVE, + MOUSE_EVENT_DOUBLE_CLICK + }EMouseEventType; + + void mouseEvent(EMouseEventType type, int x, int y, MASK modifiers); + + typedef enum + { + KEY_EVENT_DOWN, + KEY_EVENT_UP, + KEY_EVENT_REPEAT + }EKeyEventType; + + bool keyEvent(EKeyEventType type, int key_code, MASK modifiers); + + void scrollEvent(int x, int y, MASK modifiers); + + // Text may be unicode (utf8 encoded) + bool textInput(const std::string &text); + + void loadURI(const std::string &uri); + + // "Loading" means uninitialized or any state prior to fully running (processing commands) + bool isPluginLoading(void) { return mPlugin?mPlugin->isLoading():false; }; + + // "Running" means the steady state -- i.e. processing messages + bool isPluginRunning(void) { return mPlugin?mPlugin->isRunning():false; }; + + // "Exited" means any regular or error state after "Running" (plugin may have crashed or exited normally) + bool isPluginExited(void) { return mPlugin?mPlugin->isDone():false; }; + + std::string getPluginVersion() { return mPlugin?mPlugin->getPluginVersion():std::string(""); }; + + bool getDisableTimeout() { return mPlugin?mPlugin->getDisableTimeout():false; }; + void setDisableTimeout(bool disable) { if(mPlugin) mPlugin->setDisableTimeout(disable); }; + + // Inherited from LLPluginProcessParentOwner + /* virtual */ void receivePluginMessage(const LLPluginMessage &message); + /* virtual */ void pluginDied(); + + + typedef enum + { + PRIORITY_STOPPED, // media is not playing, shouldn't need to update at all. + PRIORITY_HIDDEN, // media is not being displayed or is out of view, don't need to do graphic updates, but may still update audio, playhead, etc. + PRIORITY_LOW, // media is in the far distance, may be rendered at reduced size + PRIORITY_NORMAL, // normal (default) priority + PRIORITY_HIGH // media has user focus and/or is taking up most of the screen + }EPriority; + + void setPriority(EPriority priority); + void setLowPrioritySizeLimit(int size); + + // Valid after a MEDIA_EVENT_CURSOR_CHANGED event + std::string getCursorName() const { return mCursorName; }; + + LLPluginClassMediaOwner::EMediaStatus getStatus() const { return mStatus; } + + void cut(); + bool canCut() const { return mCanCut; }; + + void copy(); + bool canCopy() const { return mCanCopy; }; + + void paste(); + bool canPaste() const { return mCanPaste; }; + + /////////////////////////////////// + // media browser class functions + bool pluginSupportsMediaBrowser(void); + + void focus(bool focused); + void clear_cache(); + void clear_cookies(); + void enable_cookies(bool enable); + void proxy_setup(bool enable, const std::string &host = LLStringUtil::null, int port = 0); + void browse_stop(); + void browse_reload(bool ignore_cache = false); + void browse_forward(); + void browse_back(); + void set_status_redirect(int code, const std::string &url); + void setBrowserUserAgent(const std::string& user_agent); + + // This is valid after MEDIA_EVENT_NAVIGATE_BEGIN or MEDIA_EVENT_NAVIGATE_COMPLETE + std::string getNavigateURI() const { return mNavigateURI; }; + + // These are valid after MEDIA_EVENT_NAVIGATE_COMPLETE + S32 getNavigateResultCode() const { return mNavigateResultCode; }; + std::string getNavigateResultString() const { return mNavigateResultString; }; + bool getHistoryBackAvailable() const { return mHistoryBackAvailable; }; + bool getHistoryForwardAvailable() const { return mHistoryForwardAvailable; }; + + // This is valid after MEDIA_EVENT_PROGRESS_UPDATED + int getProgressPercent() const { return mProgressPercent; }; + + // This is valid after MEDIA_EVENT_STATUS_TEXT_CHANGED + std::string getStatusText() const { return mStatusText; }; + + // This is valid after MEDIA_EVENT_LOCATION_CHANGED + std::string getLocation() const { return mLocation; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF or MEDIA_EVENT_CLICK_LINK_NOFOLLOW + std::string getClickURL() const { return mClickURL; }; + + // This is valid after MEDIA_EVENT_CLICK_LINK_HREF + std::string getClickTarget() const { return mClickTarget; }; + + std::string getMediaName() const { return mMediaName; }; + std::string getMediaDescription() const { return mMediaDescription; }; + + // Crash the plugin. If you use this outside of a testbed, you will be punished. + void crashPlugin(); + + // Hang the plugin. If you use this outside of a testbed, you will be punished. + void hangPlugin(); + + /////////////////////////////////// + // media time class functions + bool pluginSupportsMediaTime(void); + void stop(); + void start(float rate = 0.0f); + void pause(); + void seek(float time); + void setLoop(bool loop); + void setVolume(float volume); + + F64 getCurrentTime(void) const { return mCurrentTime; }; + F64 getDuration(void) const { return mDuration; }; + F64 getCurrentPlayRate(void) { return mCurrentRate; }; + + // Initialize the URL history of the plugin by sending + // "init_history" message + void initializeUrlHistory(const LLSD& url_history); + +protected: + LLPluginClassMediaOwner *mOwner; + + // Notify this object's owner that an event has occurred. + void mediaEvent(LLPluginClassMediaOwner::EMediaEvent event); + + void sendMessage(const LLPluginMessage &message); // Send message internally, either queueing or sending directly. + std::queue mSendQueue; // Used to queue messages while the plugin initializes. + + void setSizeInternal(void); + + bool mTextureParamsReceived; // the mRequestedTexture* fields are only valid when this is true + S32 mRequestedTextureDepth; + LLGLenum mRequestedTextureInternalFormat; + LLGLenum mRequestedTextureFormat; + LLGLenum mRequestedTextureType; + bool mRequestedTextureSwapBytes; + bool mRequestedTextureCoordsOpenGL; + + std::string mTextureSharedMemoryName; + size_t mTextureSharedMemorySize; + + // True to scale requested media up to the full size of the texture (i.e. next power of two) + bool mAutoScaleMedia; + + // default media size for the plugin, from the texture_params message. + int mDefaultMediaWidth; + int mDefaultMediaHeight; + + // Size that has been requested by the plugin itself + int mNaturalMediaWidth; + int mNaturalMediaHeight; + + // Size that has been requested with setSize() + int mSetMediaWidth; + int mSetMediaHeight; + + // Actual media size being set (may be affected by auto-scale) + int mRequestedMediaWidth; + int mRequestedMediaHeight; + + // Texture size calculated from actual media size + int mRequestedTextureWidth; + int mRequestedTextureHeight; + + // Size that the plugin has acknowledged + int mTextureWidth; + int mTextureHeight; + int mMediaWidth; + int mMediaHeight; + + float mRequestedVolume; + + // Priority of this media stream + EPriority mPriority; + int mLowPrioritySizeLimit; + + bool mAllowDownsample; + int mPadding; + + + LLPluginProcessParent *mPlugin; + + LLRect mDirtyRect; + + std::string translateModifiers(MASK modifiers); + + std::string mCursorName; + + LLPluginClassMediaOwner::EMediaStatus mStatus; + + F64 mSleepTime; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + std::string mMediaName; + std::string mMediaDescription; + + ///////////////////////////////////////// + // media_browser class + std::string mNavigateURI; + S32 mNavigateResultCode; + std::string mNavigateResultString; + bool mHistoryBackAvailable; + bool mHistoryForwardAvailable; + std::string mStatusText; + int mProgressPercent; + std::string mLocation; + std::string mClickURL; + std::string mClickTarget; + + ///////////////////////////////////////// + // media_time class + F64 mCurrentTime; + F64 mDuration; + F64 mCurrentRate; + +}; + +#endif // LL_LLPLUGINCLASSMEDIA_H diff --git a/indra/llplugin/llpluginclassmediaowner.h b/indra/llplugin/llpluginclassmediaowner.h new file mode 100644 index 0000000000..3ae176cbeb --- /dev/null +++ b/indra/llplugin/llpluginclassmediaowner.h @@ -0,0 +1,79 @@ +/** + * @file llpluginclassmediaowner.h + * @brief LLPluginClassMedia handles interaction with a plugin which knows about the "media" message class. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINCLASSMEDIAOWNER_H +#define LL_LLPLUGINCLASSMEDIAOWNER_H + +#include "llgl.h" +#include "llpluginprocessparent.h" +#include "llrect.h" +#include + +class LLPluginClassMedia; + +class LLPluginClassMediaOwner +{ +public: + typedef enum + { + MEDIA_EVENT_CONTENT_UPDATED, // contents/dirty rect have updated + MEDIA_EVENT_TIME_DURATION_UPDATED, // current time and/or duration have updated + MEDIA_EVENT_SIZE_CHANGED, // media size has changed + MEDIA_EVENT_CURSOR_CHANGED, // plugin has requested a cursor change + + MEDIA_EVENT_NAVIGATE_BEGIN, // browser has begun navigation + MEDIA_EVENT_NAVIGATE_COMPLETE, // browser has finished navigation + MEDIA_EVENT_PROGRESS_UPDATED, // browser has updated loading progress + MEDIA_EVENT_STATUS_TEXT_CHANGED, // browser has updated the status text + MEDIA_EVENT_LOCATION_CHANGED, // browser location (URL) has changed (maybe due to internal navagation/frames/etc) + MEDIA_EVENT_CLICK_LINK_HREF, // I'm not entirely sure what the semantics of these two are + MEDIA_EVENT_CLICK_LINK_NOFOLLOW, + + MEDIA_EVENT_PLUGIN_FAILED // The plugin failed to launch or died unexpectedly + + } EMediaEvent; + + typedef enum + { + MEDIA_NONE, // Uninitialized -- no useful state + MEDIA_LOADING, // loading or navigating + MEDIA_LOADED, // navigation/preroll complete + MEDIA_ERROR, // navigation/preroll failed + MEDIA_PLAYING, // playing (only for time-based media) + MEDIA_PAUSED, // paused (only for time-based media) + + } EMediaStatus; + + virtual ~LLPluginClassMediaOwner() {}; + virtual void handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent /*event*/) {}; +}; + +#endif // LL_LLPLUGINCLASSMEDIAOWNER_H diff --git a/indra/llplugin/llplugininstance.cpp b/indra/llplugin/llplugininstance.cpp new file mode 100644 index 0000000000..58fb792d0d --- /dev/null +++ b/indra/llplugin/llplugininstance.cpp @@ -0,0 +1,140 @@ +/** + * @file llplugininstance.cpp + * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llplugininstance.h" + +#include "llapr.h" + +//virtual +LLPluginInstanceMessageListener::~LLPluginInstanceMessageListener() +{ +} + +const char *LLPluginInstance::PLUGIN_INIT_FUNCTION_NAME = "LLPluginInitEntryPoint"; + +LLPluginInstance::LLPluginInstance(LLPluginInstanceMessageListener *owner) : + mDSOHandle(NULL), + mPluginUserData(NULL), + mPluginSendMessageFunction(NULL) +{ + mOwner = owner; +} + +LLPluginInstance::~LLPluginInstance() +{ + if(mDSOHandle != NULL) + { + apr_dso_unload(mDSOHandle); + mDSOHandle = NULL; + } +} + +int LLPluginInstance::load(std::string &plugin_file) +{ + pluginInitFunction init_function = NULL; + + int result = apr_dso_load(&mDSOHandle, + plugin_file.c_str(), + gAPRPoolp); + if(result != APR_SUCCESS) + { + char buf[1024]; + apr_dso_error(mDSOHandle, buf, sizeof(buf)); + + LL_WARNS("Plugin") << "apr_dso_load of " << plugin_file << " failed with error " << result << " , additional info string: " << buf << LL_ENDL; + + } + + if(result == APR_SUCCESS) + { + result = apr_dso_sym((apr_dso_handle_sym_t*)&init_function, + mDSOHandle, + PLUGIN_INIT_FUNCTION_NAME); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "apr_dso_sym failed with error " << result << LL_ENDL; + } + } + + if(result == APR_SUCCESS) + { + result = init_function(staticReceiveMessage, (void*)this, &mPluginSendMessageFunction, &mPluginUserData); + + if(result != APR_SUCCESS) + { + LL_WARNS("Plugin") << "call to init function failed with error " << result << LL_ENDL; + } + } + + return (int)result; +} + +void LLPluginInstance::sendMessage(const std::string &message) +{ + if(mPluginSendMessageFunction) + { + LL_DEBUGS("Plugin") << "sending message to plugin: \"" << message << "\"" << LL_ENDL; + mPluginSendMessageFunction(message.c_str(), &mPluginUserData); + } + else + { + LL_WARNS("Plugin") << "dropping message: \"" << message << "\"" << LL_ENDL; + } +} + +void LLPluginInstance::idle(void) +{ +} + +// static +void LLPluginInstance::staticReceiveMessage(const char *message_string, void **user_data) +{ + // TODO: validate that the user_data argument is still a valid LLPluginInstance pointer + // we could also use a key that's looked up in a map (instead of a direct pointer) for safety, but that's probably overkill + LLPluginInstance *self = (LLPluginInstance*)*user_data; + self->receiveMessage(message_string); +} + +void LLPluginInstance::receiveMessage(const char *message_string) +{ + if(mOwner) + { + LL_DEBUGS("Plugin") << "processing incoming message: \"" << message_string << "\"" << LL_ENDL; + mOwner->receivePluginMessage(message_string); + } + else + { + LL_WARNS("Plugin") << "dropping incoming message: \"" << message_string << "\"" << LL_ENDL; + } +} diff --git a/indra/llplugin/llplugininstance.h b/indra/llplugin/llplugininstance.h new file mode 100644 index 0000000000..ba569df10c --- /dev/null +++ b/indra/llplugin/llplugininstance.h @@ -0,0 +1,88 @@ +/** + * @file llplugininstance.h + * @brief LLPluginInstance handles loading the dynamic library of a plugin and setting up its entry points for message passing. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGININSTANCE_H +#define LL_LLPLUGININSTANCE_H + +#include "llstring.h" +#include "llapr.h" + +#include "apr_dso.h" + +class LLPluginInstanceMessageListener +{ +public: + virtual ~LLPluginInstanceMessageListener(); + virtual void receivePluginMessage(const std::string &message) = 0; +}; + +class LLPluginInstance +{ + LOG_CLASS(LLPluginInstance); +public: + LLPluginInstance(LLPluginInstanceMessageListener *owner); + virtual ~LLPluginInstance(); + + // Load a plugin dll/dylib/so + // Returns 0 if successful, APR error code or error code returned from the plugin's init function on failure. + int load(std::string &plugin_file); + + // Sends a message to the plugin. + void sendMessage(const std::string &message); + + // send_count is the maximum number of message to process from the send queue. If negative, it will drain the queue completely. + // The receive queue is always drained completely. + // Returns the total number of messages processed from both queues. + void idle(void); + + // this is the signature of the "send a message" function. + // message_string is a null-terminated C string + // user_data is the opaque reference that the callee supplied during setup. + typedef void (*sendMessageFunction) (const char *message_string, void **user_data); + + // signature of the plugin init function + typedef int (*pluginInitFunction) (sendMessageFunction host_send_func, void *host_user_data, sendMessageFunction *plugin_send_func, void **plugin_user_data); + + static const char *PLUGIN_INIT_FUNCTION_NAME; + +private: + static void staticReceiveMessage(const char *message_string, void **user_data); + void receiveMessage(const char *message_string); + + apr_dso_handle_t *mDSOHandle; + + void *mPluginUserData; + sendMessageFunction mPluginSendMessageFunction; + + LLPluginInstanceMessageListener *mOwner; +}; + +#endif // LL_LLPLUGININSTANCE_H diff --git a/indra/llplugin/llpluginmessage.cpp b/indra/llplugin/llpluginmessage.cpp new file mode 100644 index 0000000000..bfabc5b7ca --- /dev/null +++ b/indra/llplugin/llpluginmessage.cpp @@ -0,0 +1,249 @@ +/** + * @file llpluginmessage.cpp + * @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpluginmessage.h" +#include "llsdserialize.h" + +LLPluginMessage::LLPluginMessage() +{ +} + +LLPluginMessage::LLPluginMessage(const std::string &message_class, const std::string &message_name) +{ + setMessage(message_class, message_name); +} + + +LLPluginMessage::~LLPluginMessage() +{ +} + +void LLPluginMessage::clear() +{ + mMessage = LLSD::emptyMap(); + mMessage["params"] = LLSD::emptyMap(); +} + +void LLPluginMessage::setMessage(const std::string &message_class, const std::string &message_name) +{ + clear(); + mMessage["class"] = message_class; + mMessage["name"] = message_name; +} + +void LLPluginMessage::setValue(const std::string &key, const std::string &value) +{ + mMessage["params"][key] = value; +} + +void LLPluginMessage::setValueLLSD(const std::string &key, const LLSD &value) +{ + mMessage["params"][key] = value; +} + +void LLPluginMessage::setValueS32(const std::string &key, S32 value) +{ + mMessage["params"][key] = value; +} + +void LLPluginMessage::setValueU32(const std::string &key, U32 value) +{ + std::stringstream temp; + temp << "0x" << std::hex << value; + setValue(key, temp.str()); +} + +void LLPluginMessage::setValueBoolean(const std::string &key, bool value) +{ + mMessage["params"][key] = value; +} + +void LLPluginMessage::setValueReal(const std::string &key, F64 value) +{ + mMessage["params"][key] = value; +} + +std::string LLPluginMessage::getClass(void) const +{ + return mMessage["class"]; +} + +std::string LLPluginMessage::getName(void) const +{ + return mMessage["name"]; +} + +bool LLPluginMessage::hasValue(const std::string &key) const +{ + bool result = false; + + if(mMessage["params"].has(key)) + { + result = true; + } + + return result; +} + +std::string LLPluginMessage::getValue(const std::string &key) const +{ + std::string result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asString(); + } + + return result; +} + +LLSD LLPluginMessage::getValueLLSD(const std::string &key) const +{ + LLSD result; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key]; + } + + return result; +} + +S32 LLPluginMessage::getValueS32(const std::string &key) const +{ + S32 result = 0; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asInteger(); + } + + return result; +} + +U32 LLPluginMessage::getValueU32(const std::string &key) const +{ + U32 result = 0; + + if(mMessage["params"].has(key)) + { + std::string value = mMessage["params"][key].asString(); + + result = (U32)strtoul(value.c_str(), NULL, 16); + } + + return result; +} + +bool LLPluginMessage::getValueBoolean(const std::string &key) const +{ + bool result = false; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asBoolean(); + } + + return result; +} + +F64 LLPluginMessage::getValueReal(const std::string &key) const +{ + F64 result = 0.0f; + + if(mMessage["params"].has(key)) + { + result = mMessage["params"][key].asReal(); + } + + return result; +} + +std::string LLPluginMessage::generate(void) const +{ + std::ostringstream result; + + // Pretty XML may be slightly easier to deal with while debugging... +// LLSDSerialize::toXML(mMessage, result); + LLSDSerialize::toPrettyXML(mMessage, result); + + return result.str(); +} + + +int LLPluginMessage::parse(const std::string &message) +{ + // clear any previous state + clear(); + + std::istringstream input(message); + + S32 parse_result = LLSDSerialize::fromXML(mMessage, input); + + return (int)parse_result; +} + + +LLPluginMessageListener::~LLPluginMessageListener() +{ + // TODO: should listeners have a way to ensure they're removed from dispatcher lists when deleted? +} + + +LLPluginMessageDispatcher::~LLPluginMessageDispatcher() +{ + +} + +void LLPluginMessageDispatcher::addPluginMessageListener(LLPluginMessageListener *listener) +{ + mListeners.insert(listener); +} + +void LLPluginMessageDispatcher::removePluginMessageListener(LLPluginMessageListener *listener) +{ + mListeners.erase(listener); +} + +void LLPluginMessageDispatcher::dispatchPluginMessage(const LLPluginMessage &message) +{ + for (listener_set_t::iterator it = mListeners.begin(); + it != mListeners.end(); + ) + { + LLPluginMessageListener* listener = *it; + listener->receivePluginMessage(message); + // In case something deleted an entry. + it = mListeners.upper_bound(listener); + } +} diff --git a/indra/llplugin/llpluginmessage.h b/indra/llplugin/llpluginmessage.h new file mode 100644 index 0000000000..a17ec4bb98 --- /dev/null +++ b/indra/llplugin/llpluginmessage.h @@ -0,0 +1,123 @@ +/** + * @file llpluginmessage.h + * @brief LLPluginMessage encapsulates the serialization/deserialization of messages passed to and from plugins. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINMESSAGE_H +#define LL_LLPLUGINMESSAGE_H + +#include "llsd.h" + + +class LLPluginMessage +{ + LOG_CLASS(LLPluginMessage); +public: + LLPluginMessage(); + LLPluginMessage(const std::string &message_class, const std::string &message_name); + ~LLPluginMessage(); + + // reset all internal state + void clear(void); + + // Sets the message class and name + // Also has the side-effect of clearing any key/value pairs in the message. + void setMessage(const std::string &message_class, const std::string &message_name); + + // Sets a key/value pair in the message + void setValue(const std::string &key, const std::string &value); + void setValueLLSD(const std::string &key, const LLSD &value); + void setValueS32(const std::string &key, S32 value); + void setValueU32(const std::string &key, U32 value); + void setValueBoolean(const std::string &key, bool value); + void setValueReal(const std::string &key, F64 value); + + std::string getClass(void) const; + std::string getName(void) const; + + // Returns true if the specified key exists in this message (useful for optional parameters) + bool hasValue(const std::string &key) const; + + // get the value of a particular key as a string. If the key doesn't exist in the message, an empty string will be returned. + std::string getValue(const std::string &key) const; + + // get the value of a particular key as LLSD. If the key doesn't exist in the message, a null LLSD will be returned. + LLSD getValueLLSD(const std::string &key) const; + + // get the value of a key as a S32. If the value wasn't set as a S32, behavior is undefined. + S32 getValueS32(const std::string &key) const; + + // get the value of a key as a U32. Since there isn't an LLSD type for this, we use a hexadecimal string instead. + U32 getValueU32(const std::string &key) const; + + // get the value of a key as a Boolean. + bool getValueBoolean(const std::string &key) const; + + // get the value of a key as a float. + F64 getValueReal(const std::string &key) const; + + // Flatten the message into a string + std::string generate(void) const; + + // Parse an incoming message into component parts + // (this clears out all existing state before starting the parse) + // Returns -1 on failure, otherwise returns the number of key/value pairs in the message. + int parse(const std::string &message); + + +private: + + LLSD mMessage; + +}; + +class LLPluginMessageListener +{ +public: + virtual ~LLPluginMessageListener(); + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + +}; + +class LLPluginMessageDispatcher +{ +public: + virtual ~LLPluginMessageDispatcher(); + + void addPluginMessageListener(LLPluginMessageListener *); + void removePluginMessageListener(LLPluginMessageListener *); +protected: + void dispatchPluginMessage(const LLPluginMessage &message); + + typedef std::set listener_set_t; + listener_set_t mListeners; +}; + + +#endif // LL_LLPLUGINMESSAGE_H diff --git a/indra/llplugin/llpluginmessageclasses.h b/indra/llplugin/llpluginmessageclasses.h new file mode 100644 index 0000000000..927fcf2eb2 --- /dev/null +++ b/indra/llplugin/llpluginmessageclasses.h @@ -0,0 +1,56 @@ +/** + * @file llpluginmessageclasses.h + * @brief This file defines the versions of existing message classes for LLPluginMessage. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINMESSAGECLASSES_H +#define LL_LLPLUGINMESSAGECLASSES_H + +// Version strings for each plugin message class. +// Backwards-compatible changes (i.e. changes which only add new messges) should increment the minor version (i.e. "1.0" -> "1.1"). +// Non-backwards-compatible changes (which delete messages or change their semantics) should increment the major version (i.e. "1.1" -> "2.0"). +// Plugins will supply the set of message classes they understand, with version numbers, as part of their init_response message. +// The contents and semantics of the base:init message must NEVER change in a non-backwards-compatible way, as a special case. + +#define LLPLUGIN_MESSAGE_CLASS_INTERNAL "internal" +#define LLPLUGIN_MESSAGE_CLASS_INTERNAL_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_BASE "base" +#define LLPLUGIN_MESSAGE_CLASS_BASE_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA "media" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER "media_browser" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION "1.0" + +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME "media_time" +#define LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION "1.0" + +#endif // LL_LLPLUGINMESSAGECLASSES_H diff --git a/indra/llplugin/llpluginmessagepipe.cpp b/indra/llplugin/llpluginmessagepipe.cpp new file mode 100644 index 0000000000..31ea138912 --- /dev/null +++ b/indra/llplugin/llpluginmessagepipe.cpp @@ -0,0 +1,315 @@ +/** + * @file llpluginmessagepipe.cpp + * @brief Classes that implement connections from the plugin system to pipes/pumps. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpluginmessagepipe.h" +#include "llbufferstream.h" + +#include "llapr.h" + +static const char MESSAGE_DELIMITER = '\0'; + +LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() : + mMessagePipe(NULL), + mSocketError(APR_SUCCESS) +{ +} + +// virtual +LLPluginMessagePipeOwner::~LLPluginMessagePipeOwner() +{ + killMessagePipe(); +} + +// virtual +apr_status_t LLPluginMessagePipeOwner::socketError(apr_status_t error) +{ + mSocketError = error; + return error; +}; + +//virtual +void LLPluginMessagePipeOwner::setMessagePipe(LLPluginMessagePipe *read_pipe) +{ + // Save a reference to this pipe + mMessagePipe = read_pipe; +} + +bool LLPluginMessagePipeOwner::canSendMessage(void) +{ + return (mMessagePipe != NULL); +} + +bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message) +{ + bool result = true; + if(mMessagePipe != NULL) + { + result = mMessagePipe->addMessage(message); + } + else + { + LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL; + result = false; + } + + return result; +} + +void LLPluginMessagePipeOwner::killMessagePipe(void) +{ + if(mMessagePipe != NULL) + { + delete mMessagePipe; + mMessagePipe = NULL; + } +} + +LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket) +{ + mOwner = owner; + mOwner->setMessagePipe(this); + mSocket = socket; +} + +LLPluginMessagePipe::~LLPluginMessagePipe() +{ + if(mOwner != NULL) + { + mOwner->setMessagePipe(NULL); + } +} + +bool LLPluginMessagePipe::addMessage(const std::string &message) +{ + // queue the message for later output + mOutput += message; + mOutput += MESSAGE_DELIMITER; // message separator + + return true; +} + +void LLPluginMessagePipe::clearOwner(void) +{ + // The owner is done with this pipe. The next call to process_impl should send any remaining data and exit. + mOwner = NULL; +} + +void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec) +{ + // We never want to sleep forever, so force negative timeouts to become non-blocking. + + // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html + // blocking/non-blocking with apr sockets is somewhat non-portable. + + if(timeout_usec <= 0) + { + // Make the socket non-blocking + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), 0); + } + else + { + // Make the socket blocking-with-timeout + apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1); + apr_socket_timeout_set(mSocket->getSocket(), timeout_usec); + } +} + +bool LLPluginMessagePipe::pump(F64 timeout) +{ + bool result = true; + + if(mSocket) + { + apr_status_t status; + apr_size_t size; + + if(!mOutput.empty()) + { + // write any outgoing messages + size = (apr_size_t)mOutput.size(); + + setSocketTimeout(0); + +// LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL; + + status = apr_socket_send( + mSocket->getSocket(), + (const char*)mOutput.data(), + &size); + +// LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL; + + if(status == APR_SUCCESS) + { + // success + mOutput = mOutput.substr(size); + } + else if(APR_STATUS_IS_EAGAIN(status)) + { + // Socket buffer is full... + // remove the written part from the buffer and try again later. + mOutput = mOutput.substr(size); + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + } + } + + // FIXME: For some reason, the apr timeout stuff isn't working properly on windows. + // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead. +#if LL_WINDOWS + if(result) + { + if(timeout != 0.0f) + { + ms_sleep((int)(timeout * 1000.0f)); + timeout = 0.0f; + } + } +#endif + + // Check for incoming messages + if(result) + { + char input_buf[1024]; + apr_size_t request_size; + + // Start out by reading one byte, so that any data received will wake us up. + request_size = 1; + + // and use the timeout so we'll sleep if no data is available. + setSocketTimeout((apr_interval_time_t)(timeout * 1000000)); + + while(1) + { + size = request_size; + +// LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL; + + status = apr_socket_recv( + mSocket->getSocket(), + input_buf, + &size); + +// LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL; + + if(size > 0) + mInput.append(input_buf, size); + + if(status == APR_SUCCESS) + { +// llinfos << "success, read " << size << llendl; + + if(size != request_size) + { + // This was a short read, so we're done. + break; + } + } + else if(APR_STATUS_IS_TIMEUP(status)) + { +// llinfos << "TIMEUP, read " << size << llendl; + + // Timeout was hit. Since the initial read is 1 byte, this should never be a partial read. + break; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { +// llinfos << "EAGAIN, read " << size << llendl; + + // We've been doing partial reads, and we're done now. + break; + } + else + { + // some other error + // Treat this as fatal. + ll_apr_warn_status(status); + + if(mOwner) + { + mOwner->socketError(status); + } + result = false; + break; + } + + // Second and subsequent reads should not use the timeout + setSocketTimeout(0); + // and should try to fill the input buffer + request_size = sizeof(input_buf); + } + + processInput(); + } + } + + if(!result) + { + // If we got an error, we're done. + LL_INFOS("Plugin") << "Error from socket, cleaning up." << LL_ENDL; + delete this; + } + + return result; +} + +void LLPluginMessagePipe::processInput(void) +{ + // Look for input delimiter(s) in the input buffer. + int start = 0; + int delim; + while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos) + { + // Let the owner process this message + mOwner->receiveMessageRaw(mInput.substr(start, delim - start)); + + start = delim + 1; + } + + // Remove delivered messages from the input buffer. + if(start != 0) + mInput = mInput.substr(start); + +} + diff --git a/indra/llplugin/llpluginmessagepipe.h b/indra/llplugin/llpluginmessagepipe.h new file mode 100644 index 0000000000..4eb6575bd4 --- /dev/null +++ b/indra/llplugin/llpluginmessagepipe.h @@ -0,0 +1,91 @@ +/** + * @file llpluginmessagepipe.h + * @brief Classes that implement connections from the plugin system to pipes/pumps. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINMESSAGEPIPE_H +#define LL_LLPLUGINMESSAGEPIPE_H + +#include "lliosocket.h" + +class LLPluginMessagePipe; + +// Inherit from this to be able to receive messages from the LLPluginMessagePipe +class LLPluginMessagePipeOwner +{ + LOG_CLASS(LLPluginMessagePipeOwner); +public: + LLPluginMessagePipeOwner(); + virtual ~LLPluginMessagePipeOwner(); + // called with incoming messages + virtual void receiveMessageRaw(const std::string &message) = 0; + // called when the socket has an error + virtual apr_status_t socketError(apr_status_t error); + + // called from LLPluginMessagePipe to manage the connection with LLPluginMessagePipeOwner -- do not use! + virtual void setMessagePipe(LLPluginMessagePipe *message_pipe) ; + +protected: + // returns false if writeMessageRaw() would drop the message + bool canSendMessage(void); + // call this to send a message over the pipe + bool writeMessageRaw(const std::string &message); + // call this to close the pipe + void killMessagePipe(void); + + LLPluginMessagePipe *mMessagePipe; + apr_status_t mSocketError; +}; + +class LLPluginMessagePipe +{ + LOG_CLASS(LLPluginMessagePipe); +public: + LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket); + virtual ~LLPluginMessagePipe(); + + bool addMessage(const std::string &message); + void clearOwner(void); + + bool pump(F64 timeout = 0.0f); + +protected: + void processInput(void); + + // used internally by pump() + void setSocketTimeout(apr_interval_time_t timeout_usec); + + std::string mInput; + std::string mOutput; + + LLPluginMessagePipeOwner *mOwner; + LLSocket::ptr_t mSocket; +}; + +#endif // LL_LLPLUGINMESSAGE_H diff --git a/indra/llplugin/llpluginprocesschild.cpp b/indra/llplugin/llpluginprocesschild.cpp new file mode 100644 index 0000000000..293dea6fe1 --- /dev/null +++ b/indra/llplugin/llpluginprocesschild.cpp @@ -0,0 +1,466 @@ +/** + * @file llpluginprocesschild.cpp + * @brief LLPluginProcessChild handles the child side of the external-process plugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpluginprocesschild.h" +#include "llplugininstance.h" +#include "llpluginmessagepipe.h" +#include "llpluginmessageclasses.h" + +static const F32 HEARTBEAT_SECONDS = 1.0f; + +LLPluginProcessChild::LLPluginProcessChild() +{ + mInstance = NULL; + mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mSleepTime = 1.0f / 100.0f; // default: send idle messages at 100Hz +} + +LLPluginProcessChild::~LLPluginProcessChild() +{ + if(mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + delete mInstance; + mInstance = NULL; + } +} + +void LLPluginProcessChild::killSockets(void) +{ + killMessagePipe(); + mSocket.reset(); +} + +void LLPluginProcessChild::init(U32 launcher_port) +{ + mLauncherHost = LLHost("127.0.0.1", launcher_port); + setState(STATE_INITIALIZED); +} + +void LLPluginProcessChild::idle(void) +{ + bool idle_again; + do + { + if(mSocketError != APR_SUCCESS) + { + LL_INFOS("Plugin") << "message pipe is in error state, moving to STATE_ERROR"<< LL_ENDL; + setState(STATE_ERROR); + } + + if((mState > STATE_INITIALIZED) && (mMessagePipe == NULL)) + { + // The pipe has been closed -- we're done. + // TODO: This could be slightly more subtle, but I'm not sure it needs to be. + LL_INFOS("Plugin") << "message pipe went away, moving to STATE_ERROR"<< LL_ENDL; + setState(STATE_ERROR); + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + + if(mInstance != NULL) + { + // Provide some time to the plugin + mInstance->idle(); + } + + switch(mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + if(mSocket->blockingConnect(mLauncherHost)) + { + // This automatically sets mMessagePipe + new LLPluginMessagePipe(this, mSocket); + + setState(STATE_CONNECTED); + } + else + { + // connect failed + setState(STATE_ERROR); + } + break; + + case STATE_CONNECTED: + sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "hello")); + setState(STATE_PLUGIN_LOADING); + break; + + case STATE_PLUGIN_LOADING: + if(!mPluginFile.empty()) + { + mInstance = new LLPluginInstance(this); + if(mInstance->load(mPluginFile) == 0) + { + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(HEARTBEAT_SECONDS); + setState(STATE_PLUGIN_LOADED); + } + else + { + setState(STATE_ERROR); + } + } + break; + + case STATE_PLUGIN_LOADED: + setState(STATE_PLUGIN_INITIALIZING); + sendMessageToPlugin(LLPluginMessage("base", "init")); + break; + + case STATE_PLUGIN_INITIALIZING: + // waiting for init_response... + break; + + case STATE_RUNNING: + if(mInstance != NULL) + { + // Provide some time to the plugin + LLPluginMessage message("base", "idle"); + message.setValueReal("time", mSleepTime); + sendMessageToPlugin(message); + + mInstance->idle(); + + if(mHeartbeat.checkExpirationAndReset(HEARTBEAT_SECONDS)) + { + // This just proves that we're not stuck down inside the plugin code. + sendMessageToParent(LLPluginMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "heartbeat")); + } + } + // receivePluginMessage will transition to STATE_UNLOADING + break; + + case STATE_UNLOADING: + if(mInstance != NULL) + { + sendMessageToPlugin(LLPluginMessage("base", "cleanup")); + delete mInstance; + mInstance = NULL; + } + setState(STATE_UNLOADED); + break; + + case STATE_UNLOADED: + killSockets(); + setState(STATE_DONE); + break; + + case STATE_ERROR: + // Close the socket to the launcher + killSockets(); + // TODO: Where do we go from here? Just exit()? + setState(STATE_DONE); + break; + + case STATE_DONE: + // just sit here. + break; + } + + } while (idle_again); +} + +void LLPluginProcessChild::sleep(F64 seconds) +{ + if(mMessagePipe) + { + mMessagePipe->pump(seconds); + } + else + { + ms_sleep((int)(seconds * 1000.0f)); + } +} + +void LLPluginProcessChild::pump(void) +{ + if(mMessagePipe) + { + mMessagePipe->pump(0.0f); + } + else + { + // Should we warn here? + } +} + + +bool LLPluginProcessChild::isRunning(void) +{ + bool result = false; + + if(mState == STATE_RUNNING) + result = true; + + return result; +} + +bool LLPluginProcessChild::isDone(void) +{ + bool result = false; + + switch(mState) + { + case STATE_DONE: + result = true; + break; + default: + break; + } + + return result; +} + +void LLPluginProcessChild::sendMessageToPlugin(const LLPluginMessage &message) +{ + std::string buffer = message.generate(); + + LL_DEBUGS("Plugin") << "Sending to plugin: " << buffer << LL_ENDL; + + mInstance->sendMessage(buffer); +} + +void LLPluginProcessChild::sendMessageToParent(const LLPluginMessage &message) +{ + std::string buffer = message.generate(); + + LL_DEBUGS("Plugin") << "Sending to parent: " << buffer << LL_ENDL; + + writeMessageRaw(buffer); +} + +void LLPluginProcessChild::receiveMessageRaw(const std::string &message) +{ + // Incoming message from the TCP Socket + + LL_DEBUGS("Plugin") << "Received from parent: " << message << LL_ENDL; + + bool passMessage = true; + + // FIXME: how should we handle queueing here? + + { + // Decode this message + LLPluginMessage parsed; + parsed.parse(message); + + std::string message_class = parsed.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + passMessage = false; + + std::string message_name = parsed.getName(); + if(message_name == "load_plugin") + { + mPluginFile = parsed.getValue("file"); + } + else if(message_name == "shm_add") + { + std::string name = parsed.getValue("name"); + size_t size = (size_t)parsed.getValueS32("size"); + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // Need to remove the old region first + LL_WARNS("Plugin") << "Adding a duplicate shared memory segment!" << LL_ENDL; + } + else + { + // This is a new region + LLPluginSharedMemory *region = new LLPluginSharedMemory; + if(region->attach(name, size)) + { + mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); + + std::stringstream addr; + addr << region->getMappedAddress(); + + // Send the add notification to the plugin + LLPluginMessage message("base", "shm_added"); + message.setValue("name", name); + message.setValueS32("size", (S32)size); + // shm address is split into 2x32bit values because LLSD doesn't serialize 64bit values and we need to support 64-bit addressing. + void * address = region->getMappedAddress(); + U32 address_lo = (U32)address; + U32 address_hi = (U32)(U64(address) / (U64(1)<<31)); + message.setValueU32("address", address_lo); + message.setValueU32("address_1", address_hi); + sendMessageToPlugin(message); + + // and send the response to the parent + message.setMessage(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add_response"); + message.setValue("name", name); + sendMessageToParent(message); + } + else + { + LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + } + } + + } + else if(message_name == "shm_remove") + { + std::string name = parsed.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // forward the remove request to the plugin -- its response will trigger us to detach the segment. + LLPluginMessage message("base", "shm_remove"); + message.setValue("name", name); + sendMessageToPlugin(message); + } + else + { + LL_WARNS("Plugin") << "shm_remove for unknown memory segment!" << LL_ENDL; + } + } + else if(message_name == "sleep_time") + { + mSleepTime = parsed.getValueReal("time"); + } + else if(message_name == "crash") + { + // Crash the plugin + LL_ERRS("Plugin") << "Plugin crash requested." << LL_ENDL; + } + else if(message_name == "hang") + { + // Hang the plugin + LL_WARNS("Plugin") << "Plugin hang requested." << LL_ENDL; + while(1) + { + // wheeeeeeeee...... + } + } + else + { + LL_WARNS("Plugin") << "Unknown internal message from parent: " << message_name << LL_ENDL; + } + } + } + + if(passMessage && mInstance != NULL) + { + mInstance->sendMessage(message); + } +} + +/* virtual */ +void LLPluginProcessChild::receivePluginMessage(const std::string &message) +{ + LL_DEBUGS("Plugin") << "Received from plugin: " << message << LL_ENDL; + + // Incoming message from the plugin instance + bool passMessage = true; + + // FIXME: how should we handle queueing here? + + // Intercept certain base messages (responses to ones sent by this class) + { + // Decode this message + LLPluginMessage parsed; + parsed.parse(message); + std::string message_class = parsed.getClass(); + if(message_class == "base") + { + std::string message_name = parsed.getName(); + if(message_name == "init_response") + { + // The plugin has finished initializing. + setState(STATE_RUNNING); + + // Don't pass this message up to the parent + passMessage = false; + + LLPluginMessage new_message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin_response"); + LLSD versions = parsed.getValueLLSD("versions"); + new_message.setValueLLSD("versions", versions); + + if(parsed.hasValue("plugin_version")) + { + std::string plugin_version = parsed.getValue("plugin_version"); + new_message.setValueLLSD("plugin_version", plugin_version); + } + + // Let the parent know it's loaded and initialized. + sendMessageToParent(new_message); + } + else if(message_name == "shm_remove_response") + { + // Don't pass this message up to the parent + passMessage = false; + + std::string name = parsed.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + // detach the shared memory region + iter->second->detach(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + + // Finally, send the response to the parent. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove_response"); + message.setValue("name", name); + sendMessageToParent(message); + } + else + { + LL_WARNS("Plugin") << "shm_remove_response for unknown memory segment!" << LL_ENDL; + } + } + } + } + + if(passMessage) + { + writeMessageRaw(message); + } +} + + +void LLPluginProcessChild::setState(EState state) +{ + LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; + mState = state; +}; diff --git a/indra/llplugin/llpluginprocesschild.h b/indra/llplugin/llpluginprocesschild.h new file mode 100644 index 0000000000..f92905e8bd --- /dev/null +++ b/indra/llplugin/llpluginprocesschild.h @@ -0,0 +1,108 @@ +/** + * @file llpluginprocesschild.h + * @brief LLPluginProcessChild handles the child side of the external-process plugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINPROCESSCHILD_H +#define LL_LLPLUGINPROCESSCHILD_H + +#include "llpluginmessage.h" +#include "llpluginmessagepipe.h" +#include "llplugininstance.h" +#include "llhost.h" +#include "llpluginsharedmemory.h" + +class LLPluginInstance; + +class LLPluginProcessChild: public LLPluginMessagePipeOwner, public LLPluginInstanceMessageListener +{ + LOG_CLASS(LLPluginProcessChild); +public: + LLPluginProcessChild(); + ~LLPluginProcessChild(); + + void init(U32 launcher_port); + void idle(void); + void sleep(F64 seconds); + void pump(); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); + + // returns true if the plugin is unloaded or we're in an unrecoverable error state. + bool isDone(void); + + void killSockets(void); + + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessageToPlugin(const LLPluginMessage &message); + void sendMessageToParent(const LLPluginMessage &message); + + // Inherited from LLPluginMessagePipeOwner + /* virtual */ void receiveMessageRaw(const std::string &message); + + // Inherited from LLPluginInstanceMessageListener + /* virtual */ void receivePluginMessage(const std::string &message); + +private: + + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_CONNECTED, // connected back to launcher + STATE_PLUGIN_LOADING, // plugin library needs to be loaded + STATE_PLUGIN_LOADED, // plugin library has been loaded + STATE_PLUGIN_INITIALIZING, // plugin is processing init message + STATE_RUNNING, // steady state (processing messages) + STATE_UNLOADING, // plugin has sent shutdown_response and needs to be unloaded + STATE_UNLOADED, // plugin has been unloaded + STATE_ERROR, // generic bailout state + STATE_DONE // state machine will sit in this state after either error or normal termination. + }; + EState mState; + void setState(EState state); + + LLHost mLauncherHost; + LLSocket::ptr_t mSocket; + + std::string mPluginFile; + + LLPluginInstance *mInstance; + + typedef std::map sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLTimer mHeartbeat; + F64 mSleepTime; + +}; + +#endif // LL_LLPLUGINPROCESSCHILD_H diff --git a/indra/llplugin/llpluginprocessparent.cpp b/indra/llplugin/llpluginprocessparent.cpp new file mode 100644 index 0000000000..f18a117dde --- /dev/null +++ b/indra/llplugin/llpluginprocessparent.cpp @@ -0,0 +1,658 @@ +/** + * @file llpluginprocessparent.cpp + * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpluginprocessparent.h" +#include "llpluginmessagepipe.h" +#include "llpluginmessageclasses.h" + +#include "llapr.h" + +// If we don't receive a heartbeat in this many seconds, we declare the plugin locked up. +static const F32 PLUGIN_LOCKED_UP_SECONDS = 10.0f; + +// Somewhat longer timeout for initial launch. +static const F32 PLUGIN_LAUNCH_SECONDS = 20.0f; + +//virtual +LLPluginProcessParentOwner::~LLPluginProcessParentOwner() +{ + +} + +LLPluginProcessParent::LLPluginProcessParent(LLPluginProcessParentOwner *owner) +{ + mOwner = owner; + mBoundPort = 0; + mState = STATE_UNINITIALIZED; + mDisableTimeout = false; +} + +LLPluginProcessParent::~LLPluginProcessParent() +{ + LL_DEBUGS("Plugin") << "destructor" << LL_ENDL; + + // Destroy any remaining shared memory regions + sharedMemoryRegionsType::iterator iter; + while((iter = mSharedMemoryRegions.begin()) != mSharedMemoryRegions.end()) + { + // destroy the shared memory region + iter->second->destroy(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + + mProcess.kill(); + killSockets(); +} + +void LLPluginProcessParent::killSockets(void) +{ + killMessagePipe(); + mListenSocket.reset(); + mSocket.reset(); +} + +void LLPluginProcessParent::init(const std::string &launcher_filename, const std::string &plugin_filename) +{ + mProcess.setExecutable(launcher_filename); + mPluginFile = plugin_filename; + + setState(STATE_INITIALIZED); +} + +bool LLPluginProcessParent::accept() +{ + bool result = false; + + apr_status_t status = APR_EGENERAL; + apr_socket_t *new_socket = NULL; + + status = apr_socket_accept( + &new_socket, + mListenSocket->getSocket(), + gAPRPoolp); + + + if(status == APR_SUCCESS) + { +// llinfos << "SUCCESS" << llendl; + // Success. Create a message pipe on the new socket + + // we MUST create a new pool for the LLSocket, since it will take ownership of it and delete it in its destructor! + apr_pool_t* new_pool = NULL; + status = apr_pool_create(&new_pool, gAPRPoolp); + + mSocket = LLSocket::create(new_socket, new_pool); + new LLPluginMessagePipe(this, mSocket); + + result = true; + } + else if(APR_STATUS_IS_EAGAIN(status)) + { +// llinfos << "EAGAIN" << llendl; + + // No incoming connections. This is not an error. + status = APR_SUCCESS; + } + else + { +// llinfos << "Error:" << llendl; + ll_apr_warn_status(status); + + // Some other error. + setState(STATE_ERROR); + } + + return result; +} + +void LLPluginProcessParent::idle(void) +{ + bool idle_again; + + do + { + // Give time to network processing + if(mMessagePipe) + { + if(!mMessagePipe->pump()) + { +// LL_WARNS("Plugin") << "Message pipe hit an error state" << LL_ENDL; + setState(STATE_ERROR); + } + } + + if((mSocketError != APR_SUCCESS) && (mState < STATE_ERROR)) + { + // The socket is in an error state -- the plugin is gone. + LL_WARNS("Plugin") << "Socket hit an error state (" << mSocketError << ")" << LL_ENDL; + setState(STATE_ERROR); + } + + // If a state needs to go directly to another state (as a performance enhancement), it can set idle_again to true after calling setState(). + // USE THIS CAREFULLY, since it can starve other code. Specifically make sure there's no way to get into a closed cycle and never return. + // When in doubt, don't do it. + idle_again = false; + switch(mState) + { + case STATE_UNINITIALIZED: + break; + + case STATE_INITIALIZED: + { + + apr_status_t status = APR_SUCCESS; + apr_sockaddr_t* addr = NULL; + mListenSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); + mBoundPort = 0; + + // This code is based on parts of LLSocket::create() in lliosocket.cpp. + + status = apr_sockaddr_info_get( + &addr, + "127.0.0.1", + APR_INET, + 0, // port 0 = ephemeral ("find me a port") + 0, + gAPRPoolp); + + if(ll_apr_warn_status(status)) + { + killSockets(); + setState(STATE_ERROR); + break; + } + + // This allows us to reuse the address on quick down/up. This is unlikely to create problems. + ll_apr_warn_status(apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_REUSEADDR, 1)); + + status = apr_socket_bind(mListenSocket->getSocket(), addr); + if(ll_apr_warn_status(status)) + { + killSockets(); + setState(STATE_ERROR); + break; + } + + // Get the actual port the socket was bound to + { + apr_sockaddr_t* bound_addr = NULL; + if(ll_apr_warn_status(apr_socket_addr_get(&bound_addr, APR_LOCAL, mListenSocket->getSocket()))) + { + killSockets(); + setState(STATE_ERROR); + break; + } + mBoundPort = bound_addr->port; + + if(mBoundPort == 0) + { + LL_WARNS("Plugin") << "Bound port number unknown, bailing out." << LL_ENDL; + + killSockets(); + setState(STATE_ERROR); + break; + } + } + + LL_DEBUGS("Plugin") << "Bound tcp socket to port: " << addr->port << LL_ENDL; + + // Make the listen socket non-blocking + status = apr_socket_opt_set(mListenSocket->getSocket(), APR_SO_NONBLOCK, 1); + if(ll_apr_warn_status(status)) + { + killSockets(); + setState(STATE_ERROR); + break; + } + + apr_socket_timeout_set(mListenSocket->getSocket(), 0); + if(ll_apr_warn_status(status)) + { + killSockets(); + setState(STATE_ERROR); + break; + } + + // If it's a stream based socket, we need to tell the OS + // to keep a queue of incoming connections for ACCEPT. + status = apr_socket_listen( + mListenSocket->getSocket(), + 10); // FIXME: Magic number for queue size + + if(ll_apr_warn_status(status)) + { + killSockets(); + setState(STATE_ERROR); + break; + } + + // If we got here, we're listening. + setState(STATE_LISTENING); + } + break; + + case STATE_LISTENING: + { + // Launch the plugin process. + + // Only argument to the launcher is the port number we're listening on + std::stringstream stream; + stream << mBoundPort; + mProcess.addArgument(stream.str()); + if(mProcess.launch() != 0) + { + setState(STATE_ERROR); + } + else + { + // This will allow us to time out if the process never starts. + mHeartbeat.start(); + mHeartbeat.setTimerExpirySec(PLUGIN_LAUNCH_SECONDS); + setState(STATE_LAUNCHED); + } + } + break; + + case STATE_LAUNCHED: + // waiting for the plugin to connect + if(pluginLockedUpOrQuit()) + { + setState(STATE_ERROR); + } + else + { + // Check for the incoming connection. + if(accept()) + { + // Stop listening on the server port + mListenSocket.reset(); + setState(STATE_CONNECTED); + } + } + break; + + case STATE_CONNECTED: + // waiting for hello message from the plugin + + if(pluginLockedUpOrQuit()) + { + setState(STATE_ERROR); + } + break; + + case STATE_HELLO: + LL_DEBUGS("Plugin") << "received hello message" << llendl; + + // Send the message to load the plugin + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "load_plugin"); + message.setValue("file", mPluginFile); + sendMessage(message); + } + + setState(STATE_LOADING); + break; + + case STATE_LOADING: + // The load_plugin_response message will kick us from here into STATE_RUNNING + if(pluginLockedUpOrQuit()) + { + setState(STATE_ERROR); + } + break; + + case STATE_RUNNING: + if(pluginLockedUpOrQuit()) + { + setState(STATE_ERROR); + } + break; + + case STATE_EXITING: + if(!mProcess.isRunning()) + { + setState(STATE_CLEANUP); + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout in exiting state, bailing out" << llendl; + setState(STATE_ERROR); + } + break; + + case STATE_ERROR: + if(mOwner != NULL) + { + mOwner->pluginDied(); + } + setState(STATE_CLEANUP); + break; + + case STATE_CLEANUP: + mProcess.kill(); + killSockets(); + setState(STATE_DONE); + break; + + + case STATE_DONE: + // just sit here. + break; + + } + + } while (idle_again); +} + +bool LLPluginProcessParent::isLoading(void) +{ + bool result = false; + + if(mState <= STATE_LOADING) + result = true; + + return result; +} + +bool LLPluginProcessParent::isRunning(void) +{ + bool result = false; + + if(mState == STATE_RUNNING) + result = true; + + return result; +} + +bool LLPluginProcessParent::isDone(void) +{ + bool result = false; + + if(mState == STATE_DONE) + result = true; + + return result; +} + +void LLPluginProcessParent::setSleepTime(F64 sleep_time, bool force_send) +{ + if(force_send || (sleep_time != mSleepTime)) + { + // Cache the time locally + mSleepTime = sleep_time; + + if(canSendMessage()) + { + // and send to the plugin. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "sleep_time"); + message.setValueReal("time", mSleepTime); + sendMessage(message); + } + else + { + // Too early to send -- the load_plugin_response message will trigger us to send mSleepTime later. + } + } +} + +void LLPluginProcessParent::sendMessage(const LLPluginMessage &message) +{ + + std::string buffer = message.generate(); + LL_DEBUGS("Plugin") << "Sending: " << buffer << LL_ENDL; + writeMessageRaw(buffer); +} + + +void LLPluginProcessParent::receiveMessageRaw(const std::string &message) +{ + LL_DEBUGS("Plugin") << "Received: " << message << LL_ENDL; + + // FIXME: should this go into a queue instead? + + LLPluginMessage parsed; + if(parsed.parse(message) != -1) + { + receiveMessage(parsed); + } +} + +void LLPluginProcessParent::receiveMessage(const LLPluginMessage &message) +{ + std::string message_class = message.getClass(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_INTERNAL) + { + // internal messages should be handled here + std::string message_name = message.getName(); + if(message_name == "hello") + { + if(mState == STATE_CONNECTED) + { + // Plugin host has launched. Tell it which plugin to load. + setState(STATE_HELLO); + } + else + { + LL_WARNS("Plugin") << "received hello message in wrong state -- bailing out" << LL_ENDL; + setState(STATE_ERROR); + } + + } + else if(message_name == "load_plugin_response") + { + if(mState == STATE_LOADING) + { + // Plugin has been loaded. + + // Check which message classes/versions the plugin supports. + // TODO: check against current versions + // TODO: kill plugin on major mismatches? + mMessageClassVersions = message.getValueLLSD("versions"); + LLSD::map_iterator iter; + for(iter = mMessageClassVersions.beginMap(); iter != mMessageClassVersions.endMap(); iter++) + { + LL_INFOS("Plugin") << "message class: " << iter->first << " -> version: " << iter->second.asString() << LL_ENDL; + } + + mPluginVersionString = message.getValue("plugin_version"); + + // Send initial sleep time + setSleepTime(mSleepTime, true); + + setState(STATE_RUNNING); + } + else + { + LL_WARNS("Plugin") << "received load_plugin_response message in wrong state -- bailing out" << LL_ENDL; + setState(STATE_ERROR); + } + } + else if(message_name == "heartbeat") + { + // this resets our timer. + mHeartbeat.setTimerExpirySec(PLUGIN_LOCKED_UP_SECONDS); + } + else if(message_name == "shm_add_response") + { + // Nothing to do here. + } + else if(message_name == "shm_remove_response") + { + std::string name = message.getValue("name"); + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + + if(iter != mSharedMemoryRegions.end()) + { + // destroy the shared memory region + iter->second->destroy(); + + // and remove it from our map + mSharedMemoryRegions.erase(iter); + } + } + else + { + LL_WARNS("Plugin") << "Unknown internal message from child: " << message_name << LL_ENDL; + } + } + else + { + if(mOwner != NULL) + { + mOwner->receivePluginMessage(message); + } + } +} + +std::string LLPluginProcessParent::addSharedMemory(size_t size) +{ + std::string name; + + LLPluginSharedMemory *region = new LLPluginSharedMemory; + + // This is a new region + if(region->create(size)) + { + name = region->getName(); + + mSharedMemoryRegions.insert(sharedMemoryRegionsType::value_type(name, region)); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_add"); + message.setValue("name", name); + message.setValueS32("size", (S32)size); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Couldn't create a shared memory segment!" << LL_ENDL; + + // Don't leak + delete region; + } + + return name; +} + +void LLPluginProcessParent::removeSharedMemory(const std::string &name) +{ + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + + if(iter != mSharedMemoryRegions.end()) + { + // This segment exists. Send the message to the child to unmap it. The response will cause the parent to unmap our end. + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_INTERNAL, "shm_remove"); + message.setValue("name", name); + sendMessage(message); + } + else + { + LL_WARNS("Plugin") << "Request to remove an unknown shared memory segment." << LL_ENDL; + } +} +size_t LLPluginProcessParent::getSharedMemorySize(const std::string &name) +{ + size_t result = 0; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getSize(); + } + + return result; +} +void *LLPluginProcessParent::getSharedMemoryAddress(const std::string &name) +{ + void *result = NULL; + + sharedMemoryRegionsType::iterator iter = mSharedMemoryRegions.find(name); + if(iter != mSharedMemoryRegions.end()) + { + result = iter->second->getMappedAddress(); + } + + return result; +} + +std::string LLPluginProcessParent::getMessageClassVersion(const std::string &message_class) +{ + std::string result; + + if(mMessageClassVersions.has(message_class)) + { + result = mMessageClassVersions[message_class].asString(); + } + + return result; +} + +std::string LLPluginProcessParent::getPluginVersion(void) +{ + return mPluginVersionString; +} + +void LLPluginProcessParent::setState(EState state) +{ + LL_DEBUGS("Plugin") << "setting state to " << state << LL_ENDL; + mState = state; +}; + +bool LLPluginProcessParent::pluginLockedUpOrQuit() +{ + bool result = false; + + if(!mDisableTimeout) + { + if(!mProcess.isRunning()) + { + LL_WARNS("Plugin") << "child exited" << llendl; + result = true; + } + else if(pluginLockedUp()) + { + LL_WARNS("Plugin") << "timeout" << llendl; + result = true; + } + } + + return result; +} + +bool LLPluginProcessParent::pluginLockedUp() +{ + // If the timer has expired, the plugin has locked up. + return mHeartbeat.hasExpired(); +} + diff --git a/indra/llplugin/llpluginprocessparent.h b/indra/llplugin/llpluginprocessparent.h new file mode 100644 index 0000000000..545eb85c9a --- /dev/null +++ b/indra/llplugin/llpluginprocessparent.h @@ -0,0 +1,147 @@ +/** + * @file llpluginprocessparent.h + * @brief LLPluginProcessParent handles the parent side of the external-process plugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINPROCESSPARENT_H +#define LL_LLPLUGINPROCESSPARENT_H + +#include "llprocesslauncher.h" +#include "llpluginmessage.h" +#include "llpluginmessagepipe.h" +#include "llpluginsharedmemory.h" + +#include "lliosocket.h" + +class LLPluginProcessParentOwner +{ +public: + virtual ~LLPluginProcessParentOwner(); + virtual void receivePluginMessage(const LLPluginMessage &message) = 0; + // This will only be called when the plugin has died unexpectedly + virtual void pluginDied() {}; +}; + +class LLPluginProcessParent : public LLPluginMessagePipeOwner +{ + LOG_CLASS(LLPluginProcessParent); +public: + LLPluginProcessParent(LLPluginProcessParentOwner *owner); + ~LLPluginProcessParent(); + + void init(const std::string &launcher_filename, const std::string &plugin_filename); + void idle(void); + + // returns true if the plugin is on its way to steady state + bool isLoading(void); + + // returns true if the plugin is in the steady state (processing messages) + bool isRunning(void); + + // returns true if the process has exited or we've had a fatal error + bool isDone(void); + + void killSockets(void); + + void setSleepTime(F64 sleep_time, bool force_send = false); + F64 getSleepTime(void) const { return mSleepTime; }; + + void sendMessage(const LLPluginMessage &message); + + void receiveMessage(const LLPluginMessage &message); + + // Inherited from LLPluginMessagePipeOwner + void receiveMessageRaw(const std::string &message); + + // This adds a memory segment shared with the client, generating a name for the segment. The name generated is guaranteed to be unique on the host. + // The caller must call removeSharedMemory first (and wait until getSharedMemorySize returns 0 for the indicated name) before re-adding a segment with the same name. + std::string addSharedMemory(size_t size); + // Negotiates for the removal of a shared memory segment. It is the caller's responsibility to ensure that nothing touches the memory + // after this has been called, since the segment will be unmapped shortly thereafter. + void removeSharedMemory(const std::string &name); + size_t getSharedMemorySize(const std::string &name); + void *getSharedMemoryAddress(const std::string &name); + + // Returns the version string the plugin indicated for the message class, or an empty string if that class wasn't in the list. + std::string getMessageClassVersion(const std::string &message_class); + + std::string getPluginVersion(void); + + bool getDisableTimeout() { return mDisableTimeout; }; + void setDisableTimeout(bool disable) { mDisableTimeout = disable; }; + +private: + + enum EState + { + STATE_UNINITIALIZED, + STATE_INITIALIZED, // init() has been called + STATE_LISTENING, // listening for incoming connection + STATE_LAUNCHED, // process has been launched + STATE_CONNECTED, // process has connected + STATE_HELLO, // first message from the plugin process has been received + STATE_LOADING, // process has been asked to load the plugin + STATE_RUNNING, // + STATE_ERROR, // generic bailout state + STATE_CLEANUP, // clean everything up + STATE_EXITING, // Tried to kill process, waiting for it to exit + STATE_DONE // + + }; + EState mState; + void setState(EState state); + + bool pluginLockedUp(); + bool pluginLockedUpOrQuit(); + + bool accept(); + + LLSocket::ptr_t mListenSocket; + LLSocket::ptr_t mSocket; + U32 mBoundPort; + + LLProcessLauncher mProcess; + + std::string mPluginFile; + + LLPluginProcessParentOwner *mOwner; + + typedef std::map sharedMemoryRegionsType; + sharedMemoryRegionsType mSharedMemoryRegions; + + LLSD mMessageClassVersions; + std::string mPluginVersionString; + + LLTimer mHeartbeat; + F64 mSleepTime; + + bool mDisableTimeout; +}; + +#endif // LL_LLPLUGINPROCESSPARENT_H diff --git a/indra/llplugin/llpluginsharedmemory.cpp b/indra/llplugin/llpluginsharedmemory.cpp new file mode 100644 index 0000000000..ce8b8e3e09 --- /dev/null +++ b/indra/llplugin/llpluginsharedmemory.cpp @@ -0,0 +1,495 @@ +/** + * @file llpluginsharedmemory.cpp + * @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpluginsharedmemory.h" + +// on Mac and Linux, we use the native shm_open/mmap interface by using +// #define USE_SHM_OPEN_SHARED_MEMORY 1 +// in the appropriate sections below. + +// For Windows, use: +// #define USE_WIN32_SHARED_MEMORY 1 + +// If we ever want to fall back to the apr implementation for a platform, use: +// #define USE_APR_SHARED_MEMORY 1 + +#if LL_WINDOWS +// #define USE_APR_SHARED_MEMORY 1 + #define USE_WIN32_SHARED_MEMORY 1 +#elif LL_DARWIN + #define USE_SHM_OPEN_SHARED_MEMORY 1 +#elif LL_LINUX + #define USE_SHM_OPEN_SHARED_MEMORY 1 +#endif + + +// FIXME: This path thing is evil and unacceptable. +#if LL_WINDOWS + #define APR_SHARED_MEMORY_PREFIX_STRING "C:\\LLPlugin_" + // Apparnently using the "Global\\" prefix here only works from administrative accounts under Vista. + // Other options I've seen referenced are "Local\\" and "Session\\". + #define WIN32_SHARED_MEMORY_PREFIX_STRING "Local\\LL_" +#else + // mac and linux + #define APR_SHARED_MEMORY_PREFIX_STRING "/tmp/LLPlugin_" + #define SHM_OPEN_SHARED_MEMORY_PREFIX_STRING "/LL" +#endif + +#if USE_APR_SHARED_MEMORY + #include "llapr.h" + #include "apr_shm.h" +#elif USE_SHM_OPEN_SHARED_MEMORY + #include + #include + #include +#elif USE_WIN32_SHARED_MEMORY +#include +#endif // USE_APR_SHARED_MEMORY + + +int LLPluginSharedMemory::sSegmentNumber = 0; + +std::string LLPluginSharedMemory::createName(void) +{ + std::stringstream newname; + +#if LL_WINDOWS + newname << GetCurrentProcessId(); +#else // LL_WINDOWS + newname << getpid(); +#endif // LL_WINDOWS + + newname << "_" << sSegmentNumber++; + + return newname.str(); +} + +class LLPluginSharedMemoryPlatformImpl +{ +public: + LLPluginSharedMemoryPlatformImpl(); + ~LLPluginSharedMemoryPlatformImpl(); + +#if USE_APR_SHARED_MEMORY + apr_shm_t* mAprSharedMemory; +#elif USE_SHM_OPEN_SHARED_MEMORY + int mSharedMemoryFD; +#elif USE_WIN32_SHARED_MEMORY + HANDLE mMapFile; +#endif + +}; + +LLPluginSharedMemory::LLPluginSharedMemory() +{ + mSize = 0; + mMappedAddress = NULL; + mNeedsDestroy = false; + + mImpl = new LLPluginSharedMemoryPlatformImpl; +} + +LLPluginSharedMemory::~LLPluginSharedMemory() +{ + if(mNeedsDestroy) + destroy(); + else + detach(); + + unlink(); + + delete mImpl; +} + +#if USE_APR_SHARED_MEMORY +// MARK: apr implementation + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mAprSharedMemory = NULL; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ + +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = apr_shm_baseaddr_get(mImpl->mAprSharedMemory); + if(mMappedAddress == NULL) + { + return false; + } + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + // This is a no-op under apr. + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + // This is a no-op under apr. + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + // This is a no-op under apr. + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = APR_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + apr_status_t status = apr_shm_create( &(mImpl->mAprSharedMemory), mSize, mName.c_str(), gAPRPoolp ); + + if(ll_apr_warn_status(status)) + { + return false; + } + + mNeedsDestroy = true; + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_destroy(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + apr_status_t status = apr_shm_attach( &(mImpl->mAprSharedMemory), mName.c_str(), gAPRPoolp ); + + if(ll_apr_warn_status(status)) + { + return false; + } + + return map(); +} + + +bool LLPluginSharedMemory::detach(void) +{ + if(mImpl->mAprSharedMemory) + { + apr_status_t status = apr_shm_detach(mImpl->mAprSharedMemory); + if(ll_apr_warn_status(status)) + { + // TODO: Is this a fatal error? I think not... + } + mImpl->mAprSharedMemory = NULL; + } + + return true; +} + + +#elif USE_SHM_OPEN_SHARED_MEMORY +// MARK: shm_open/mmap implementation + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mSharedMemoryFD = -1; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = ::mmap(NULL, mSize, PROT_READ | PROT_WRITE, MAP_SHARED, mImpl->mSharedMemoryFD, 0); + if(mMappedAddress == NULL) + { + return false; + } + + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + if(mMappedAddress != NULL) + { + LL_DEBUGS("Plugin") << "calling munmap(" << mMappedAddress << ", " << mSize << ")" << LL_ENDL; + if(::munmap(mMappedAddress, mSize) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mMappedAddress = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + if(mImpl->mSharedMemoryFD != -1) + { + LL_DEBUGS("Plugin") << "calling close(" << mImpl->mSharedMemoryFD << ")" << LL_ENDL; + if(::close(mImpl->mSharedMemoryFD) == -1) + { + // TODO: Is this a fatal error? I think not... + } + + mImpl->mSharedMemoryFD = -1; + } + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + if(!mName.empty()) + { + if(::shm_unlink(mName.c_str()) == -1) + { + return false; + } + } + + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = SHM_OPEN_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + // Preemptive unlink, just in case something didn't get cleaned up. + unlink(); + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + mNeedsDestroy = true; + + if(::ftruncate(mImpl->mSharedMemoryFD, mSize) == -1) + { + return false; + } + + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + unmap(); + close(); + + return true; +} + + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + mImpl->mSharedMemoryFD = ::shm_open(mName.c_str(), O_RDWR, S_IRUSR | S_IWUSR); + if(mImpl->mSharedMemoryFD == -1) + { + return false; + } + + // unlink here so the segment will be cleaned up automatically after the last close. + unlink(); + + return map(); +} + +bool LLPluginSharedMemory::detach(void) +{ + unmap(); + close(); + return true; +} + +#elif USE_WIN32_SHARED_MEMORY +// MARK: Win32 CreateFileMapping-based implementation + +// Reference: http://msdn.microsoft.com/en-us/library/aa366551(VS.85).aspx + +LLPluginSharedMemoryPlatformImpl::LLPluginSharedMemoryPlatformImpl() +{ + mMapFile = NULL; +} + +LLPluginSharedMemoryPlatformImpl::~LLPluginSharedMemoryPlatformImpl() +{ + +} + +bool LLPluginSharedMemory::map(void) +{ + mMappedAddress = MapViewOfFile( + mImpl->mMapFile, // handle to map object + FILE_MAP_ALL_ACCESS, // read/write permission + 0, + 0, + mSize); + + if(mMappedAddress == NULL) + { + LL_WARNS("Plugin") << "MapViewOfFile failed: " << GetLastError() << LL_ENDL; + return false; + } + + LL_DEBUGS("Plugin") << "memory mapped at " << mMappedAddress << LL_ENDL; + + return true; +} + +bool LLPluginSharedMemory::unmap(void) +{ + if(mMappedAddress != NULL) + { + UnmapViewOfFile(mMappedAddress); + mMappedAddress = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::close(void) +{ + if(mImpl->mMapFile != NULL) + { + CloseHandle(mImpl->mMapFile); + mImpl->mMapFile = NULL; + } + + return true; +} + +bool LLPluginSharedMemory::unlink(void) +{ + // This is a no-op on Windows. + return true; +} + + +bool LLPluginSharedMemory::create(size_t size) +{ + mName = WIN32_SHARED_MEMORY_PREFIX_STRING; + mName += createName(); + mSize = size; + + mImpl->mMapFile = CreateFileMappingA( + INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // max. object size + mSize, // buffer size + mName.c_str()); // name of mapping object + + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "CreateFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } + + mNeedsDestroy = true; + + return map(); +} + +bool LLPluginSharedMemory::destroy(void) +{ + unmap(); + close(); + return true; +} + +bool LLPluginSharedMemory::attach(const std::string &name, size_t size) +{ + mName = name; + mSize = size; + + mImpl->mMapFile = OpenFileMappingA( + FILE_MAP_ALL_ACCESS, // read/write access + FALSE, // do not inherit the name + mName.c_str()); // name of mapping object + + if(mImpl->mMapFile == NULL) + { + LL_WARNS("Plugin") << "OpenFileMapping failed: " << GetLastError() << LL_ENDL; + return false; + } + + return map(); +} + +bool LLPluginSharedMemory::detach(void) +{ + unmap(); + close(); + return true; +} + + + +#endif diff --git a/indra/llplugin/llpluginsharedmemory.h b/indra/llplugin/llpluginsharedmemory.h new file mode 100644 index 0000000000..a4613b9a54 --- /dev/null +++ b/indra/llplugin/llpluginsharedmemory.h @@ -0,0 +1,79 @@ +/** + * @file llpluginsharedmemory.h + * @brief LLPluginSharedMemory manages a shared memory segment for use by the LLPlugin API. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPLUGINSHAREDMEMORY_H +#define LL_LLPLUGINSHAREDMEMORY_H + +class LLPluginSharedMemoryPlatformImpl; + +class LLPluginSharedMemory +{ + LOG_CLASS(LLPluginSharedMemory); +public: + LLPluginSharedMemory(); + ~LLPluginSharedMemory(); + + // Parent will use create/destroy, child will use attach/detach. + // Message transactions will ensure child attaches after parent creates and detaches before parent destroys. + + // create() implicitly creates a name for the segment which is guaranteed to be unique on the host at the current time. + bool create(size_t size); + bool destroy(void); + + bool attach(const std::string &name, size_t size); + bool detach(void); + + bool isMapped(void) const { return (mMappedAddress != NULL); }; + void *getMappedAddress(void) const { return mMappedAddress; }; + size_t getSize(void) const { return mSize; }; + std::string getName() const { return mName; }; + +private: + bool map(void); + bool unmap(void); + bool close(void); + bool unlink(void); + + std::string mName; + size_t mSize; + void *mMappedAddress; + bool mNeedsDestroy; + + LLPluginSharedMemoryPlatformImpl *mImpl; + + static int sSegmentNumber; + static std::string createName(); + +}; + + + +#endif // LL_LLPLUGINSHAREDMEMORY_H diff --git a/indra/llplugin/slplugin/CMakeLists.txt b/indra/llplugin/slplugin/CMakeLists.txt new file mode 100644 index 0000000000..4a7d670c23 --- /dev/null +++ b/indra/llplugin/slplugin/CMakeLists.txt @@ -0,0 +1,55 @@ +project(SLPlugin) + +include(00-Common) +include(LLCommon) +include(LLPlugin) +include(Linking) +include(PluginAPI) +include(LLMessage) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLMESSAGE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} +) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(CARBON_LIBRARY Carbon) +endif (DARWIN) + + +### SLPlugin + +set(SLPlugin_SOURCE_FILES + slplugin.cpp + ) + +add_executable(SLPlugin + WIN32 + ${SLPlugin_SOURCE_FILES} +) + +target_link_libraries(SLPlugin + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(SLPlugin + ${LLPLUGIN_LIBRARIES} + ${LLMESSAGE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (DARWIN) + # Mac version needs to link against carbon, and also needs an embedded plist (to set LSBackgroundOnly) + target_link_libraries(SLPlugin ${CARBON_LIBRARY}) + set_target_properties( + SLPlugin + PROPERTIES + LINK_FLAGS "-Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_SOURCE_DIR}/slplugin_info.plist" + ) +endif (DARWIN) + diff --git a/indra/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp new file mode 100644 index 0000000000..005e427572 --- /dev/null +++ b/indra/llplugin/slplugin/slplugin.cpp @@ -0,0 +1,243 @@ +/** + * @file slplugin.cpp + * @brief Loader shell for plugins, intended to be launched by the plugin host application, which directly loads a plugin dynamic library. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "linden_common.h" + +#include "llpluginprocesschild.h" +#include "llpluginmessage.h" +#include "llerrorcontrol.h" +#include "llapr.h" +#include "llstring.h" + +#if LL_DARWIN + #include +#endif + +#if LL_DARWIN || LL_LINUX + #include +#endif + +/* + On Mac OS, since we call WaitNextEvent, this process will show up in the dock unless we set the LSBackgroundOnly flag in the Info.plist. + + Normally non-bundled binaries don't have an info.plist file, but it's possible to embed one in the binary by adding this to the linker flags: + + -sectcreate __TEXT __info_plist /path/to/slplugin_info.plist + + which means adding this to the gcc flags: + + -Wl,-sectcreate,__TEXT,__info_plist,/path/to/slplugin_info.plist + +*/ + +#if LL_DARWIN || LL_LINUX +// Signal handlers to make crashes not show an OS dialog... +static void crash_handler(int sig) +{ + // Just exit cleanly. + // TODO: add our own crash reporting + _exit(1); +} +#endif + +#if LL_WINDOWS +#include +//////////////////////////////////////////////////////////////////////////////// +// Our exception handler - will probably just exit and the host application +// will miss the heartbeat and log the error in the usual fashion. +LONG WINAPI myWin32ExceptionHandler( struct _EXCEPTION_POINTERS* exception_infop ) +{ + //std::cerr << "This plugin (" << __FILE__ << ") - "; + //std::cerr << "intercepted an unhandled exception and will exit immediately." << std::endl; + + // TODO: replace exception handler before we exit? + return EXCEPTION_EXECUTE_HANDLER; +} + +//////////////////////////////////////////////////////////////////////////////// +// Hook our exception handler and replace the system one +void initExceptionHandler() +{ + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + + // save old exception handler in case we need to restore it at the end + prev_filter = SetUnhandledExceptionFilter( myWin32ExceptionHandler ); +} + +bool checkExceptionHandler() +{ + bool ok = true; + LPTOP_LEVEL_EXCEPTION_FILTER prev_filter; + prev_filter = SetUnhandledExceptionFilter(myWin32ExceptionHandler); + + if (prev_filter != myWin32ExceptionHandler) + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with " << prev_filter << "!" << LL_ENDL; + ok = false; + } + + if (prev_filter == NULL) + { + ok = FALSE; + if (myWin32ExceptionHandler == NULL) + { + LL_WARNS("AppInit") << "Exception handler uninitialized." << LL_ENDL; + } + else + { + LL_WARNS("AppInit") << "Our exception handler (" << (void *)myWin32ExceptionHandler << ") replaced with NULL!" << LL_ENDL; + } + } + + return ok; +} +#endif + +// If this application on Windows platform is a console application, a console is always +// created which is bad. Making it a Windows "application" via CMake settings but not +// adding any code to explicitly create windows does the right thing. +#if LL_WINDOWS +int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) +#else +int main(int argc, char **argv) +#endif +{ + ll_init_apr(); + + // Set up llerror logging + { + LLError::initForApplication("."); + LLError::setDefaultLevel(LLError::LEVEL_INFO); +// LLError::setTagLevel("Plugin", LLError::LEVEL_DEBUG); +// LLError::logToFile("slplugin.log"); + } + +#if LL_WINDOWS + if( strlen( lpCmdLine ) == 0 ) + { + LL_ERRS("slplugin") << "usage: " << "SLPlugin" << " launcher_port" << LL_ENDL; + }; + + U32 port = 0; + if(!LLStringUtil::convertToU32(lpCmdLine, port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + }; + + // Insert our exception handler into the system so this plugin doesn't + // display a crash message if something bad happens. The host app will + // see the missing heartbeat and log appropriately. + initExceptionHandler(); +#elif LL_DARWIN || LL_LINUX + if(argc < 2) + { + LL_ERRS("slplugin") << "usage: " << argv[0] << " launcher_port" << LL_ENDL; + } + + U32 port = 0; + if(!LLStringUtil::convertToU32(argv[1], port)) + { + LL_ERRS("slplugin") << "port number must be numeric" << LL_ENDL; + } + + // Catch signals that most kinds of crashes will generate, and exit cleanly so the system crash dialog isn't shown. + signal(SIGILL, &crash_handler); // illegal instruction +# if LL_DARWIN + signal(SIGEMT, &crash_handler); // emulate instruction executed +# endif // LL_DARWIN + signal(SIGFPE, &crash_handler); // floating-point exception + signal(SIGBUS, &crash_handler); // bus error + signal(SIGSEGV, &crash_handler); // segmentation violation + signal(SIGSYS, &crash_handler); // non-existent system call invoked +#endif + + LLPluginProcessChild *plugin = new LLPluginProcessChild(); + + plugin->init(port); + + LLTimer timer; + timer.start(); + +#if LL_WINDOWS + checkExceptionHandler(); +#endif + + while(!plugin->isDone()) + { + timer.reset(); + plugin->idle(); +#if LL_DARWIN + { + // Some plugins (webkit at least) will want an event loop. This qualifies. + EventRecord evt; + WaitNextEvent(0, &evt, 0, NULL); + } +#endif + F64 elapsed = timer.getElapsedTimeF64(); + F64 remaining = plugin->getSleepTime() - elapsed; + + if(remaining <= 0.0f) + { + // We've already used our full allotment. +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, not sleeping" << LL_ENDL; + + // Still need to service the network... + plugin->pump(); + } + else + { + +// LL_INFOS("slplugin") << "elapsed = " << elapsed * 1000.0f << " ms, remaining = " << remaining * 1000.0f << " ms, sleeping for " << remaining * 1000.0f << " ms" << LL_ENDL; +// timer.reset(); + + // This also services the network as needed. + plugin->sleep(remaining); + +// LL_INFOS("slplugin") << "slept for "<< timer.getElapsedTimeF64() * 1000.0f << " ms" << LL_ENDL; + } + +#if LL_WINDOWS + // More agressive checking of interfering exception handlers. + // Doesn't appear to be required so far - even for plugins + // that do crash with a single call to the intercept + // exception handler such as QuickTime. + //checkExceptionHandler(); +#endif + } + + delete plugin; + + ll_cleanup_apr(); + + return 0; +} + diff --git a/indra/llplugin/slplugin/slplugin_info.plist b/indra/llplugin/slplugin/slplugin_info.plist new file mode 100644 index 0000000000..b1daf87424 --- /dev/null +++ b/indra/llplugin/slplugin/slplugin_info.plist @@ -0,0 +1,12 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleInfoDictionaryVersion + 6.0 + LSBackgroundOnly + + + diff --git a/indra/llprimitive/llmaterialtable.cpp b/indra/llprimitive/llmaterialtable.cpp index 4c22203eb9..18787c47c5 100644 --- a/indra/llprimitive/llmaterialtable.cpp +++ b/indra/llprimitive/llmaterialtable.cpp @@ -124,6 +124,17 @@ LLMaterialTable::~LLMaterialTable() mMaterialInfoList.clear(); } +void LLMaterialTable::initTableTransNames(std::map namemap) +{ + for (info_list_t::iterator iter = mMaterialInfoList.begin(); + iter != mMaterialInfoList.end(); ++iter) + { + LLMaterialInfo *infop = *iter; + std::string name = infop->mName; + infop->mName = namemap[name]; + } +} + void LLMaterialTable::initBasicTable() { // *TODO: Translate diff --git a/indra/llprimitive/llmaterialtable.h b/indra/llprimitive/llmaterialtable.h index ca9017abd0..2c0b046fa7 100644 --- a/indra/llprimitive/llmaterialtable.h +++ b/indra/llprimitive/llmaterialtable.h @@ -147,6 +147,8 @@ public: void initBasicTable(); + void initTableTransNames(std::map namemap); + BOOL add(U8 mcode, const std::string& name, const LLUUID &uuid); BOOL addCollisionSound(U8 mcode, U8 mcode2, const LLUUID &uuid); BOOL addSlidingSound(U8 mcode, U8 mcode2, const LLUUID &uuid); diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp index 7b755a7d17..2177f5c365 100644 --- a/indra/llprimitive/llprimitive.cpp +++ b/indra/llprimitive/llprimitive.cpp @@ -132,7 +132,7 @@ void LLPrimitive::setVolumeManager( LLVolumeMgr* volume_manager ) { if ( !volume_manager || sVolumeManager ) { - llerrs << "Unable to set LLPrimitive::sVolumeManager to NULL" << llendl; + llerrs << "LLPrimitive::sVolumeManager attempting to be set to NULL or it already has been set." << llendl; } sVolumeManager = volume_manager; } diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h index 01389a0e04..53095cc925 100644 --- a/indra/llprimitive/llprimitive.h +++ b/indra/llprimitive/llprimitive.h @@ -37,7 +37,7 @@ #include "v3math.h" #include "xform.h" #include "message.h" -#include "llmemory.h" +#include "llpointer.h" #include "llvolume.h" #include "lltextureentry.h" #include "llprimtexturelist.h" diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp index b02d4c50bd..1c7de95975 100644 --- a/indra/llprimitive/llprimtexturelist.cpp +++ b/indra/llprimitive/llprimtexturelist.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008-2007, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h index 61285bd1bf..6254878b99 100644 --- a/indra/llprimitive/llprimtexturelist.h +++ b/indra/llprimitive/llprimtexturelist.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008-2007, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llprimitive/tests/llmessagesystem_stub.cpp b/indra/llprimitive/tests/llmessagesystem_stub.cpp new file mode 100644 index 0000000000..62504be3b0 --- /dev/null +++ b/indra/llprimitive/tests/llmessagesystem_stub.cpp @@ -0,0 +1,42 @@ +/** + * @file llmessagesystem_stub.cpp + * @brief stub class to allow unit testing + * + * $LicenseInfo:firstyear=2008&license=internal$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * The following source code is PROPRIETARY AND CONFIDENTIAL. Use of + * this source code is governed by the Linden Lab Source Code Disclosure + * Agreement ("Agreement") { } + * Lab. By accessing, using, copying, modifying or distributing this + * software, you acknowledge that you have been informed of your + * obligations under the Agreement and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" + +char * _PREHASH_TextureEntry; + +S32 LLMessageSystem::getSizeFast(char const*, char const*) const +{ + return 0; +} + +S32 LLMessageSystem::getSizeFast(char const*, int, char const*) const +{ + return 0; +} + +void LLMessageSystem::getBinaryDataFast(char const*, char const*, void*, int, int, int) +{ +} + +void LLMessageSystem::addBinaryDataFast(char const*, void const*, int) +{ +} + diff --git a/indra/llprimitive/tests/llprimitive_test.cpp b/indra/llprimitive/tests/llprimitive_test.cpp new file mode 100644 index 0000000000..1805a9e968 --- /dev/null +++ b/indra/llprimitive/tests/llprimitive_test.cpp @@ -0,0 +1,214 @@ +/** + * @file llprimitive_test.cpp + * @brief llprimitive tests + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * Copyright (c) 2001-2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "../test/lltut.h" + +#include "../llprimitive.h" + +#include "../../llmath/llvolumemgr.h" + +class DummyVolumeMgr : public LLVolumeMgr +{ +public: + DummyVolumeMgr() : LLVolumeMgr(), mVolumeTest(NULL), mCurrDetailTest(0) {} + ~DummyVolumeMgr() + { + } + + + virtual LLVolume *refVolume(const LLVolumeParams &volume_params, const S32 detail) + { + if (mVolumeTest.isNull() || volume_params != mCurrParamsTest || detail != mCurrDetailTest) + { + F32 volume_detail = LLVolumeLODGroup::getVolumeScaleFromDetail(detail); + mVolumeTest = new LLVolume(volume_params, volume_detail, FALSE, FALSE); + mCurrParamsTest = volume_params; + mCurrDetailTest = detail; + return mVolumeTest; + } + else + { + return mVolumeTest; + } + } + + virtual void unrefVolume(LLVolume *volumep) + { + if (mVolumeTest == volumep) + { + mVolumeTest = NULL; + } + } + +private: + LLPointer mVolumeTest; + LLVolumeParams mCurrParamsTest; + S32 mCurrDetailTest; +}; + +class PRIMITIVE_TEST_SETUP +{ +public: + PRIMITIVE_TEST_SETUP() + { + volume_manager_test = new DummyVolumeMgr(); + LLPrimitive::setVolumeManager(volume_manager_test); + } + + ~PRIMITIVE_TEST_SETUP() + { + LLPrimitive::cleanupVolumeManager(); + } + DummyVolumeMgr * volume_manager_test; +}; + +namespace tut +{ + struct llprimitive + { + PRIMITIVE_TEST_SETUP setup_class; + }; + + typedef test_group llprimitive_t; + typedef llprimitive_t::object llprimitive_object_t; + tut::llprimitive_t tut_llprimitive("llprimitive"); + + template<> template<> + void llprimitive_object_t::test<1>() + { + set_test_name("Test LLPrimitive Instantiation"); + LLPrimitive test; + } + + template<> template<> + void llprimitive_object_t::test<2>() + { + set_test_name("Test LLPrimitive PCode setter and getter."); + LLPrimitive test; + ensure_equals(test.getPCode(), 0); + LLPCode code = 1; + test.setPCode(code); + ensure_equals(test.getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<3>() + { + set_test_name("Test llprimitive constructor and initer."); + LLPCode code = 1; + LLPrimitive primitive; + primitive.init_primitive(code); + ensure_equals(primitive.getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<4>() + { + set_test_name("Test Static llprimitive constructor and initer."); + LLPCode code = 1; + LLPrimitive * primitive = LLPrimitive::createPrimitive(code); + ensure(primitive != NULL); + ensure_equals(primitive->getPCode(), code); + } + + template<> template<> + void llprimitive_object_t::test<5>() + { + set_test_name("Test setVolume creation of new unique volume."); + LLPrimitive primitive; + LLVolumeParams params; + + // Make sure volume starts off null + ensure(primitive.getVolume() == NULL); + + // Make sure we have no texture entries before setting the volume + ensure_equals(primitive.getNumTEs(), 0); + + // Test that GEOMETRY has not been flagged as changed. + ensure(!primitive.isChanged(LLXform::GEOMETRY)); + + // Make sure setVolume returns true + ensure(primitive.setVolume(params, 0, true) == TRUE); + LLVolume* new_volume = primitive.getVolume(); + + // make sure new volume was actually created + ensure(new_volume != NULL); + + // Make sure that now that we've set the volume we have texture entries + ensure_not_equals(primitive.getNumTEs(), 0); + + // Make sure that the number of texture entries equals the number of faces in the volume (should be 6) + ensure_equals(new_volume->getNumFaces(), 6); + ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces()); + + // Test that GEOMETRY has been flagged as changed. + ensure(primitive.isChanged(LLXform::GEOMETRY)); + + // Run it twice to make sure it doesn't create a different one if params are the same + ensure(primitive.setVolume(params, 0, true) == FALSE); + ensure(new_volume == primitive.getVolume()); + + // Change the param definition and try setting it again. + params.setRevolutions(4); + ensure(primitive.setVolume(params, 0, true) == TRUE); + + // Ensure that we now have a different volume + ensure(new_volume != primitive.getVolume()); + } + + template<> template<> + void llprimitive_object_t::test<6>() + { + set_test_name("Test setVolume creation of new NOT-unique volume."); + LLPrimitive primitive; + LLVolumeParams params; + + // Make sure volume starts off null + ensure(primitive.getVolume() == NULL); + + // Make sure we have no texture entries before setting the volume + ensure_equals(primitive.getNumTEs(), 0); + + // Test that GEOMETRY has not been flagged as changed. + ensure(!primitive.isChanged(LLXform::GEOMETRY)); + + // Make sure setVolume returns true + ensure(primitive.setVolume(params, 0, false) == TRUE); + + LLVolume* new_volume = primitive.getVolume(); + + // make sure new volume was actually created + ensure(new_volume != NULL); + + // Make sure that now that we've set the volume we have texture entries + ensure_not_equals(primitive.getNumTEs(), 0); + + // Make sure that the number of texture entries equals the number of faces in the volume (should be 6) + ensure_equals(new_volume->getNumFaces(), 6); + ensure_equals(primitive.getNumTEs(), new_volume->getNumFaces()); + + // Test that GEOMETRY has been flagged as changed. + ensure(primitive.isChanged(LLXform::GEOMETRY)); + + // Run it twice to make sure it doesn't create a different one if params are the same + ensure(primitive.setVolume(params, 0, false) == FALSE); + ensure(new_volume == primitive.getVolume()); + + // Change the param definition and try setting it again. + params.setRevolutions(4); + ensure(primitive.setVolume(params, 0, false) == TRUE); + + // Ensure that we now have a different volume + ensure(new_volume != primitive.getVolume()); + } +} + +#include "llmessagesystem_stub.cpp" diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt index 0bb835970f..aac650bec9 100644 --- a/indra/llrender/CMakeLists.txt +++ b/indra/llrender/CMakeLists.txt @@ -26,7 +26,7 @@ include_directories( set(llrender_SOURCE_FILES llcubemap.cpp - llfont.cpp + llfontfreetype.cpp llfontgl.cpp llfontbitmapcache.cpp llfontregistry.cpp @@ -36,6 +36,7 @@ set(llrender_SOURCE_FILES llpostprocess.cpp llrendersphere.cpp llshadermgr.cpp + lltexture.cpp llvertexbuffer.cpp ) @@ -44,7 +45,7 @@ set(llrender_HEADER_FILES llcubemap.h llfontgl.h - llfont.h + llfontfreetype.h llfontbitmapcache.h llfontregistry.h llgl.h @@ -58,6 +59,7 @@ set(llrender_HEADER_FILES llrender.h llrendersphere.h llshadermgr.h + lltexture.h llvertexbuffer.h ) diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index f6321b0534..052510e6ed 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, diff --git a/indra/llrender/llfontbitmapcache.h b/indra/llrender/llfontbitmapcache.h index e5c09f8826..4a57052b91 100644 --- a/indra/llrender/llfontbitmapcache.h +++ b/indra/llrender/llfontbitmapcache.h @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -35,7 +36,7 @@ #include // Maintain a collection of bitmaps containing rendered glyphs. -// Generalizes the single-bitmap logic from LLFont and LLFontGL. +// Generalizes the single-bitmap logic from LLFontFreetype and LLFontGL. class LLFontBitmapCache: public LLRefCount { public: diff --git a/indra/llrender/llfontfreetype.cpp b/indra/llrender/llfontfreetype.cpp new file mode 100644 index 0000000000..0be6bedbee --- /dev/null +++ b/indra/llrender/llfontfreetype.cpp @@ -0,0 +1,644 @@ +/** + * @file llfontfreetype.cpp + * @brief Freetype font library wrapper + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfontfreetype.h" +#include "llfontgl.h" + +// Freetype stuff +#include + +// For some reason, this won't work if it's not wrapped in the ifdef +#ifdef FT_FREETYPE_H +#include FT_FREETYPE_H +#endif + +#include "llerror.h" +#include "llimage.h" +//#include "llimagej2c.h" +#include "llmath.h" // Linden math +#include "llstring.h" +//#include "imdebug.h" +#include "llfontbitmapcache.h" +#include "llgl.h" + +FT_Render_Mode gFontRenderMode = FT_RENDER_MODE_NORMAL; + +LLFontManager *gFontManagerp = NULL; + +FT_Library gFTLibrary = NULL; + +//static +void LLFontManager::initClass() +{ + gFontManagerp = new LLFontManager; +} + +//static +void LLFontManager::cleanupClass() +{ + delete gFontManagerp; + gFontManagerp = NULL; +} + +LLFontManager::LLFontManager() +{ + int error; + error = FT_Init_FreeType(&gFTLibrary); + if (error) + { + // Clean up freetype libs. + llerrs << "Freetype initialization failure!" << llendl; + FT_Done_FreeType(gFTLibrary); + } +} + +LLFontManager::~LLFontManager() +{ + FT_Done_FreeType(gFTLibrary); +} + + +LLFontGlyphInfo::LLFontGlyphInfo(U32 index) +: mGlyphIndex(index), + mXBitmapOffset(0), // Offset to the origin in the bitmap + mYBitmapOffset(0), // Offset to the origin in the bitmap + mXBearing(0), // Distance from baseline to left in pixels + mYBearing(0), // Distance from baseline to top in pixels + mWidth(0), // In pixels + mHeight(0), // In pixels + mXAdvance(0.f), // In pixels + mYAdvance(0.f), // In pixels + mIsRendered(FALSE), + mMetricsValid(FALSE) +{ +} + +LLFontFreetype::LLFontFreetype() +: mFontBitmapCachep(new LLFontBitmapCache), + mValid(FALSE), + mAscender(0.f), + mDescender(0.f), + mLineHeight(0.f), + mIsFallback(FALSE), + mFTFace(NULL), + mRenderGlyphCount(0), + mAddGlyphCount(0), + mPointSize(0) +{ +} + + +LLFontFreetype::~LLFontFreetype() +{ + // Clean up freetype libs. + if (mFTFace) + FT_Done_Face(mFTFace); + mFTFace = NULL; + + // Delete glyph info + std::for_each(mCharGlyphInfoMap.begin(), mCharGlyphInfoMap.end(), DeletePairedPointer()); + + // mFontBitmapCachep will be cleaned up by LLPointer destructor. + // mFallbackFonts cleaned up by LLPointer destructor +} + +BOOL LLFontFreetype::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback) +{ + // Don't leak face objects. This is also needed to deal with + // changed font file names. + if (mFTFace) + { + FT_Done_Face(mFTFace); + mFTFace = NULL; + } + + int error; + + error = FT_New_Face( gFTLibrary, + filename.c_str(), + 0, + &mFTFace ); + + if (error) + { + return FALSE; + } + + mIsFallback = is_fallback; + F32 pixels_per_em = (point_size / 72.f)*vert_dpi; // Size in inches * dpi + + error = FT_Set_Char_Size(mFTFace, /* handle to face object */ + 0, /* char_width in 1/64th of points */ + (S32)(point_size*64), /* char_height in 1/64th of points */ + (U32)horz_dpi, /* horizontal device resolution */ + (U32)vert_dpi); /* vertical device resolution */ + + if (error) + { + // Clean up freetype libs. + FT_Done_Face(mFTFace); + mFTFace = NULL; + return FALSE; + } + + F32 y_max, y_min, x_max, x_min; + F32 ems_per_unit = 1.f/ mFTFace->units_per_EM; + F32 pixels_per_unit = pixels_per_em * ems_per_unit; + + // Get size of bbox in pixels + y_max = mFTFace->bbox.yMax * pixels_per_unit; + y_min = mFTFace->bbox.yMin * pixels_per_unit; + x_max = mFTFace->bbox.xMax * pixels_per_unit; + x_min = mFTFace->bbox.xMin * pixels_per_unit; + mAscender = mFTFace->ascender * pixels_per_unit; + mDescender = -mFTFace->descender * pixels_per_unit; + mLineHeight = mFTFace->height * pixels_per_unit; + + S32 max_char_width = llround(0.5f + (x_max - x_min)); + S32 max_char_height = llround(0.5f + (y_max - y_min)); + + mFontBitmapCachep->init(components, max_char_width, max_char_height); + + if (!mFTFace->charmap) + { + //llinfos << " no unicode encoding, set whatever encoding there is..." << llendl; + FT_Set_Charmap(mFTFace, mFTFace->charmaps[0]); + } + + if (!mIsFallback) + { + // Add the default glyph + addGlyph(0, 0); + } + + mName = filename; + mPointSize = point_size; + + mStyle = LLFontGL::NORMAL; + if(mFTFace->style_flags & FT_STYLE_FLAG_BOLD) + { + mStyle |= LLFontGL::BOLD; + mStyle &= ~LLFontGL::NORMAL; + } + + if(mFTFace->style_flags & FT_STYLE_FLAG_ITALIC) + { + mStyle |= LLFontGL::ITALIC; + mStyle &= ~LLFontGL::NORMAL; + } + + return TRUE; +} + +void LLFontFreetype::setFallbackFonts(const font_vector_t &font) +{ + mFallbackFonts = font; +} + +const LLFontFreetype::font_vector_t &LLFontFreetype::getFallbackFonts() const +{ + return mFallbackFonts; +} + +F32 LLFontFreetype::getLineHeight() const +{ + return mLineHeight; +} + +F32 LLFontFreetype::getAscenderHeight() const +{ + return mAscender; +} + +F32 LLFontFreetype::getDescenderHeight() const +{ + return mDescender; +} + +F32 LLFontFreetype::getXAdvance(llwchar wch) const +{ + if (mFTFace == NULL) + return 0.0; + + //llassert(!mIsFallback); + U32 glyph_index; + + // Return existing info only if it is current + LLFontGlyphInfo* gi = getGlyphInfo(wch); + if (gi && gi->mMetricsValid) + { + return gi->mXAdvance; + } + + const LLFontFreetype* fontp = this; + + // Initialize char to glyph map + glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + font_vector_t::const_iterator iter; + for(iter = mFallbackFonts.begin(); (iter != mFallbackFonts.end()) && (glyph_index == 0); iter++) + { + glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); + if(glyph_index) + { + fontp = *iter; + } + } + } + + if (glyph_index) + { + // This font has this glyph + fontp->renderGlyph(glyph_index); + + // Create the entry if it's not there + char_glyph_info_map_t::iterator iter2 = mCharGlyphInfoMap.find(wch); + if (iter2 == mCharGlyphInfoMap.end()) + { + gi = new LLFontGlyphInfo(glyph_index); + insertGlyphInfo(wch, gi); + } + else + { + gi = iter2->second; + } + + gi->mWidth = fontp->mFTFace->glyph->bitmap.width; + gi->mHeight = fontp->mFTFace->glyph->bitmap.rows; + + // Convert these from 26.6 units to float pixels. + gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; + gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; + gi->mMetricsValid = TRUE; + return gi->mXAdvance; + } + else + { + gi = get_if_there(mCharGlyphInfoMap, (llwchar)0, (LLFontGlyphInfo*)NULL); + if (gi) + { + return gi->mXAdvance; + } + } + + // Last ditch fallback - no glyphs defined at all. + return (F32)mFontBitmapCachep->getMaxCharWidth(); +} + +F32 LLFontFreetype::getXKerning(llwchar char_left, llwchar char_right) const +{ + if (mFTFace == NULL) + return 0.0; + + //llassert(!mIsFallback); + LLFontGlyphInfo* left_glyph_info = get_if_there(mCharGlyphInfoMap, char_left, (LLFontGlyphInfo*)NULL); + U32 left_glyph = left_glyph_info ? left_glyph_info->mGlyphIndex : 0; + // Kern this puppy. + LLFontGlyphInfo* right_glyph_info = get_if_there(mCharGlyphInfoMap, char_right, (LLFontGlyphInfo*)NULL); + U32 right_glyph = right_glyph_info ? right_glyph_info->mGlyphIndex : 0; + + FT_Vector delta; + + llverify(!FT_Get_Kerning(mFTFace, left_glyph, right_glyph, ft_kerning_unfitted, &delta)); + + return delta.x*(1.f/64.f); +} + +BOOL LLFontFreetype::hasGlyph(llwchar wch) const +{ + llassert(!mIsFallback); + const LLFontGlyphInfo* gi = getGlyphInfo(wch); + if (gi && gi->mIsRendered) + { + return TRUE; + } + else + { + return FALSE; + } +} + +BOOL LLFontFreetype::addChar(llwchar wch) const +{ + if (mFTFace == NULL) + return FALSE; + + llassert(!mIsFallback); + //lldebugs << "Adding new glyph for " << wch << " to font" << llendl; + + FT_UInt glyph_index; + + // Initialize char to glyph map + glyph_index = FT_Get_Char_Index(mFTFace, wch); + if (glyph_index == 0) + { + //llinfos << "Trying to add glyph from fallback font!" << llendl + font_vector_t::const_iterator iter; + for(iter = mFallbackFonts.begin(); iter != mFallbackFonts.end(); iter++) + { + glyph_index = FT_Get_Char_Index((*iter)->mFTFace, wch); + if (glyph_index) + { + addGlyphFromFont(*iter, wch, glyph_index); + return TRUE; + } + } + } + + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter == mCharGlyphInfoMap.end() || !(iter->second->mIsRendered)) + { + BOOL result = addGlyph(wch, glyph_index); + return result; + } + return FALSE; +} + +BOOL LLFontFreetype::addGlyph(llwchar wch, U32 glyph_index) const +{ + return addGlyphFromFont(this, wch, glyph_index); +} + +BOOL LLFontFreetype::addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const +{ + if (mFTFace == NULL) + return FALSE; + + llassert(!mIsFallback); + fontp->renderGlyph(glyph_index); + S32 width = fontp->mFTFace->glyph->bitmap.width; + S32 height = fontp->mFTFace->glyph->bitmap.rows; + + S32 pos_x, pos_y; + S32 bitmap_num; + mFontBitmapCachep->nextOpenPos(width, pos_x, pos_y, bitmap_num); + mAddGlyphCount++; + + LLFontGlyphInfo* gi = new LLFontGlyphInfo(glyph_index); + gi->mXBitmapOffset = pos_x; + gi->mYBitmapOffset = pos_y; + gi->mBitmapNum = bitmap_num; + gi->mWidth = width; + gi->mHeight = height; + gi->mXBearing = fontp->mFTFace->glyph->bitmap_left; + gi->mYBearing = fontp->mFTFace->glyph->bitmap_top; + // Convert these from 26.6 units to float pixels. + gi->mXAdvance = fontp->mFTFace->glyph->advance.x / 64.f; + gi->mYAdvance = fontp->mFTFace->glyph->advance.y / 64.f; + gi->mIsRendered = TRUE; + gi->mMetricsValid = TRUE; + + insertGlyphInfo(wch, gi); + + llassert(fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY); + + if (fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO + || fontp->mFTFace->glyph->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) + { + U8 *buffer_data = fontp->mFTFace->glyph->bitmap.buffer; + S32 buffer_row_stride = fontp->mFTFace->glyph->bitmap.pitch; + U8 *tmp_graydata = NULL; + + if (fontp->mFTFace->glyph->bitmap.pixel_mode + == FT_PIXEL_MODE_MONO) + { + // need to expand 1-bit bitmap to 8-bit graymap. + tmp_graydata = new U8[width * height]; + S32 xpos, ypos; + for (ypos = 0; ypos < height; ++ypos) + { + S32 bm_row_offset = buffer_row_stride * ypos; + for (xpos = 0; xpos < width; ++xpos) + { + U32 bm_col_offsetbyte = xpos / 8; + U32 bm_col_offsetbit = 7 - (xpos % 8); + U32 bit = + !!(buffer_data[bm_row_offset + + bm_col_offsetbyte + ] & (1 << bm_col_offsetbit) ); + tmp_graydata[width*ypos + xpos] = + 255 * bit; + } + } + // use newly-built graymap. + buffer_data = tmp_graydata; + buffer_row_stride = width; + } + + switch (mFontBitmapCachep->getNumComponents()) + { + case 1: + mFontBitmapCachep->getImageRaw(bitmap_num)->setSubImage(pos_x, + pos_y, + width, + height, + buffer_data, + buffer_row_stride, + TRUE); + break; + case 2: + setSubImageLuminanceAlpha(pos_x, + pos_y, + bitmap_num, + width, + height, + buffer_data, + buffer_row_stride); + break; + default: + break; + } + + if (tmp_graydata) + delete[] tmp_graydata; + } else { + // we don't know how to handle this pixel format from FreeType; + // omit it from the font-image. + } + + return TRUE; +} + +LLFontGlyphInfo* LLFontFreetype::getGlyphInfo(llwchar wch) const +{ + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter != mCharGlyphInfoMap.end()) + { + return iter->second; + } + return NULL; +} + +void LLFontFreetype::insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const +{ + char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.find(wch); + if (iter != mCharGlyphInfoMap.end()) + { + delete iter->second; + iter->second = gi; + } + else + { + mCharGlyphInfoMap[wch] = gi; + } +} + +void LLFontFreetype::renderGlyph(U32 glyph_index) const +{ + if (mFTFace == NULL) + return; + + int error = FT_Load_Glyph(mFTFace, glyph_index, FT_LOAD_DEFAULT ); + llassert(!error); + + error = FT_Render_Glyph(mFTFace->glyph, gFontRenderMode); + + mRenderGlyphCount++; + + llassert(!error); +} + +void LLFontFreetype::reset(F32 vert_dpi, F32 horz_dpi) +{ + if (!mIsFallback) + { + // This is the head of the list - need to rebuild ourself and all fallbacks. + loadFace(mName, mPointSize, vert_dpi ,horz_dpi, mFontBitmapCachep->getNumComponents(), mIsFallback); + + if (mFallbackFonts.empty()) + { + llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl; + } + else + { + for(font_vector_t::iterator it = mFallbackFonts.begin(); + it != mFallbackFonts.end(); + ++it) + { + (*it)->reset(vert_dpi, horz_dpi); + } + } + } + resetBitmapCache(); +} + +void LLFontFreetype::resetBitmapCache() +{ + // Iterate through glyphs and clear the mIsRendered flag + for (char_glyph_info_map_t::iterator iter = mCharGlyphInfoMap.begin(); + iter != mCharGlyphInfoMap.end(); ++iter) + { + iter->second->mIsRendered = FALSE; + //FIXME: this is only strictly necessary when resetting the entire font, + //not just flushing the bitmap + iter->second->mMetricsValid = FALSE; + } + mFontBitmapCachep->reset(); + + // Add the empty glyph`5 + addGlyph(0, 0); +} + +void LLFontFreetype::destroyGL() +{ + mFontBitmapCachep->destroyGL(); +} + +BOOL LLFontFreetype::getIsFallback() const +{ + return mIsFallback; +} + +const std::string &LLFontFreetype::getName() const +{ + return mName; +} + +F32 LLFontFreetype::getPointSize() const +{ + return mPointSize; +} + +const LLPointer LLFontFreetype::getFontBitmapCache() const +{ + return mFontBitmapCachep; +} + +void LLFontFreetype::setStyle(U8 style) +{ + mStyle = style; +} + +U8 LLFontFreetype::getStyle() const +{ + return mStyle; +} + +void LLFontFreetype::setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride) const +{ + LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); + + llassert(!mIsFallback); + llassert(image_raw && (image_raw->getComponents() == 2)); + + + U8 *target = image_raw->getData(); + + if (!data) + { + return; + } + + if (0 == stride) + stride = width; + + U32 i, j; + U32 to_offset; + U32 from_offset; + U32 target_width = image_raw->getWidth(); + for (i = 0; i < height; i++) + { + to_offset = (y + i)*target_width + x; + from_offset = (height - 1 - i)*stride; + for (j = 0; j < width; j++) + { + *(target + to_offset*2 + 1) = *(data + from_offset); + to_offset++; + from_offset++; + } + } +} + diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h new file mode 100644 index 0000000000..0520ef2cd6 --- /dev/null +++ b/indra/llrender/llfontfreetype.h @@ -0,0 +1,380 @@ +/** + * @file llfontfreetype.h + * @brief Font library wrapper + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFONTFREETYPE_H +#define LL_LLFONTFREETYPE_H + +#include +#include "llpointer.h" +#include "llstl.h" + +#include "llimagegl.h" +#include "llfontbitmapcache.h" + +// Hack. FT_Face is just a typedef for a pointer to a struct, +// but there's no simple forward declarations file for FreeType, +// and the main include file is 200K. +// We'll forward declare the struct here. JC +struct FT_FaceRec_; +typedef struct FT_FaceRec_* LLFT_Face; + +class LLFontManager +{ +public: + static void initClass(); + static void cleanupClass(); + +private: + LLFontManager(); + ~LLFontManager(); +}; + +class LLFontGlyphInfo +{ +public: + LLFontGlyphInfo(U32 index); + + U32 mGlyphIndex; + + // Metrics + S32 mWidth; // In pixels + S32 mHeight; // In pixels + F32 mXAdvance; // In pixels + F32 mYAdvance; // In pixels + BOOL mMetricsValid; // We have up-to-date metrics for this glyph + + // Information for actually rendering + BOOL mIsRendered; // We actually have rendered this glyph + S32 mXBitmapOffset; // Offset to the origin in the bitmap + S32 mYBitmapOffset; // Offset to the origin in the bitmap + S32 mXBearing; // Distance from baseline to left in pixels + S32 mYBearing; // Distance from baseline to top in pixels + S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph +}; + +extern LLFontManager *gFontManagerp; + +class LLFontFreetype : public LLRefCount +{ +public: + LLFontFreetype(); + ~LLFontFreetype(); + + // is_fallback should be true for fallback fonts that aren't used + // to render directly (Unicode backup, primarily) + BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback); + + typedef std::vector > font_vector_t; + + void setFallbackFonts(const font_vector_t &font); + const font_vector_t &getFallbackFonts() const; + + // Global font metrics - in units of pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + + +// For a lowercase "g": +// +// ------------------------------ +// ^ ^ +// | | +// xxx x |Ascender +// x x v | +// --------- xxxx-------------- Baseline +// ^ x | +// | Descender x | +// v xxxx |LineHeight +// ----------------------- | +// v +// ------------------------------ + + enum + { + FIRST_CHAR = 32, + NUM_CHARS = 127 - 32, + LAST_CHAR_BASIC = 127, + + // Need full 8-bit ascii range for spanish + NUM_CHARS_FULL = 255 - 32, + LAST_CHAR_FULL = 255 + }; + + F32 getXAdvance(llwchar wc) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + BOOL addChar(llwchar wch) const; // Add a new character to the font if necessary + BOOL addGlyph(llwchar wch, U32 glyph_index) const; // Add a new glyph to the existing font + BOOL addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + + LLFontGlyphInfo* getGlyphInfo(llwchar wch) const; + + void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; + void renderGlyph(U32 glyph_index) const; + + void reset(F32 vert_dpi, F32 horz_dpi); + void resetBitmapCache(); + + void destroyGL(); + + BOOL getIsFallback() const; + + const std::string& getName() const; + + F32 getPointSize() const; + + const LLPointer getFontBitmapCache() const; + + void setStyle(U8 style); + U8 getStyle() const; + +private: + void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; + + std::string mName; + + U8 mStyle; + + F32 mPointSize; + F32 mAscender; + F32 mDescender; + F32 mLineHeight; + + LLFT_Face mFTFace; + + BOOL mIsFallback; + font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) + + BOOL mValid; + + typedef std::map char_glyph_info_map_t; + mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap + + mutable LLPointer mFontBitmapCachep; + + mutable S32 mRenderGlyphCount; + mutable S32 mAddGlyphCount; +}; + +#endif // LL_FONTFREETYPE_H +/** + * @file llfontfreetype.h + * @brief Font library wrapper + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFONTFREETYPE_H +#define LL_LLFONTFREETYPE_H + +#include +#include "llpointer.h" +#include "llstl.h" + +#include "llimagegl.h" +#include "llfontbitmapcache.h" + +// Hack. FT_Face is just a typedef for a pointer to a struct, +// but there's no simple forward declarations file for FreeType, +// and the main include file is 200K. +// We'll forward declare the struct here. JC +struct FT_FaceRec_; +typedef struct FT_FaceRec_* LLFT_Face; + +class LLFontManager +{ +public: + static void initClass(); + static void cleanupClass(); + +private: + LLFontManager(); + ~LLFontManager(); +}; + +class LLFontGlyphInfo +{ +public: + LLFontGlyphInfo(U32 index); + + U32 mGlyphIndex; + + // Metrics + S32 mWidth; // In pixels + S32 mHeight; // In pixels + F32 mXAdvance; // In pixels + F32 mYAdvance; // In pixels + BOOL mMetricsValid; // We have up-to-date metrics for this glyph + + // Information for actually rendering + BOOL mIsRendered; // We actually have rendered this glyph + S32 mXBitmapOffset; // Offset to the origin in the bitmap + S32 mYBitmapOffset; // Offset to the origin in the bitmap + S32 mXBearing; // Distance from baseline to left in pixels + S32 mYBearing; // Distance from baseline to top in pixels + S32 mBitmapNum; // Which bitmap in the bitmap cache contains this glyph +}; + +extern LLFontManager *gFontManagerp; + +class LLFontFreetype : public LLRefCount +{ +public: + LLFontFreetype(); + ~LLFontFreetype(); + + // is_fallback should be true for fallback fonts that aren't used + // to render directly (Unicode backup, primarily) + BOOL loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback); + + typedef std::vector > font_vector_t; + + void setFallbackFonts(const font_vector_t &font); + const font_vector_t &getFallbackFonts() const; + + // Global font metrics - in units of pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; + + +// For a lowercase "g": +// +// ------------------------------ +// ^ ^ +// | | +// xxx x |Ascender +// x x v | +// --------- xxxx-------------- Baseline +// ^ x | +// | Descender x | +// v xxxx |LineHeight +// ----------------------- | +// v +// ------------------------------ + + enum + { + FIRST_CHAR = 32, + NUM_CHARS = 127 - 32, + LAST_CHAR_BASIC = 127, + + // Need full 8-bit ascii range for spanish + NUM_CHARS_FULL = 255 - 32, + LAST_CHAR_FULL = 255 + }; + + F32 getXAdvance(llwchar wc) const; + F32 getXKerning(llwchar char_left, llwchar char_right) const; // Get the kerning between the two characters + + BOOL hasGlyph(llwchar wch) const; // Has a glyph for this character + BOOL addChar(llwchar wch) const; // Add a new character to the font if necessary + BOOL addGlyph(llwchar wch, U32 glyph_index) const; // Add a new glyph to the existing font + BOOL addGlyphFromFont(const LLFontFreetype *fontp, llwchar wch, U32 glyph_index) const; // Add a glyph from this font to the other (returns the glyph_index, 0 if not found) + + LLFontGlyphInfo* getGlyphInfo(llwchar wch) const; + + void insertGlyphInfo(llwchar wch, LLFontGlyphInfo* gi) const; + void renderGlyph(U32 glyph_index) const; + + void reset(F32 vert_dpi, F32 horz_dpi); + void resetBitmapCache(); + + void destroyGL(); + + BOOL getIsFallback() const; + + const std::string& getName() const; + + F32 getPointSize() const; + + const LLPointer getFontBitmapCache() const; + + void setStyle(U8 style); + U8 getStyle() const; + +private: + void setSubImageLuminanceAlpha(U32 x, U32 y, U32 bitmap_num, U32 width, U32 height, U8 *data, S32 stride = 0) const; + + std::string mName; + + U8 mStyle; + + F32 mPointSize; + F32 mAscender; + F32 mDescender; + F32 mLineHeight; + + LLFT_Face mFTFace; + + BOOL mIsFallback; + font_vector_t mFallbackFonts; // A list of fallback fonts to look for glyphs in (for Unicode chars) + + BOOL mValid; + + typedef std::map char_glyph_info_map_t; + mutable char_glyph_info_map_t mCharGlyphInfoMap; // Information about glyph location in bitmap + + mutable LLPointer mFontBitmapCachep; + + mutable S32 mRenderGlyphCount; + mutable S32 mAddGlyphCount; +}; + +#endif // LL_FONTFREETYPE_H diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index beecb6b7c1..d76b23248d 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -32,16 +32,21 @@ #include "linden_common.h" -#include - -#include "llfont.h" #include "llfontgl.h" + +// Linden library includes +#include "llfontfreetype.h" #include "llfontbitmapcache.h" #include "llfontregistry.h" #include "llgl.h" +#include "llimagegl.h" #include "llrender.h" -#include "v4color.h" #include "llstl.h" +#include "v4color.h" +#include "lltexture.h" + +// Third party library includes +#include const S32 BOLD_OFFSET = 1; @@ -68,320 +73,52 @@ const F32 PIXEL_CORRECTION_DISTANCE = 0.01f; const F32 PAD_UVY = 0.5f; // half of vertical padding between glyphs in the glyph texture const F32 DROP_SHADOW_SOFT_STRENGTH = 0.3f; -F32 llfont_round_x(F32 x) +static F32 llfont_round_x(F32 x) { //return llfloor((x-LLFontGL::sCurOrigin.mX)/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleX+LLFontGL::sCurOrigin.mX; //return llfloor(x/LLFontGL::sScaleX+0.5f)*LLFontGL::sScaleY; return x; } -F32 llfont_round_y(F32 y) +static F32 llfont_round_y(F32 y) { //return llfloor((y-LLFontGL::sCurOrigin.mY)/LLFontGL::sScaleY+0.5f)*LLFontGL::sScaleY+LLFontGL::sCurOrigin.mY; //return llfloor(y+0.5f); return y; } -// static -U8 LLFontGL::getStyleFromString(const std::string &style) -{ - S32 ret = 0; - if (style.find("NORMAL") != style.npos) - { - ret |= NORMAL; - } - if (style.find("BOLD") != style.npos) - { - ret |= BOLD; - } - if (style.find("ITALIC") != style.npos) - { - ret |= ITALIC; - } - if (style.find("UNDERLINE") != style.npos) - { - ret |= UNDERLINE; - } - if (style.find("SHADOW") != style.npos) - { - ret |= DROP_SHADOW; - } - if (style.find("SOFT_SHADOW") != style.npos) - { - ret |= DROP_SHADOW_SOFT; - } - return ret; -} - LLFontGL::LLFontGL() - : LLFont() { - clearEmbeddedChars(); -} - -LLFontGL::LLFontGL(const LLFontGL &source) -{ - llerrs << "Not implemented!" << llendl; } LLFontGL::~LLFontGL() { - clearEmbeddedChars(); } void LLFontGL::reset() { - if (!mIsFallback) - { - // This is the head of the list - need to rebuild ourself and all fallbacks. - loadFace(mName,mPointSize,sVertDPI,sHorizDPI,mFontBitmapCachep->getNumComponents(),mIsFallback); - if (mFallbackFontp==NULL) - { - llwarns << "LLFontGL::reset(), no fallback fonts present" << llendl; - } - else - { - for (LLFontList::iterator it = mFallbackFontp->begin(); - it != mFallbackFontp->end(); - ++it) - { - (*it)->reset(); - } - } - } - resetBitmapCache(); -} - -// static -std::string LLFontGL::getFontPathSystem() -{ - std::string system_path; - - // Try to figure out where the system's font files are stored. - char *system_root = NULL; -#if LL_WINDOWS - system_root = getenv("SystemRoot"); /* Flawfinder: ignore */ - if (!system_root) - { - llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl; - } -#endif - - if (system_root) - { - system_path = llformat("%s/fonts/", system_root); - } - else - { -#if LL_WINDOWS - // HACK for windows 98/Me - system_path = "/WINDOWS/FONTS/"; -#elif LL_DARWIN - // HACK for Mac OS X - system_path = "/System/Library/Fonts/"; -#endif - } - return system_path; -} - - -// static -std::string LLFontGL::getFontPathLocal() -{ - std::string local_path; - - // Backup files if we can't load from system fonts directory. - // We could store this in an end-user writable directory to allow - // end users to switch fonts. - if (LLFontGL::sAppDir.length()) - { - // use specified application dir to look for fonts - local_path = LLFontGL::sAppDir + "/fonts/"; - } - else - { - // assume working directory is executable directory - local_path = "./fonts/"; - } - return local_path; -} - -bool findOrCreateFont(LLFontGL*& fontp, const LLFontDescriptor& desc) -{ - // Don't delete existing fonts, if any, here, because they've - // already been deleted by LLFontRegistry::clear() - fontp = LLFontGL::getFont(desc); - return (fontp != NULL); -} - -// static -BOOL LLFontGL::initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale, - const std::string& app_dir, - const std::vector& xui_paths) -{ - bool succ = true; - sVertDPI = (F32)llfloor(screen_dpi * y_scale); - sHorizDPI = (F32)llfloor(screen_dpi * x_scale); - sScaleX = x_scale; - sScaleY = y_scale; - sAppDir = app_dir; - - // Font registry init - if (!sFontRegistry) - { - sFontRegistry = new LLFontRegistry(xui_paths); - sFontRegistry->parseFontInfo("fonts.xml"); - } - else - { - sFontRegistry->reset(); - } - - // Force standard fonts to get generated up front. - // This is primarily for error detection purposes. - succ &= (NULL != getFontSansSerifSmall()); - succ &= (NULL != getFontSansSerif()); - succ &= (NULL != getFontSansSerifBig()); - succ &= (NULL != getFontSansSerifHuge()); - succ &= (NULL != getFontSansSerifBold()); - succ &= (NULL != getFontMonospace()); - succ &= (NULL != getFontExtChar()); - - return succ; -} - - - -// static -void LLFontGL::destroyDefaultFonts() -{ - // Remove the actual fonts. - delete sFontRegistry; - sFontRegistry = NULL; -} - -//static -void LLFontGL::destroyAllGL() -{ - if (sFontRegistry) - { - sFontRegistry->destroyGL(); - } + mFontFreetype->reset(sVertDPI, sHorizDPI); } void LLFontGL::destroyGL() { - mFontBitmapCachep->destroyGL(); + mFontFreetype->destroyGL(); } - - -LLFontGL &LLFontGL::operator=(const LLFontGL &source) +BOOL LLFontGL::loadFace(const std::string& filename, F32 point_size, F32 vert_dpi, F32 horz_dpi, S32 components, BOOL is_fallback) { - llerrs << "Not implemented" << llendl; - return *this; -} - -BOOL LLFontGL::loadFace(const std::string& filename, - const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, - const S32 components, BOOL is_fallback) -{ - if (!LLFont::loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback)) + if(mFontFreetype == reinterpret_cast(NULL)) { - return FALSE; - } - return TRUE; -} - -//static -LLFontGL* LLFontGL::getFontMonospace() -{ - return getFont(LLFontDescriptor("Monospace","Monospace",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerifSmall() -{ - return getFont(LLFontDescriptor("SansSerif","Small",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerif() -{ - return getFont(LLFontDescriptor("SansSerif","Medium",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerifBig() -{ - return getFont(LLFontDescriptor("SansSerif","Large",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerifHuge() -{ - return getFont(LLFontDescriptor("SansSerif","Huge",0)); -} - -//static -LLFontGL* LLFontGL::getFontSansSerifBold() -{ - return getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); -} - -//static -LLFontGL* LLFontGL::getFontExtChar() -{ - return getFontSansSerif(); -} - -//static -LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) -{ - return sFontRegistry->getFont(desc); -} - -BOOL LLFontGL::addChar(const llwchar wch) const -{ - if (!LLFont::addChar(wch)) - { - return FALSE; + mFontFreetype = new LLFontFreetype; } - stop_glerror(); - - LLFontGlyphInfo *glyph_info = getGlyphInfo(wch); - U32 bitmap_num = glyph_info->mBitmapNum; - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(bitmap_num); - LLImageRaw *image_raw = mFontBitmapCachep->getImageRaw(bitmap_num); - image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); - return TRUE; + return mFontFreetype->loadFace(filename, point_size, vert_dpi, horz_dpi, components, is_fallback); } +static LLFastTimer::DeclareTimer FTM_RENDER_FONTS("Fonts"); -S32 LLFontGL::renderUTF8(const std::string &text, const S32 offset, - const F32 x, const F32 y, - const LLColor4 &color, - const HAlign halign, const VAlign valign, - U8 style, - const S32 max_chars, const S32 max_pixels, - F32* right_x, - BOOL use_ellipses) const -{ - LLWString wstr = utf8str_to_wstring(text); - return render(wstr, offset, x, y, color, halign, valign, style, max_chars, max_pixels, right_x, FALSE, use_ellipses); -} - -S32 LLFontGL::render(const LLWString &wstr, - const S32 begin_offset, - const F32 x, const F32 y, - const LLColor4 &color, - const HAlign halign, const VAlign valign, - U8 style, - const S32 max_chars, S32 max_pixels, - F32* right_x, - BOOL use_embedded, - BOOL use_ellipses) const +S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, + ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const { if(!sDisplayFont) //do not display texts { @@ -397,18 +134,19 @@ S32 LLFontGL::render(const LLWString &wstr, S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX); - // Strip off any style bits that are already accounted for by the font. - style = style & (~getFontDesc().getStyle()); + // determine which style flags need to be added programmatically by striping off the + // style bits that are drawn by the underlying Freetype font + U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle(); F32 drop_shadow_strength = 0.f; - if (style & (DROP_SHADOW | DROP_SHADOW_SOFT)) + if (shadow != NO_SHADOW) { F32 luminance; color.calcHSL(NULL, NULL, &luminance); drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f); if (luminance < 0.35f) { - style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT); + shadow = NO_SHADOW; } } @@ -421,7 +159,7 @@ S32 LLFontGL::render(const LLWString &wstr, F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY); gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f); - LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS); + LLFastTimer t(FTM_RENDER_FONTS); gGL.color4fv( color.mV ); @@ -450,13 +188,13 @@ S32 LLFontGL::render(const LLWString &wstr, switch (valign) { case TOP: - cur_y -= mAscender; + cur_y -= mFontFreetype->getAscenderHeight(); break; case BOTTOM: - cur_y += mDescender; + cur_y += mFontFreetype->getDescenderHeight(); break; case VCENTER: - cur_y -= ((mAscender - mDescender)/2.f); + cur_y -= ((mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight())/2.f); break; case BASELINE: // Baseline, do nothing. @@ -484,14 +222,16 @@ S32 LLFontGL::render(const LLWString &wstr, F32 start_x = cur_x; - F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth(); - F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight(); + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); - const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL; + F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); + F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); + + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; BOOL draw_ellipses = FALSE; - if (use_ellipses && halign == LEFT) + if (use_ellipses) { // check for too long of a string if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels) @@ -511,135 +251,69 @@ S32 LLFontGL::render(const LLWString &wstr, { llwchar wch = wstr[i]; - // Handle embedded characters first, if they're enabled. - // Embedded characters are a hack for notecards - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + if (!mFontFreetype->hasGlyph(wch)) { - LLImageGL* ext_image = ext_data->mImage; - const LLWString& label = ext_data->mLabel; - - F32 ext_height = (F32)ext_image->getHeight() * sScaleY; - - F32 ext_width = (F32)ext_image->getWidth() * sScaleX; - F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width; - - if (!label.empty()) - { - ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX; - } - - if (start_x + scaled_max_pixels < cur_x + ext_advance) - { - // Not enough room for this character. - break; - } - - if (last_bound_texture != ext_image) - { - gGL.getTexUnit(0)->bind(ext_image); - last_bound_texture = ext_image; - } - - // snap origin to whole screen pixel - const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX)); - const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight)); - - LLRectf uv_rect(0.f, 1.f, 1.f, 0.f); - LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y); - drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength); - - if (!label.empty()) - { - gGL.pushMatrix(); - //glLoadIdentity(); - //gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f); - //glScalef(sScaleX, sScaleY, 1.f); - getFontExtChar()->render(label, 0, - /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), - /*llfloor*/(cur_y / sScaleY), - color, - halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL, - TRUE ); - gGL.popMatrix(); - } - - gGL.color4fv(color.mV); - - chars_drawn++; - cur_x += ext_advance; - if (((i + 1) < length) && wstr[i+1]) - { - cur_x += EXT_KERNING * sScaleX; - } - cur_render_x = cur_x; + addChar(wch); } - else + + const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch); + if (!fgi) { - if (!hasGlyph(wch)) - { - addChar(wch); - } - - const LLFontGlyphInfo* fgi= getGlyphInfo(wch); - if (!fgi) - { - llerrs << "Missing Glyph Info" << llendl; - break; - } - // Per-glyph bitmap texture. - LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum); - if (last_bound_texture != image_gl) - { - gGL.getTexUnit(0)->bind(image_gl); - last_bound_texture = image_gl; - } - - if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) - { - // Not enough room for this character. - break; - } - - // Draw the text at the appropriate location - //Specify vertices and texture coordinates - LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, - (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, - (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, - (fgi->mYBitmapOffset - PAD_UVY) * inv_height); - // snap glyph origin to whole screen pixel - LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing), - llround(cur_render_y + (F32)fgi->mYBearing), - llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, - llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); - - drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength); - - chars_drawn++; - cur_x += fgi->mXAdvance; - cur_y += fgi->mYAdvance; - - llwchar next_char = wstr[i+1]; - if (next_char && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - if (!hasGlyph(next_char)) - { - addChar(next_char); - } - cur_x += getXKerning(wch, next_char); - } - - // Round after kerning. - // Must do this to cur_x, not just to cur_render_x, otherwise you - // will squish sub-pixel kerned characters too close together. - // For example, "CCCCC" looks bad. - cur_x = (F32)llfloor(cur_x + 0.5f); - //cur_y = (F32)llfloor(cur_y + 0.5f); - - cur_render_x = cur_x; - cur_render_y = cur_y; + llerrs << "Missing Glyph Info" << llendl; + break; } + // Per-glyph bitmap texture. + LLImageGL *image_gl = mFontFreetype->getFontBitmapCache()->getImageGL(fgi->mBitmapNum); + if (last_bound_texture != image_gl) + { + gGL.getTexUnit(0)->bind(image_gl); + last_bound_texture = image_gl; + } + + if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) + { + // Not enough room for this character. + break; + } + + // Draw the text at the appropriate location + //Specify vertices and texture coordinates + LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width, + (fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height, + (fgi->mXBitmapOffset + fgi->mWidth) * inv_width, + (fgi->mYBitmapOffset - PAD_UVY) * inv_height); + // snap glyph origin to whole screen pixel + LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing), + llround(cur_render_y + (F32)fgi->mYBearing), + llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth, + llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight); + + drawGlyph(screen_rect, uv_rect, color, style_to_add, shadow, drop_shadow_strength); + + chars_drawn++; + cur_x += fgi->mXAdvance; + cur_y += fgi->mYAdvance; + + llwchar next_char = wstr[i+1]; + if (next_char && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + if (!mFontFreetype->hasGlyph(next_char)) + { + addChar(next_char); + } + cur_x += mFontFreetype->getXKerning(wch, next_char); + } + + // Round after kerning. + // Must do this to cur_x, not just to cur_render_x, otherwise you + // will squish sub-pixel kerned characters too close together. + // For example, "CCCCC" looks bad. + cur_x = (F32)llfloor(cur_x + 0.5f); + //cur_y = (F32)llfloor(cur_y + 0.5f); + + cur_render_x = cur_x; + cur_render_y = cur_y; } if (right_x) @@ -647,18 +321,20 @@ S32 LLFontGL::render(const LLWString &wstr, *right_x = cur_x / sScaleX; } - if (style & UNDERLINE) + if (style_to_add & UNDERLINE) { + F32 descender = mFontFreetype->getDescenderHeight(); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.begin(LLRender::LINES); - gGL.vertex2f(start_x, cur_y - (mDescender)); - gGL.vertex2f(cur_x, cur_y - (mDescender)); + gGL.vertex2f(start_x, cur_y - (descender)); + gGL.vertex2f(cur_x, cur_y - (descender)); gGL.end(); } - // *FIX: get this working in all alignment cases, etc. if (draw_ellipses) { + // recursively render ellipses at end of string // we've already reserved enough room gGL.pushMatrix(); @@ -670,7 +346,8 @@ S32 LLFontGL::render(const LLWString &wstr, cur_x / sScaleX, (F32)y, color, LEFT, valign, - style, + style_to_add, + shadow, S32_MAX, max_pixels, right_x, FALSE); @@ -682,6 +359,41 @@ S32 LLFontGL::render(const LLWString &wstr, return chars_drawn; } +S32 LLFontGL::render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const +{ + return render(text, begin_offset, x, y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const +{ + return render(utf8str_to_wstring(text), begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const +{ + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, LEFT, BASELINE, NORMAL, NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); +} + +S32 LLFontGL::renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow) const +{ + return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, halign, valign, style, shadow, S32_MAX, S32_MAX, NULL, FALSE); +} + +// font metrics - override for LLFontFreetype that returns units of virtual pixels +F32 LLFontGL::getLineHeight() const +{ + return (F32)llround(mFontFreetype->getLineHeight() / sScaleY); +} + +F32 LLFontGL::getAscenderHeight() const +{ + return (F32)llround(mFontFreetype->getAscenderHeight() / sScaleY); +} + +F32 LLFontGL::getDescenderHeight() const +{ + return (F32)llround(mFontFreetype->getDescenderHeight() / sScaleY); +} S32 LLFontGL::getWidth(const std::string& utf8text) const { @@ -694,15 +406,15 @@ S32 LLFontGL::getWidth(const llwchar* wchars) const return getWidth(wchars, 0, S32_MAX); } -S32 LLFontGL::getWidth(const std::string& utf8text, const S32 begin_offset, const S32 max_chars) const +S32 LLFontGL::getWidth(const std::string& utf8text, S32 begin_offset, S32 max_chars) const { LLWString wtext = utf8str_to_wstring(utf8text); return getWidth(wtext.c_str(), begin_offset, max_chars); } -S32 LLFontGL::getWidth(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const +S32 LLFontGL::getWidth(const llwchar* wchars, S32 begin_offset, S32 max_chars) const { - F32 width = getWidthF32(wchars, begin_offset, max_chars, use_embedded); + F32 width = getWidthF32(wchars, begin_offset, max_chars); return llround(width); } @@ -717,48 +429,35 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars) const return getWidthF32(wchars, 0, S32_MAX); } -F32 LLFontGL::getWidthF32(const std::string& utf8text, const S32 begin_offset, const S32 max_chars ) const +F32 LLFontGL::getWidthF32(const std::string& utf8text, S32 begin_offset, S32 max_chars ) const { LLWString wtext = utf8str_to_wstring(utf8text); return getWidthF32(wtext.c_str(), begin_offset, max_chars); } -F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const +F32 LLFontGL::getWidthF32(const llwchar* wchars, S32 begin_offset, S32 max_chars) const { - const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL; + const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL; F32 cur_x = 0; const S32 max_index = begin_offset + max_chars; for (S32 i = begin_offset; i < max_index; i++) { - const llwchar wch = wchars[i]; + llwchar wch = wchars[i]; if (wch == 0) { break; // done } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) - { - // Handle crappy embedded hack - cur_x += getEmbeddedCharAdvance(ext_data); - if( ((i+1) < max_chars) && (i+1 < max_index)) - { - cur_x += EXT_KERNING * sScaleX; - } - } - else - { - cur_x += getXAdvance(wch); - llwchar next_char = wchars[i+1]; + cur_x += mFontFreetype->getXAdvance(wch); + llwchar next_char = wchars[i+1]; - if (((i + 1) < max_chars) - && next_char - && (next_char < LAST_CHARACTER)) - { - // Kern this puppy. - cur_x += getXKerning(wch, next_char); - } + if (((i + 1) < begin_offset + max_chars) + && next_char + && (next_char < LAST_CHARACTER)) + { + // Kern this puppy. + cur_x += mFontFreetype->getXKerning(wch, next_char); } // Round after kerning. cur_x = (F32)llfloor(cur_x + 0.5f); @@ -767,12 +466,8 @@ F32 LLFontGL::getWidthF32(const llwchar* wchars, const S32 begin_offset, const S return cur_x / sScaleX; } - - // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels -S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, - BOOL end_on_word_boundary, const BOOL use_embedded, - F32* drawn_pixels) const +S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars, BOOL end_on_word_boundary) const { if (!wchars || !wchars[0] || max_chars == 0) { @@ -802,68 +497,51 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch break; } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + if (in_word) { - if (in_word) + if (iswspace(wch)) { - in_word = FALSE; - } - else - { - start_of_last_word = i; - } - cur_x += getEmbeddedCharAdvance(ext_data); - - if (scaled_max_pixels < cur_x) - { - clip = TRUE; - break; - } - - if (((i+1) < max_chars) && wchars[i+1]) - { - cur_x += EXT_KERNING * sScaleX; - } - - if( scaled_max_pixels < cur_x ) - { - clip = TRUE; - break; - } - } - else - { - if (in_word) - { - if (iswspace(wch)) + if(wch !=(0x00A0)) { in_word = FALSE; } } - else + if (iswindividual(wch)) { - start_of_last_word = i; - if (!iswspace(wch)) + if (iswpunct(wchars[i+1])) { - in_word = TRUE; + in_word=TRUE; + } + else + { + in_word=FALSE; + start_of_last_word = i; } } - - cur_x += getXAdvance(wch); - - if (scaled_max_pixels < cur_x) + } + else + { + start_of_last_word = i; + if (!iswspace(wch)||!iswindividual(wch)) { - clip = TRUE; - break; - } - - if (((i+1) < max_chars) && wchars[i+1]) - { - // Kern this puppy. - cur_x += getXKerning(wch, wchars[i+1]); + in_word = TRUE; } } + + cur_x += mFontFreetype->getXAdvance(wch); + + if (scaled_max_pixels < cur_x) + { + clip = TRUE; + break; + } + + if (((i+1) < max_chars) && wchars[i+1]) + { + // Kern this puppy. + cur_x += mFontFreetype->getXKerning(wch, wchars[i+1]); + } + // Round after kerning. cur_x = (F32)llfloor(cur_x + 0.5f); drawn_x = cur_x; @@ -873,14 +551,9 @@ S32 LLFontGL::maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_ch { i = start_of_last_word; } - if (drawn_pixels) - { - *drawn_pixels = drawn_x; - } return i; } - S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos, S32 max_chars) const { if (!wchars || !wchars[0] || max_chars == 0) @@ -898,8 +571,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ { llwchar wch = wchars[i]; - const embedded_data_t* ext_data = getEmbeddedCharData(wch); - F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : getXAdvance(wch); + F32 char_width = mFontFreetype->getXAdvance(wch); if( scaled_max_pixels < (total_width + char_width) ) { @@ -917,7 +589,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ if ( i > 0 ) { // kerning - total_width += ext_data ? (EXT_KERNING * sScaleX) : getXKerning(wchars[i-1], wch); + total_width += mFontFreetype->getXKerning(wchars[i-1], wch); } // Round after kerning. @@ -927,8 +599,7 @@ S32 LLFontGL::firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_ return start_pos - drawable_chars; } - -S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const +S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round) const { if (!wchars || !wchars[0] || max_chars == 0) { @@ -936,7 +607,6 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, } F32 cur_x = 0; - S32 pos = 0; target_x *= sScaleX; @@ -945,246 +615,159 @@ S32 LLFontGL::charFromPixelOffset(const llwchar* wchars, const S32 begin_offset, F32 scaled_max_pixels = max_pixels * sScaleX; - for (S32 i = begin_offset; (i < max_index); i++) + S32 pos; + for (pos = begin_offset; pos < max_index; pos++) { - llwchar wch = wchars[i]; + llwchar wch = wchars[pos]; if (!wch) { break; // done } - const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL; - if (ext_data) + F32 char_width = mFontFreetype->getXAdvance(wch); + + if (round) { - F32 ext_advance = getEmbeddedCharAdvance(ext_data); - - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + ext_advance/2) - { - break; - } - } - else - { - if (target_x < cur_x + ext_advance) - { - break; - } - } - - if (scaled_max_pixels < cur_x + ext_advance) + // Note: if the mouse is on the left half of the character, the pick is to the character's left + // If it's on the right half, the pick is to the right. + if (target_x < cur_x + char_width*0.5f) { break; } - - pos++; - cur_x += ext_advance; - - if (((i + 1) < max_index) - && (wchars[(i + 1)])) - { - cur_x += EXT_KERNING * sScaleX; - } - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); } - else + else if (target_x < cur_x + char_width) { - F32 char_width = getXAdvance(wch); - - if (round) - { - // Note: if the mouse is on the left half of the character, the pick is to the character's left - // If it's on the right half, the pick is to the right. - if (target_x < cur_x + char_width*0.5f) - { - break; - } - } - else if (target_x < cur_x + char_width) - { - break; - } - - if (scaled_max_pixels < cur_x + char_width) - { - break; - } - - pos++; - cur_x += char_width; - - if (((i + 1) < max_index) - && (wchars[(i + 1)])) - { - llwchar next_char = wchars[i + 1]; - // Kern this puppy. - cur_x += getXKerning(wch, next_char); - } - - // Round after kerning. - cur_x = (F32)llfloor(cur_x + 0.5f); + break; } + + if (scaled_max_pixels < cur_x + char_width) + { + break; + } + + cur_x += char_width; + + if (((pos + 1) < max_index) + && (wchars[(pos + 1)])) + { + llwchar next_char = wchars[pos + 1]; + // Kern this puppy. + cur_x += mFontFreetype->getXKerning(wch, next_char); + } + + // Round after kerning. + cur_x = (F32)llfloor(cur_x + 0.5f); } - return pos; + return llmin(max_chars, pos - begin_offset); } - -const LLFontGL::embedded_data_t* LLFontGL::getEmbeddedCharData(const llwchar wch) const +BOOL LLFontGL::addChar(llwchar wch) const { - // Handle crappy embedded hack - embedded_map_t::const_iterator iter = mEmbeddedChars.find(wch); - if (iter != mEmbeddedChars.end()) + if (!mFontFreetype->addChar(wch)) { - return iter->second; + return FALSE; } - return NULL; + + stop_glerror(); + + LLFontGlyphInfo *glyph_info = mFontFreetype->getGlyphInfo(wch); + U32 bitmap_num = glyph_info->mBitmapNum; + + const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); + LLImageGL *image_gl = font_bitmap_cache->getImageGL(bitmap_num); + LLImageRaw *image_raw = font_bitmap_cache->getImageRaw(bitmap_num); + image_gl->setSubImage(image_raw, 0, 0, image_gl->getWidth(), image_gl->getHeight()); + return TRUE; } - -F32 LLFontGL::getEmbeddedCharAdvance(const embedded_data_t* ext_data) const +const LLFontDescriptor& LLFontGL::getFontDesc() const { - const LLWString& label = ext_data->mLabel; - LLImageGL* ext_image = ext_data->mImage; + return mFontDescriptor; +} - F32 ext_width = (F32)ext_image->getWidth(); - if( !label.empty() ) +// static +void LLFontGL::initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector& xui_paths, bool create_gl_textures) +{ + sVertDPI = (F32)llfloor(screen_dpi * y_scale); + sHorizDPI = (F32)llfloor(screen_dpi * x_scale); + sScaleX = x_scale; + sScaleY = y_scale; + sAppDir = app_dir; + + // Font registry init + if (!sFontRegistry) { - ext_width += (EXT_X_BEARING + getFontExtChar()->getWidthF32(label.c_str())) * sScaleX; + sFontRegistry = new LLFontRegistry(xui_paths, create_gl_textures); + sFontRegistry->parseFontInfo("fonts.xml"); } - - return (EXT_X_BEARING * sScaleX) + ext_width; -} - - -void LLFontGL::clearEmbeddedChars() -{ - for_each(mEmbeddedChars.begin(), mEmbeddedChars.end(), DeletePairedPointer()); - mEmbeddedChars.clear(); -} - -void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label ) const -{ - LLWString wlabel = utf8str_to_wstring(label); - addEmbeddedChar(wc, image, wlabel); -} - -void LLFontGL::addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& wlabel ) const -{ - embedded_data_t* ext_data = new embedded_data_t(image, wlabel); - mEmbeddedChars[wc] = ext_data; -} - -void LLFontGL::removeEmbeddedChar( llwchar wc ) const -{ - embedded_map_t::iterator iter = mEmbeddedChars.find(wc); - if (iter != mEmbeddedChars.end()) + else { - delete iter->second; - mEmbeddedChars.erase(wc); + sFontRegistry->reset(); } } - -void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +// Force standard fonts to get generated up front. +// This is primarily for error detection purposes. +// Don't do this during initClass because it can be slow and we want to get +// the viewer window on screen first. JC +// static +bool LLFontGL::loadDefaultFonts() { - gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mRight), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft), - llfont_round_y(screen_rect.mTop)); - - gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), - llfont_round_y(screen_rect.mBottom)); - - gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); - gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), - llfont_round_y(screen_rect.mBottom)); + bool succ = true; + succ &= (NULL != getFontSansSerifSmall()); + succ &= (NULL != getFontSansSerif()); + succ &= (NULL != getFontSansSerifBig()); + succ &= (NULL != getFontSansSerifHuge()); + succ &= (NULL != getFontSansSerifBold()); + succ &= (NULL != getFontMonospace()); + succ &= (NULL != getFontExtChar()); + return succ; } -void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_strength) const +// static +void LLFontGL::destroyDefaultFonts() { - F32 slant_offset; - slant_offset = ((style & ITALIC) ? ( -mAscender * 0.2f) : 0.f); + // Remove the actual fonts. + delete sFontRegistry; + sFontRegistry = NULL; +} - gGL.begin(LLRender::QUADS); +//static +void LLFontGL::destroyAllGL() +{ + if (sFontRegistry) { - //FIXME: bold and drop shadow are mutually exclusive only for convenience - //Allow both when we need them. - if (style & BOLD) - { - gGL.color4fv(color.mV); - for (S32 pass = 0; pass < 2; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } - } - else if (style & DROP_SHADOW_SOFT) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH; - gGL.color4fv(shadow_color.mV); - for (S32 pass = 0; pass < 5; pass++) - { - LLRectf screen_rect_offset = screen_rect; - - switch(pass) - { - case 0: - screen_rect_offset.translate(-1.f, -1.f); - break; - case 1: - screen_rect_offset.translate(1.f, -1.f); - break; - case 2: - screen_rect_offset.translate(1.f, 1.f); - break; - case 3: - screen_rect_offset.translate(-1.f, 1.f); - break; - case 4: - screen_rect_offset.translate(0, -2.f); - break; - } - - renderQuad(screen_rect_offset, uv_rect, slant_offset); - } - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else if (style & DROP_SHADOW) - { - LLColor4 shadow_color = LLFontGL::sShadowColor; - shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; - gGL.color4fv(shadow_color.mV); - LLRectf screen_rect_shadow = screen_rect; - screen_rect_shadow.translate(1.f, -1.f); - renderQuad(screen_rect_shadow, uv_rect, slant_offset); - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - else // normal rendering - { - gGL.color4fv(color.mV); - renderQuad(screen_rect, uv_rect, slant_offset); - } - + sFontRegistry->destroyGL(); } - gGL.end(); } +// static +U8 LLFontGL::getStyleFromString(const std::string &style) +{ + S32 ret = 0; + if (style.find("NORMAL") != style.npos) + { + ret |= NORMAL; + } + if (style.find("BOLD") != style.npos) + { + ret |= BOLD; + } + if (style.find("ITALIC") != style.npos) + { + ret |= ITALIC; + } + if (style.find("UNDERLINE") != style.npos) + { + ret |= UNDERLINE; + } + return ret; +} + +// static std::string LLFontGL::nameFromFont(const LLFontGL* fontp) { - return fontp->getFontDesc().getName(); + return fontp->mFontDescriptor.getName(); } // static @@ -1249,3 +832,237 @@ LLFontGL::VAlign LLFontGL::vAlignFromName(const std::string& name) //else leave baseline return gl_vfont_align; } + +//static +LLFontGL* LLFontGL::getFontMonospace() +{ + return getFont(LLFontDescriptor("Monospace","Monospace",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifSmall() +{ + return getFont(LLFontDescriptor("SansSerif","Small",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerif() +{ + return getFont(LLFontDescriptor("SansSerif","Medium",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifBig() +{ + return getFont(LLFontDescriptor("SansSerif","Large",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifHuge() +{ + return getFont(LLFontDescriptor("SansSerif","Huge",0)); +} + +//static +LLFontGL* LLFontGL::getFontSansSerifBold() +{ + return getFont(LLFontDescriptor("SansSerif","Medium",BOLD)); +} + +//static +LLFontGL* LLFontGL::getFontExtChar() +{ + return getFontSansSerif(); +} + +//static +LLFontGL* LLFontGL::getFont(const LLFontDescriptor& desc) +{ + return sFontRegistry->getFont(desc); +} + +//static +LLFontGL* LLFontGL::getFontByName(const std::string& name) +{ + // check for most common fonts first + if (name == "SANSSERIF") + { + return getFontSansSerif(); + } + else if (name == "SANSSERIF_SMALL") + { + return getFontSansSerifSmall(); + } + else if (name == "SANSSERIF_BIG") + { + return getFontSansSerifBig(); + } + else if (name == "SMALL" || name == "OCRA") + { + // *BUG: Should this be "MONOSPACE"? Do we use "OCRA" anymore? + // Does "SMALL" mean "SERIF"? + return getFontMonospace(); + } + else + { + return NULL; + } +} + +// static +std::string LLFontGL::getFontPathSystem() +{ + std::string system_path; + + // Try to figure out where the system's font files are stored. + char *system_root = NULL; +#if LL_WINDOWS + system_root = getenv("SystemRoot"); /* Flawfinder: ignore */ + if (!system_root) + { + llwarns << "SystemRoot not found, attempting to load fonts from default path." << llendl; + } +#endif + + if (system_root) + { + system_path = llformat("%s/fonts/", system_root); + } + else + { +#if LL_WINDOWS + // HACK for windows 98/Me + system_path = "/WINDOWS/FONTS/"; +#elif LL_DARWIN + // HACK for Mac OS X + system_path = "/System/Library/Fonts/"; +#endif + } + return system_path; +} + + +// static +std::string LLFontGL::getFontPathLocal() +{ + std::string local_path; + + // Backup files if we can't load from system fonts directory. + // We could store this in an end-user writable directory to allow + // end users to switch fonts. + if (LLFontGL::sAppDir.length()) + { + // use specified application dir to look for fonts + local_path = LLFontGL::sAppDir + "/fonts/"; + } + else + { + // assume working directory is executable directory + local_path = "./fonts/"; + } + return local_path; +} + +LLFontGL::LLFontGL(const LLFontGL &source) +{ + llerrs << "Not implemented!" << llendl; +} + +LLFontGL &LLFontGL::operator=(const LLFontGL &source) +{ + llerrs << "Not implemented" << llendl; + return *this; +} + +void LLFontGL::renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const +{ + gGL.texCoord2f(uv_rect.mRight, uv_rect.mTop); + gGL.vertex2f(llfont_round_x(screen_rect.mRight), + llfont_round_y(screen_rect.mTop)); + + gGL.texCoord2f(uv_rect.mLeft, uv_rect.mTop); + gGL.vertex2f(llfont_round_x(screen_rect.mLeft), + llfont_round_y(screen_rect.mTop)); + + gGL.texCoord2f(uv_rect.mLeft, uv_rect.mBottom); + gGL.vertex2f(llfont_round_x(screen_rect.mLeft + slant_amt), + llfont_round_y(screen_rect.mBottom)); + + gGL.texCoord2f(uv_rect.mRight, uv_rect.mBottom); + gGL.vertex2f(llfont_round_x(screen_rect.mRight + slant_amt), + llfont_round_y(screen_rect.mBottom)); +} + +void LLFontGL::drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_strength) const +{ + F32 slant_offset; + slant_offset = ((style & ITALIC) ? ( -mFontFreetype->getAscenderHeight() * 0.2f) : 0.f); + + gGL.begin(LLRender::QUADS); + { + //FIXME: bold and drop shadow are mutually exclusive only for convenience + //Allow both when we need them. + if (style & BOLD) + { + gGL.color4fv(color.mV); + for (S32 pass = 0; pass < 2; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + screen_rect_offset.translate((F32)(pass * BOLD_OFFSET), 0.f); + renderQuad(screen_rect_offset, uv_rect, slant_offset); + } + } + else if (shadow == DROP_SHADOW_SOFT) + { + LLColor4 shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength * DROP_SHADOW_SOFT_STRENGTH; + gGL.color4fv(shadow_color.mV); + for (S32 pass = 0; pass < 5; pass++) + { + LLRectf screen_rect_offset = screen_rect; + + switch(pass) + { + case 0: + screen_rect_offset.translate(-1.f, -1.f); + break; + case 1: + screen_rect_offset.translate(1.f, -1.f); + break; + case 2: + screen_rect_offset.translate(1.f, 1.f); + break; + case 3: + screen_rect_offset.translate(-1.f, 1.f); + break; + case 4: + screen_rect_offset.translate(0, -2.f); + break; + } + + renderQuad(screen_rect_offset, uv_rect, slant_offset); + } + gGL.color4fv(color.mV); + renderQuad(screen_rect, uv_rect, slant_offset); + } + else if (shadow == DROP_SHADOW) + { + LLColor4 shadow_color = LLFontGL::sShadowColor; + shadow_color.mV[VALPHA] = color.mV[VALPHA] * drop_shadow_strength; + gGL.color4fv(shadow_color.mV); + LLRectf screen_rect_shadow = screen_rect; + screen_rect_shadow.translate(1.f, -1.f); + renderQuad(screen_rect_shadow, uv_rect, slant_offset); + gGL.color4fv(color.mV); + renderQuad(screen_rect, uv_rect, slant_offset); + } + else // normal rendering + { + gGL.color4fv(color.mV); + renderQuad(screen_rect, uv_rect, slant_offset); + } + + } + gGL.end(); +} diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 6cb1727ff4..af8e0909af 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -34,23 +34,22 @@ #ifndef LL_LLFONTGL_H #define LL_LLFONTGL_H -#include "llfont.h" -#include "llimagegl.h" -#include "v2math.h" #include "llcoord.h" -#include "llrect.h" - #include "llfontregistry.h" +#include "llimagegl.h" +#include "llpointer.h" +#include "llrect.h" +#include "v2math.h" class LLColor4; - // Key used to request a font. class LLFontDescriptor; +class LLFontFreetype; // Structure used to store previously requested fonts. class LLFontRegistry; -class LLFontGL : public LLFont +class LLFontGL { public: enum HAlign @@ -73,131 +72,81 @@ public: enum StyleFlags { // text style to render. May be combined (these are bit flags) + // TODO:: Maybe change the value to 0x01 << 0 for 1 0x01 << 1 for 2, 0x01 << 2 for 4 NORMAL = 0, BOLD = 1, ITALIC = 2, - UNDERLINE = 4, - DROP_SHADOW = 8, - DROP_SHADOW_SOFT = 16 + UNDERLINE = 4 + }; + + enum ShadowType + { + NO_SHADOW, + DROP_SHADOW, + DROP_SHADOW_SOFT }; - - // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" - static U8 getStyleFromString(const std::string &style); LLFontGL(); - LLFontGL(const LLFontGL &source); ~LLFontGL(); - void init(); // Internal init, or reinitialization + void reset(); // Reset a font after GL cleanup. ONLY works on an already loaded font. - LLFontGL &operator=(const LLFontGL &source); - - static BOOL initDefaultFonts(F32 screen_dpi, F32 x_scale, F32 y_scale, - const std::string& app_dir, - const std::vector& xui_paths); - - static void destroyDefaultFonts(); - static void destroyAllGL(); void destroyGL(); - /* virtual*/ BOOL loadFace(const std::string& filename, - const F32 point_size, const F32 vert_dpi, const F32 horz_dpi, - const S32 components, BOOL is_fallback); + BOOL loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, const S32 components, BOOL is_fallback); + S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign = LEFT, VAlign valign = BASELINE, U8 style = NORMAL, + ShadowType shadow = NO_SHADOW, S32 max_chars = S32_MAX, S32 max_pixels = S32_MAX, F32* right_x=NULL, BOOL use_ellipses = FALSE) const; + S32 render(const LLWString &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color) const; - S32 renderUTF8(const std::string &text, const S32 begin_offset, - S32 x, S32 y, - const LLColor4 &color) const - { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, - LEFT, BASELINE, NORMAL, - S32_MAX, S32_MAX, NULL, FALSE); - } - - S32 renderUTF8(const std::string &text, const S32 begin_offset, - S32 x, S32 y, - const LLColor4 &color, - HAlign halign, VAlign valign, U8 style = NORMAL) const - { - return renderUTF8(text, begin_offset, (F32)x, (F32)y, color, - halign, valign, style, - S32_MAX, S32_MAX, NULL, FALSE); - } - // renderUTF8 does a conversion, so is slower! - S32 renderUTF8(const std::string &text, - S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color, - HAlign halign, - VAlign valign, - U8 style, - S32 max_chars, - S32 max_pixels, - F32* right_x, - BOOL use_ellipses) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color) const; + S32 renderUTF8(const std::string &text, S32 begin_offset, S32 x, S32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style = NORMAL, ShadowType shadow = NO_SHADOW) const; - S32 render(const LLWString &text, const S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color) const - { - return render(text, begin_offset, x, y, color, - LEFT, BASELINE, NORMAL, - S32_MAX, S32_MAX, NULL, FALSE, FALSE); - } - + // font metrics - override for LLFontFreetype that returns units of virtual pixels + F32 getLineHeight() const; + F32 getAscenderHeight() const; + F32 getDescenderHeight() const; - S32 render(const LLWString &text, - S32 begin_offset, - F32 x, F32 y, - const LLColor4 &color, - HAlign halign = LEFT, - VAlign valign = BASELINE, - U8 style = NORMAL, - S32 max_chars = S32_MAX, - S32 max_pixels = S32_MAX, - F32* right_x=NULL, - BOOL use_embedded = FALSE, - BOOL use_ellipses = FALSE) const; + S32 getWidth(const std::string& utf8text) const; + S32 getWidth(const llwchar* wchars) const; + S32 getWidth(const std::string& utf8text, S32 offset, S32 max_chars ) const; + S32 getWidth(const llwchar* wchars, S32 offset, S32 max_chars) const; - // font metrics - override for LLFont that returns units of virtual pixels - /*virtual*/ F32 getLineHeight() const { return (F32)llround(mLineHeight / sScaleY); } - /*virtual*/ F32 getAscenderHeight() const { return (F32)llround(mAscender / sScaleY); } - /*virtual*/ F32 getDescenderHeight() const { return (F32)llround(mDescender / sScaleY); } - - virtual S32 getWidth(const std::string& utf8text) const; - virtual S32 getWidth(const llwchar* wchars) const; - virtual S32 getWidth(const std::string& utf8text, const S32 offset, const S32 max_chars ) const; - virtual S32 getWidth(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE) const; - - virtual F32 getWidthF32(const std::string& utf8text) const; - virtual F32 getWidthF32(const llwchar* wchars) const; - virtual F32 getWidthF32(const std::string& text, const S32 offset, const S32 max_chars ) const; - virtual F32 getWidthF32(const llwchar* wchars, const S32 offset, const S32 max_chars, BOOL use_embedded = FALSE ) const; + F32 getWidthF32(const std::string& utf8text) const; + F32 getWidthF32(const llwchar* wchars) const; + F32 getWidthF32(const std::string& text, S32 offset, S32 max_chars ) const; + F32 getWidthF32(const llwchar* wchars, S32 offset, S32 max_chars) const; // The following are called often, frequently with large buffers, so do not use a string interface // Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels - virtual S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, - BOOL end_on_word_boundary = FALSE, const BOOL use_embedded = FALSE, - F32* drawn_pixels = NULL) const; + S32 maxDrawableChars(const llwchar* wchars, F32 max_pixels, S32 max_chars = S32_MAX, BOOL end_on_word_boundary = FALSE) const; // Returns the index of the first complete characters from text that can be drawn in max_pixels // given that the character at start_pos should be the last character (or as close to last as possible). - virtual S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; + S32 firstDrawableChar(const llwchar* wchars, F32 max_pixels, S32 text_len, S32 start_pos=S32_MAX, S32 max_chars = S32_MAX) const; // Returns the index of the character closest to pixel position x (ignoring text to the right of max_pixels and max_chars) - virtual S32 charFromPixelOffset(const llwchar* wchars, const S32 char_offset, - F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, - BOOL round = TRUE, BOOL use_embedded = FALSE) const; + S32 charFromPixelOffset(const llwchar* wchars, S32 char_offset, F32 x, F32 max_pixels=F32_MAX, S32 max_chars = S32_MAX, BOOL round = TRUE) const; + + BOOL addChar(const llwchar wch) const; + + const LLFontDescriptor& getFontDesc() const; - LLImageGL *getImageGL() const; + static void initClass(F32 screen_dpi, F32 x_scale, F32 y_scale, const std::string& app_dir, const std::vector& xui_paths, bool create_gl_textures = true); - void addEmbeddedChar( llwchar wc, LLImageGL* image, const std::string& label) const; - void addEmbeddedChar( llwchar wc, LLImageGL* image, const LLWString& label) const; - void removeEmbeddedChar( llwchar wc ) const; + // Load sans-serif, sans-serif-small, etc. + // Slow, requires multiple seconds to load fonts. + static bool loadDefaultFonts(); + static void destroyDefaultFonts(); + static void destroyAllGL(); + + // Takes a string with potentially several flags, i.e. "NORMAL|BOLD|ITALIC" + static U8 getStyleFromString(const std::string &style); static std::string nameFromFont(const LLFontGL* fontp); @@ -207,28 +156,7 @@ public: static std::string nameFromVAlign(LLFontGL::VAlign align); static LLFontGL::VAlign vAlignFromName(const std::string& name); - static void setFontDisplay(BOOL flag) { sDisplayFont = flag ; } - -protected: - struct embedded_data_t - { - embedded_data_t(LLImageGL* image, const LLWString& label) : mImage(image), mLabel(label) {} - LLPointer mImage; - LLWString mLabel; - }; - const embedded_data_t* getEmbeddedCharData(const llwchar wch) const; - F32 getEmbeddedCharAdvance(const embedded_data_t* ext_data) const; - void clearEmbeddedChars(); - void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const; - void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, F32 drop_shadow_fade) const; - -public: - static F32 sVertDPI; - static F32 sHorizDPI; - static F32 sScaleX; - static F32 sScaleY; - static BOOL sDisplayFont ; - static std::string sAppDir; // For loading fonts + static void setFontDisplay(BOOL flag) { sDisplayFont = flag; } static LLFontGL* getFontMonospace(); static LLFontGL* getFontSansSerifSmall(); @@ -238,33 +166,40 @@ public: static LLFontGL* getFontSansSerifBold(); static LLFontGL* getFontExtChar(); static LLFontGL* getFont(const LLFontDescriptor& desc); + // Use with legacy names like "SANSSERIF_SMALL" or "OCRA" + static LLFontGL* getFontByName(const std::string& name); - static LLColor4 sShadowColor; - - friend class LLTextBillboard; - friend class LLHUDText; - -protected: - /*virtual*/ BOOL addChar(const llwchar wch) const; - -protected: - typedef std::map embedded_map_t; - mutable embedded_map_t mEmbeddedChars; - - LLFontDescriptor mFontDesc; - - // Registry holds all instantiated fonts. - static LLFontRegistry* sFontRegistry; - -public: static std::string getFontPathLocal(); static std::string getFontPathSystem(); static LLCoordFont sCurOrigin; static std::vector sOriginStack; - const LLFontDescriptor &getFontDesc() const { return mFontDesc; } - void setFontDesc(const LLFontDescriptor& font_desc) { mFontDesc = font_desc; } + static LLColor4 sShadowColor; + + static F32 sVertDPI; + static F32 sHorizDPI; + static F32 sScaleX; + static F32 sScaleY; + static BOOL sDisplayFont ; + static std::string sAppDir; // For loading fonts + +private: + friend class LLFontRegistry; + friend class LLTextBillboard; + friend class LLHUDText; + + LLFontGL(const LLFontGL &source); + LLFontGL &operator=(const LLFontGL &source); + + LLFontDescriptor mFontDescriptor; + LLPointer mFontFreetype; + + void renderQuad(const LLRectf& screen_rect, const LLRectf& uv_rect, F32 slant_amt) const; + void drawGlyph(const LLRectf& screen_rect, const LLRectf& uv_rect, const LLColor4& color, U8 style, ShadowType shadow, F32 drop_shadow_fade) const; + + // Registry holds all instantiated fonts. + static LLFontRegistry* sFontRegistry; }; #endif diff --git a/indra/llrender/llfontregistry.cpp b/indra/llrender/llfontregistry.cpp index 9b5bc5d0af..99f364a589 100644 --- a/indra/llrender/llfontregistry.cpp +++ b/indra/llrender/llfontregistry.cpp @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -32,8 +33,9 @@ #include "linden_common.h" #include "llgl.h" -#include "llfontregistry.h" +#include "llfontfreetype.h" #include "llfontgl.h" +#include "llfontregistry.h" #include #include "llcontrol.h" #include "lldir.h" @@ -103,7 +105,7 @@ bool removeSubString(std::string& str, const std::string& substr) size_t pos = str.find(substr); if (pos != string::npos) { - str.replace(pos,substr.length(),(const char *)NULL, 0); + str.erase(pos); return true; } return false; @@ -167,7 +169,9 @@ LLFontDescriptor LLFontDescriptor::normalize() const return LLFontDescriptor(new_name,new_size,new_style,getFileNames()); } -LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths) +LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths, + bool create_gl_textures) +: mCreateGLTextures(create_gl_textures) { // Propagate this down from LLUICtrlFactory so LLRender doesn't // need an upstream dependency on LLUI. @@ -215,8 +219,8 @@ bool LLFontRegistry::parseFontInfo(const std::string& xml_filename) success = success || init_succ; } } - if (success) - dump(); + //if (success) + // dump(); return success; } @@ -379,7 +383,14 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) if (it != mFontMap.end()) { llinfos << "-- matching font exists: " << nearest_exact_desc.getName() << " size " << nearest_exact_desc.getSize() << " style " << ((S32) nearest_exact_desc.getStyle()) << llendl; - return it->second; + + // copying underlying Freetype font, and storing in LLFontGL with requested font descriptor + LLFontGL *font = new LLFontGL; + font->mFontDescriptor = desc; + font->mFontFreetype = it->second->mFontFreetype; + mFontMap[desc] = font; + + return font; } // Build list of font names to look for. @@ -407,10 +418,11 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) llwarns << "createFont failed, no file names specified" << llendl; return NULL; } - LLFontList *fontlistp = new LLFontList; + + LLFontFreetype::font_vector_t fontlist; LLFontGL *result = NULL; - // Snarf all fonts we can into fontlistp. First will get pulled + // Snarf all fonts we can into fontlist. First will get pulled // off the list and become the "head" font, set to non-fallback. // Rest will consitute the fallback list. BOOL is_first_found = TRUE; @@ -426,7 +438,9 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) { LLFontGL *fontp = new LLFontGL; std::string font_path = local_path + *file_name_it; - BOOL is_fallback = !is_first_found; + // *HACK: Fallback fonts don't render, so we can use that to suppress + // creation of OpenGL textures for test apps. JC + BOOL is_fallback = !is_first_found || !mCreateGLTextures; F32 extra_scale = (is_fallback)?fallback_scale:1.0; if (!fontp->loadFace(font_path, extra_scale * point_size, LLFontGL::sVertDPI, LLFontGL::sHorizDPI, 2, is_fallback)) @@ -450,23 +464,27 @@ LLFontGL *LLFontRegistry::createFont(const LLFontDescriptor& desc) is_first_found = false; } else - fontlistp->addAtEnd(fontp); + { + fontlist.push_back(fontp->mFontFreetype); + } } } - if (result && !fontlistp->empty()) + + if (result && !fontlist.empty()) { - result->setFallbackFont(fontlistp); + result->mFontFreetype->setFallbackFonts(fontlist); } - norm_desc.setStyle(match_desc->getStyle()); if (result) - result->setFontDesc(norm_desc); - - if (!result) + { + result->mFontDescriptor = desc; + } + else { llwarns << "createFont failed in some way" << llendl; } - mFontMap[norm_desc] = result; + + mFontMap[desc] = result; return result; } @@ -506,21 +524,19 @@ void LLFontRegistry::destroyGL() } } -LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& orig_desc) +LLFontGL *LLFontRegistry::getFont(const LLFontDescriptor& desc) { - LLFontDescriptor norm_desc = orig_desc.normalize(); - - font_reg_map_t::iterator it = mFontMap.find(norm_desc); + font_reg_map_t::iterator it = mFontMap.find(desc); if (it != mFontMap.end()) return it->second; else { - LLFontGL *fontp = createFont(orig_desc); + LLFontGL *fontp = createFont(desc); if (!fontp) { - llwarns << "getFont failed, name " << orig_desc.getName() - <<" style=[" << ((S32) orig_desc.getStyle()) << "]" - << " size=[" << orig_desc.getSize() << "]" << llendl; + llwarns << "getFont failed, name " << desc.getName() + <<" style=[" << ((S32) desc.getStyle()) << "]" + << " size=[" << desc.getSize() << "]" << llendl; } return fontp; } @@ -648,3 +664,8 @@ void LLFontRegistry::dump() } } } + +const string_vec_t& LLFontRegistry::getUltimateFallbackList() const +{ + return mUltimateFallbackList; +} diff --git a/indra/llrender/llfontregistry.h b/indra/llrender/llfontregistry.h index ed775eeed0..4da4ca48bb 100644 --- a/indra/llrender/llfontregistry.h +++ b/indra/llrender/llfontregistry.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -70,7 +71,10 @@ private: class LLFontRegistry { public: - LLFontRegistry(const string_vec_t& xui_paths); + // create_gl_textures - set to false for test apps with no OpenGL window, + // such as llui_libtest + LLFontRegistry(const string_vec_t& xui_paths, + bool create_gl_textures); ~LLFontRegistry(); // Load standard font info from XML file(s). @@ -94,7 +98,7 @@ public: void dump(); - const string_vec_t& getUltimateFallbackList() const { return mUltimateFallbackList; } + const string_vec_t& getUltimateFallbackList() const; private: LLFontGL *createFont(const LLFontDescriptor& desc); @@ -108,6 +112,7 @@ private: string_vec_t mUltimateFallbackList; string_vec_t mXUIPaths; + bool mCreateGLTextures; }; #endif // LL_LLFONTREGISTRY_H diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp index 61194c4ecf..7e1df0e565 100644 --- a/indra/llrender/llgl.cpp +++ b/indra/llrender/llgl.cpp @@ -45,10 +45,13 @@ #include "llrender.h" #include "llerror.h" +#include "llerrorcontrol.h" #include "llquaternion.h" #include "llmath.h" #include "m4math.h" #include "llstring.h" +#include "llmemtype.h" +#include "llstacktrace.h" #include "llglheaders.h" @@ -56,9 +59,49 @@ //#define GL_STATE_VERIFY #endif + +BOOL gDebugSession = FALSE; BOOL gDebugGL = FALSE; BOOL gClothRipple = FALSE; BOOL gNoRender = FALSE; + +std::ofstream gFailLog; + +void ll_init_fail_log(std::string filename) +{ + gFailLog.open(filename.c_str()); +} + + +void ll_fail(std::string msg) +{ + + if (gDebugSession) + { + std::vector lines; + + gFailLog << LLError::utcTime() << " " << msg << std::endl; + + gFailLog << "Stack Trace:" << std::endl; + + ll_get_stack_trace(lines); + + for(size_t i = 0; i < lines.size(); ++i) + { + gFailLog << lines[i] << std::endl; + } + + gFailLog << "End of Stack Trace." << std::endl << std::endl; + + gFailLog.flush(); + } +}; + +void ll_close_fail_log() +{ + gFailLog.close(); +} + LLMatrix4 gGLObliqueProjectionInverse; #define LL_GL_NAME_POOLING 0 @@ -596,6 +639,7 @@ void LLGLManager::initExtensions() mHasShaderObjects = FALSE; mHasVertexShader = FALSE; mHasFragmentShader = FALSE; + mHasTextureRectangle = FALSE; #else // LL_MESA_HEADLESS mHasMultitexture = glh_init_extensions("GL_ARB_multitexture"); mHasMipMapGeneration = glh_init_extensions("GL_SGIS_generate_mipmap"); @@ -612,6 +656,7 @@ void LLGLManager::initExtensions() && ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts); mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts); mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts); + mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts); #if !LL_DARWIN mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts); #endif @@ -685,6 +730,7 @@ void LLGLManager::initExtensions() if (strchr(blacklist,'q')) mHasFramebufferObject = FALSE;//S if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE; + if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE; } #endif // LL_LINUX || LL_SOLARIS @@ -971,6 +1017,7 @@ void assert_glerror() { return; } + if (!gGLManager.mInited) { LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL; @@ -988,12 +1035,22 @@ void assert_glerror() { LL_WARNS("RenderState") << "GL Error:" << error<< LL_ENDL; LL_WARNS("RenderState") << "GL Error String:" << gl_error_msg << LL_ENDL; + + if (gDebugSession) + { + gFailLog << "GL Error:" << gl_error_msg << std::endl; + } } else { // gluErrorString returns NULL for some extensions' error codes. // you'll probably have to grep for the number in glext.h. LL_WARNS("RenderState") << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << LL_ENDL; + + if (gDebugSession) + { + gFailLog << "GL Error: UNKNOWN 0x" << std::hex << error << std::dec << std::endl; + } } error = glGetError(); #endif @@ -1001,7 +1058,14 @@ void assert_glerror() if (quit) { - llerrs << "One or more unhandled GL errors." << llendl; + if (gDebugSession) + { + ll_fail("assert_glerror failed"); + } + else + { + llerrs << "One or more unhandled GL errors." << llendl; + } } } @@ -1087,9 +1151,19 @@ void LLGLState::checkStates(const std::string& msg) glGetIntegerv(GL_BLEND_SRC, &src); glGetIntegerv(GL_BLEND_DST, &dst); + BOOL error = FALSE; + if (src != GL_SRC_ALPHA || dst != GL_ONE_MINUS_SRC_ALPHA) { - LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << LL_ENDL; + if (gDebugSession) + { + gFailLog << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << std::endl; + error = TRUE; + } + else + { + LL_GL_ERRS << "Blend function corrupted: " << std::hex << src << " " << std::hex << dst << " " << msg << std::dec << LL_ENDL; + } } for (std::map::iterator iter = sStateMap.begin(); @@ -1101,10 +1175,22 @@ void LLGLState::checkStates(const std::string& msg) if(cur_state != gl_state) { dumpStates(); - LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; + if (gDebugSession) + { + gFailLog << llformat("LLGLState error. State: 0x%04x",state) << std::endl; + error = TRUE; + } + else + { + LL_GL_ERRS << llformat("LLGLState error. State: 0x%04x",state) << LL_ENDL; + } } } + if (error) + { + ll_fail("LLGLState::checkStates failed."); + } stop_glerror(); } @@ -1115,9 +1201,12 @@ void LLGLState::checkTextureChannels(const std::string& msg) return; } + stop_glerror(); + GLint activeTexture; glGetIntegerv(GL_ACTIVE_TEXTURE_ARB, &activeTexture); - + stop_glerror(); + BOOL error = FALSE; if (activeTexture == GL_TEXTURE0_ARB) @@ -1125,15 +1214,22 @@ void LLGLState::checkTextureChannels(const std::string& msg) GLint tex_env_mode = 0; glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &tex_env_mode); + stop_glerror(); + if (tex_env_mode != GL_MODULATE) { error = TRUE; LL_WARNS("RenderState") << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL_TEXTURE_ENV_MODE invalid: " << std::hex << tex_env_mode << std::dec << std::endl; + } } } - GLint maxTextureUnits; + GLint maxTextureUnits = 0; glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &maxTextureUnits); + stop_glerror(); static const char* label[] = { @@ -1169,30 +1265,48 @@ void LLGLState::checkTextureChannels(const std::string& msg) { gGL.getTexUnit(i)->activate(); glClientActiveTextureARB(GL_TEXTURE0_ARB+i); - + stop_glerror(); glGetIntegerv(GL_TEXTURE_STACK_DEPTH, &stackDepth); + stop_glerror(); if (stackDepth != 1) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix stack corrupted." << LL_ENDL; + + if (gDebugSession) + { + gFailLog << "Texture matrix stack corrupted." << std::endl; + } } glGetFloatv(GL_TEXTURE_MATRIX, (GLfloat*) matrix.mMatrix); + stop_glerror(); if (matrix != identity) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix in channel " << i << " corrupt." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "Texture matrix in channel " << i << " corrupt." << std::endl; + } } - for (S32 j = (i == 0 ? 1 : 0); j < 9; j++) + + for (S32 j = (i == 0 ? 1 : 0); + j < (gGLManager.mHasTextureRectangle ? 9 : 8); j++) { if (glIsEnabled(value[j])) { error = TRUE; LL_WARNS("RenderState") << "Texture channel " << i << " still has " << label[j] << " enabled." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "Texture channel " << i << " still has " << label[j] << " enabled." << std::endl; + } } + stop_glerror(); } glh::matrix4f mat; @@ -1200,20 +1314,33 @@ void LLGLState::checkTextureChannels(const std::string& msg) identity.identity(); glGetFloatv(GL_TEXTURE_MATRIX, mat.m); + stop_glerror(); if (mat != identity) { error = TRUE; LL_WARNS("RenderState") << "Texture matrix " << i << " is not identity." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "Texture matrix " << i << " is not identity." << std::endl; + } } } gGL.getTexUnit(0)->activate(); glClientActiveTextureARB(GL_TEXTURE0_ARB); + stop_glerror(); if (error) { - LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL; + if (gDebugSession) + { + ll_fail("LLGLState::checkTextureChannels failed."); + } + else + { + LL_GL_ERRS << "GL texture state corruption detected. " << msg << LL_ENDL; + } } } @@ -1233,6 +1360,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) if (active_texture != GL_TEXTURE0_ARB) { llwarns << "Client active texture corrupted: " << active_texture << llendl; + if (gDebugSession) + { + gFailLog << "Client active texture corrupted: " << active_texture << std::endl; + } error = TRUE; } @@ -1240,6 +1371,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) if (active_texture != GL_TEXTURE0_ARB) { llwarns << "Active texture corrupted: " << active_texture << llendl; + if (gDebugSession) + { + gFailLog << "Active texture corrupted: " << active_texture << std::endl; + } error = TRUE; } @@ -1276,6 +1411,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL still has " << label[j] << " enabled." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL still has " << label[j] << " enabled." << std::endl; + } } } else @@ -1284,6 +1423,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL does not have " << label[j] << " enabled." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL does not have " << label[j] << " enabled." << std::endl; + } } } } @@ -1296,6 +1439,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL still has GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl; + } } } else @@ -1304,6 +1451,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL does not have GL_TEXTURE_COORD_ARRAY enabled on channel 1." << std::endl; + } } } @@ -1313,6 +1464,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL still has GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL still has GL_TEXTURE_2D enabled on channel 1." << std::endl; + } } } else @@ -1321,6 +1476,10 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL does not have GL_TEXTURE_2D enabled on channel 1." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL does not have GL_TEXTURE_2D enabled on channel 1." << std::endl; + } } } @@ -1339,13 +1498,24 @@ void LLGLState::checkClientArrays(const std::string& msg, U32 data_mask) { error = TRUE; LL_WARNS("RenderState") << "GL still has vertex attrib array " << i << " enabled." << LL_ENDL; + if (gDebugSession) + { + gFailLog << "GL still has vertex attrib array " << i << " enabled." << std::endl; + } } } } if (error) { - LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL; + if (gDebugSession) + { + ll_fail("LLGLState::checkClientArrays failed."); + } + else + { + LL_GL_ERRS << "GL client array corruption detected. " << msg << LL_ENDL; + } } } @@ -1396,7 +1566,17 @@ LLGLState::~LLGLState() { if (gDebugGL) { - llassert_always(sStateMap[mState] == glIsEnabled(mState)); + if (!gDebugSession) + { + llassert_always(sStateMap[mState] == glIsEnabled(mState)); + } + else + { + if (sStateMap[mState] != glIsEnabled(mState)) + { + ll_fail("GL enabled state does not match expected"); + } + } } if (mIsEnabled != mWasEnabled) @@ -1708,6 +1888,7 @@ void LLGLNamePool::release(GLuint name) //static void LLGLNamePool::upkeepPools() { + LLMemType mt(LLMemType::MTYPE_UPKEEP_POOLS); for (pool_list_t::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter) { LLGLNamePool* pool = *iter; diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h index 00ff1e2f53..34dd982259 100644 --- a/indra/llrender/llgl.h +++ b/indra/llrender/llgl.h @@ -50,9 +50,17 @@ #include "glh/glh_linear.h" extern BOOL gDebugGL; +extern BOOL gDebugSession; +extern std::ofstream gFailLog; #define LL_GL_ERRS LL_ERRS("RenderState") +void ll_init_fail_log(std::string filename); + +void ll_fail(std::string msg); + +void ll_close_fail_log(); + class LLSD; // Manage GL extensions... @@ -88,6 +96,7 @@ public: BOOL mHasOcclusionQuery; BOOL mHasPointParameters; BOOL mHasDrawBuffers; + BOOL mHasTextureRectangle; // Other extensions. BOOL mHasAnisotropic; diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp index 9e34144658..830617063b 100644 --- a/indra/llrender/llglslshader.cpp +++ b/indra/llrender/llglslshader.cpp @@ -408,7 +408,15 @@ S32 LLGLSLShader::disableTexture(S32 uniform, LLTexUnit::eTextureType mode) { if (gDebugGL && gGL.getTexUnit(index)->getCurrType() != mode) { - llerrs << "Texture channel " << index << " texture type corrupted." << llendl; + if (gDebugSession) + { + gFailLog << "Texture channel " << index << " texture type corrupted." << std::endl; + ll_fail("LLGLSLShader::disableTexture failed"); + } + else + { + llerrs << "Texture channel " << index << " texture type corrupted." << llendl; + } } gGL.getTexUnit(index)->disable(); } diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp index d1efb119c6..9d2cd4867a 100644 --- a/indra/llrender/llimagegl.cpp +++ b/indra/llrender/llimagegl.cpp @@ -46,7 +46,6 @@ //---------------------------------------------------------------------------- - const F32 MIN_TEXTURE_LIFETIME = 10.f; //statics @@ -61,8 +60,9 @@ S32 LLImageGL::sCount = 0; BOOL LLImageGL::sGlobalUseAnisotropic = FALSE; F32 LLImageGL::sLastFrameTime = 0.f; - +LLImageGL* LLImageGL::sDefaultGLTexture = NULL ; std::set LLImageGL::sImageList; + //************************************************************************************** //below are functions for debug use //do not delete them even though they are not currently being used. @@ -87,9 +87,18 @@ void LLImageGL::checkTexSize() const { GLint texname; glGetIntegerv(GL_TEXTURE_BINDING_2D, &texname); + BOOL error = FALSE; if (texname != mTexName) { - llerrs << "Invalid texture bound!" << llendl; + error = TRUE; + if (gDebugSession) + { + gFailLog << "Invalid texture bound!" << std::endl; + } + else + { + llerrs << "Invalid texture bound!" << llendl; + } } stop_glerror() ; LLGLint x = 0, y = 0 ; @@ -102,7 +111,20 @@ void LLImageGL::checkTexSize() const } if(x != (mWidth >> mCurrentDiscardLevel) || y != (mHeight >> mCurrentDiscardLevel)) { - llerrs << "wrong texture size and discard level!" << llendl ; + error = TRUE; + if (gDebugSession) + { + gFailLog << "wrong texture size and discard level!" << std::endl; + } + else + { + llerrs << "wrong texture size and discard level!" << llendl ; + } + } + + if (error) + { + ll_fail("LLImageGL::checkTexSize failed."); } } } @@ -241,6 +263,7 @@ void LLImageGL::restoreGL() //---------------------------------------------------------------------------- +//for server side use only. //static BOOL LLImageGL::create(LLPointer& dest, BOOL usemipmaps) { @@ -248,12 +271,14 @@ BOOL LLImageGL::create(LLPointer& dest, BOOL usemipmaps) return TRUE; } +//for server side use only. BOOL LLImageGL::create(LLPointer& dest, U32 width, U32 height, U8 components, BOOL usemipmaps) { dest = new LLImageGL(width, height, components, usemipmaps); return TRUE; } +//for server side use only. BOOL LLImageGL::create(LLPointer& dest, const LLImageRaw* imageraw, BOOL usemipmaps) { dest = new LLImageGL(imageraw, usemipmaps); @@ -308,7 +333,6 @@ void LLImageGL::init(BOOL usemipmaps) #endif mPickMask = NULL; - mTextureState = NO_DELETE ; mTextureMemory = 0; mLastBindTime = 0.f; @@ -328,8 +352,7 @@ void LLImageGL::init(BOOL usemipmaps) mComponents = 0; mMaxDiscardLevel = MAX_DISCARD_LEVEL; - mCurrentDiscardLevel = -1; - mDontDiscard = FALSE; + mCurrentDiscardLevel = -1; mFormatInternal = -1; mFormatPrimary = (LLGLenum) 0; @@ -339,6 +362,7 @@ void LLImageGL::init(BOOL usemipmaps) mGLTextureCreated = FALSE ; mIsMask = FALSE; + mNeedsAlphaAndPickMask = TRUE ; } void LLImageGL::cleanup() @@ -439,7 +463,7 @@ void LLImageGL::dump() //---------------------------------------------------------------------------- -void LLImageGL::updateBindStats(void) const +BOOL LLImageGL::updateBindStats(S32 tex_mem) const { if (mTexName != 0) { @@ -451,28 +475,18 @@ void LLImageGL::updateBindStats(void) const { // we haven't accounted for this texture yet this frame sUniqueCount++; - updateBoundTexMem(mTextureMemory); + updateBoundTexMem(tex_mem); mLastBindTime = sLastFrameTime; + + return TRUE ; } } + return FALSE ; } -//virtual -bool LLImageGL::bindError(const S32 stage) const +F32 LLImageGL::getTimePassedSinceLastBound() { - return false; -} - -//virtual -bool LLImageGL::bindDefaultImage(const S32 stage) const -{ - return false; -} - -//virtual -void LLImageGL::forceImmediateUpdate() -{ - return ; + return sLastFrameTime - mLastBindTime ; } void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes ) @@ -502,7 +516,6 @@ void LLImageGL::setImage(const LLImageRaw* imageraw) void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) { -// LLFastTimer t1(LLFastTimer::FTM_TEMP1); llpushcallstacks ; bool is_compressed = false; if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) @@ -510,12 +523,10 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) is_compressed = true; } -// LLFastTimer t2(LLFastTimer::FTM_TEMP2); gGL.getTexUnit(0)->bind(this); if (mUseMipMaps) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP3); if (data_hasmips) { // NOTE: data_in points to largest image; smaller images @@ -532,14 +543,13 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } if (is_compressed) { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); S32 tex_size = dataFormatBytes(mFormatPrimary, w, h); glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in); stop_glerror(); } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -572,7 +582,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_GENERATE_MIPMAP_SGIS, TRUE); stop_glerror(); { -// LLFastTimer t2(LLFastTimer::FTM_TEMP4); +// LLFastTimer t2(FTM_TEMP4); if(mFormatSwapBytes) { @@ -632,7 +642,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } llassert(w > 0 && h > 0 && cur_mip_data); { -// LLFastTimer t1(LLFastTimer::FTM_TEMP4); +// LLFastTimer t1(FTM_TEMP4); if(mFormatSwapBytes) { glPixelStorei(GL_UNPACK_SWAP_BYTES, 1); @@ -680,7 +690,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) } else { -// LLFastTimer t2(LLFastTimer::FTM_TEMP5); S32 w = getWidth(); S32 h = getHeight(); if (is_compressed) @@ -719,7 +728,7 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips) llpushcallstacks ; } -BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) { llpushcallstacks ; if (!width || !height) @@ -737,7 +746,8 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 return FALSE; } - if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) + // HACK: allow the caller to explicitly force the fast path (i.e. using glTexSubImage2D here instead of calling setImage) even when updating the full texture. + if (!force_fast_update && x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight() && data_width == width && data_height == height) { setImage(datap, FALSE); } @@ -814,9 +824,9 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3 return TRUE; } -BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update) { - return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height); + return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height, force_fast_update); } // Copy sub image from frame buffer @@ -975,7 +985,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ LLImageGL::generateTextures(1, &mTexName); stop_glerror(); { -// LLFastTimer t1(LLFastTimer::FTM_TEMP6); llverify(gGL.getTexUnit(0)->bind(this)); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(LLTexUnit::getInternalType(mBindTarget), GL_TEXTURE_MAX_LEVEL, mMaxDiscardLevel-discard_level); @@ -1020,7 +1029,6 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_ mTextureMemory = getMipBytes(discard_level); sGlobalTextureMemoryInBytes += mTextureMemory; - setActive() ; // mark this as bound at this point, so we don't throw it out immediately mLastBindTime = sLastFrameTime; @@ -1036,12 +1044,7 @@ BOOL LLImageGL::setDiscardLevel(S32 discard_level) discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel); - if (mDontDiscard) - { - // don't discard! - return FALSE; - } - else if (discard_level == mCurrentDiscardLevel) + if (discard_level == mCurrentDiscardLevel) { // nothing to do return FALSE; @@ -1096,7 +1099,7 @@ BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_h return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ; } -BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) +BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const { llpushcallstacks ; if (discard_level < 0) @@ -1223,8 +1226,7 @@ void LLImageGL::destroyGLTexture() sGlobalTextureMemoryInBytes -= mTextureMemory; mTextureMemory = 0; - LLImageGL::deleteTextures(1, &mTexName); - mTextureState = DELETED ; + LLImageGL::deleteTextures(1, &mTexName); mTexName = 0; mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel. mGLTextureCreated = FALSE ; @@ -1351,6 +1353,11 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) { + if(!mNeedsAlphaAndPickMask) + { + return ; + } + if (mFormatType != GL_UNSIGNED_BYTE) { llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl; @@ -1377,7 +1384,6 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) stride = 4; break; default: - llwarns << "Cannot analyze alpha of image with primary format " << std::hex << mFormatPrimary << std::dec << llendl; return; } @@ -1409,60 +1415,14 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h) } } -BOOL LLImageGL::isDeleted() -{ - return mTextureState == DELETED ; -} - -BOOL LLImageGL::isInactive() -{ - return mTextureState == INACTIVE ; -} - -BOOL LLImageGL::isDeletionCandidate() -{ - return mTextureState == DELETION_CANDIDATE ; -} - -void LLImageGL::setDeletionCandidate() -{ - if(mTexName && (mTextureState == INACTIVE)) - { - mTextureState = DELETION_CANDIDATE ; - } -} - -void LLImageGL::forceActive() -{ - mTextureState = ACTIVE ; -} - -void LLImageGL::setActive() -{ - if(mTextureState != NO_DELETE) - { - mTextureState = ACTIVE ; - } -} - -//set the texture inactive -void LLImageGL::setInactive() -{ - if(mTexName && (mTextureState == ACTIVE) && !getBoundRecently()) - { - mTextureState = INACTIVE ; - } -} - -//set the texture to stay in memory -void LLImageGL::setNoDelete() -{ - mTextureState = NO_DELETE ; -} - //---------------------------------------------------------------------------- void LLImageGL::updatePickMask(S32 width, S32 height, const U8* data_in) { + if(!mNeedsAlphaAndPickMask) + { + return ; + } + if (mFormatType != GL_UNSIGNED_BYTE || mFormatPrimary != GL_RGBA) { diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h index 2f08a5a2cc..987a1dc538 100644 --- a/indra/llrender/llimagegl.h +++ b/indra/llrender/llimagegl.h @@ -37,7 +37,8 @@ #include "llimage.h" #include "llgltypes.h" -#include "llmemory.h" +#include "llpointer.h" +#include "llrefcount.h" #include "v2math.h" #include "llrender.h" @@ -56,7 +57,8 @@ public: static S32 dataFormatBytes(S32 dataformat, S32 width, S32 height); static S32 dataFormatComponents(S32 dataformat); - void updateBindStats(void) const; + BOOL updateBindStats(S32 tex_mem) const ; + F32 getTimePassedSinceLastBound(); // needs to be called every frame static void updateStats(F32 current_time); @@ -69,13 +71,14 @@ public: static S32 updateBoundTexMem(const S32 delta); static bool checkSize(S32 width, S32 height); - + + //for server side use only. // Not currently necessary for LLImageGL, but required in some derived classes, // so include for compatability static BOOL create(LLPointer& dest, BOOL usemipmaps = TRUE); static BOOL create(LLPointer& dest, U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); static BOOL create(LLPointer& dest, const LLImageRaw* imageraw, BOOL usemipmaps = TRUE); - + public: LLImageGL(BOOL usemipmaps = TRUE); LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps = TRUE); @@ -88,11 +91,9 @@ protected: public: virtual void dump(); // debugging info to llinfos - virtual bool bindError(const S32 stage = 0) const; - virtual bool bindDefaultImage(const S32 stage = 0) const; - virtual void forceImmediateUpdate() ; - + void setSize(S32 width, S32 height, S32 ncomponents); + void setComponents(S32 ncomponents) { mComponents = (S8)ncomponents ;} // These 3 functions currently wrap glGenTextures(), glDeleteTextures(), and glTexImage2D() // for tracking purposes and will be deprecated in the future @@ -105,16 +106,15 @@ public: BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0); void setImage(const LLImageRaw* imageraw); void setImage(const U8* data_in, BOOL data_hasmips = FALSE); - BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); - BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE); BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height); BOOL setDiscardLevel(S32 discard_level); // Read back a raw image for this discard level, if it exists - BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok); + BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; void destroyGLTexture(); void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); - void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } S32 getDiscardLevel() const { return mCurrentDiscardLevel; } S32 getMaxDiscardLevel() const { return mMaxDiscardLevel; } @@ -143,9 +143,7 @@ public: void setGLTextureCreated (bool initialized) { mGLTextureCreated = initialized; } BOOL getUseMipMaps() const { return mUseMipMaps; } - void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } - BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; } - BOOL getDontDiscard() const { return mDontDiscard; } + void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; } BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ; @@ -166,19 +164,10 @@ public: void setFilteringOption(LLTexUnit::eTextureFilterOptions option); LLTexUnit::eTextureFilterOptions getFilteringOption(void) const { return mFilterOption; } - BOOL isDeleted() ; - BOOL isInactive() ; - BOOL isDeletionCandidate(); - void setDeletionCandidate() ; - void setInactive() ; - void setActive() ; - void forceActive() ; - void setNoDelete() ; - -protected: void init(BOOL usemipmaps); virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized. Be careful when using this in derived class destructors + void setNeedsAlphaAndPickMask(BOOL need_mask) {mNeedsAlphaAndPickMask = need_mask;} public: // Various GL/Rendering options S32 mTextureMemory; @@ -192,6 +181,7 @@ private: S8 mAutoGenMips; BOOL mIsMask; + BOOL mNeedsAlphaAndPickMask; bool mGLTextureCreated ; LLGLuint mTexName; @@ -208,28 +198,15 @@ protected: S8 mComponents; S8 mMaxDiscardLevel; - S8 mDontDiscard; // Keep full res version of this image (for UI, etc) - + bool mTexOptionsDirty; LLTexUnit::eTextureAddressMode mAddressMode; // Defaults to TAM_WRAP LLTexUnit::eTextureFilterOptions mFilterOption; // Defaults to TFO_TRILINEAR - LLGLint mFormatInternal; // = GL internalformat LLGLenum mFormatPrimary; // = GL format (pixel data format) LLGLenum mFormatType; BOOL mFormatSwapBytes;// if true, use glPixelStorei(GL_UNPACK_SWAP_BYTES, 1) - -protected: - typedef enum - { - DELETED = 0, //removed from memory - DELETION_CANDIDATE, //ready to be removed from memory - INACTIVE, //not be used for the last certain period (i.e., 30 seconds). - ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). - NO_DELETE = 99 //stay in memory, can not be removed. - } LLGLTexureState; - LLGLTexureState mTextureState ; // STATICS public: @@ -247,6 +224,8 @@ public: static U32 sBindCount; // Tracks number of texture binds for current frame static U32 sUniqueCount; // Tracks number of unique texture binds for current frame static BOOL sGlobalUseAnisotropic; + static LLImageGL* sDefaultGLTexture ; + #if DEBUG_MISS BOOL mMissed; // Missed on last bind? BOOL getMissed() const { return mMissed; }; diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp index 6bb217a9c2..d577daf3f4 100644 --- a/indra/llrender/llrender.cpp +++ b/indra/llrender/llrender.cpp @@ -38,6 +38,7 @@ #include "llcubemap.h" #include "llimagegl.h" #include "llrendertarget.h" +#include "lltexture.h" LLRender gGL; @@ -177,20 +178,21 @@ void LLTexUnit::disable(void) } } -bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) +bool LLTexUnit::bind(LLTexture* texture, bool forceBind) { stop_glerror(); if (mIndex < 0) return false; gGL.flush(); - if (texture == NULL) + LLImageGL* gl_tex = NULL ; + if (texture == NULL || !(gl_tex = texture->getGLTexture())) { llwarns << "NULL LLTexUnit::bind texture" << llendl; return false; } - - if (!texture->getTexName()) //if texture does not exist + + if (!gl_tex->getTexName()) //if texture does not exist { //if deleted, will re-generate it immediately texture->forceImmediateUpdate() ; @@ -198,14 +200,57 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) return texture->bindDefaultImage(mIndex); } + if ((mCurrTexture != gl_tex->getTexName()) || forceBind) + { + activate(); + enable(gl_tex->getTarget()); + mCurrTexture = gl_tex->getTexName(); + glBindTexture(sGLTextureType[gl_tex->getTarget()], mCurrTexture); + if(gl_tex->updateBindStats(gl_tex->mTextureMemory)) + { + texture->setActive() ; + texture->updateBindStatsForTester() ; + } + mHasMipMaps = gl_tex->mHasMipMaps; + if (gl_tex->mTexOptionsDirty) + { + gl_tex->mTexOptionsDirty = false; + setTextureAddressMode(gl_tex->mAddressMode); + setTextureFilteringOption(gl_tex->mFilterOption); + } + } + return true; +} + +bool LLTexUnit::bind(LLImageGL* texture, bool forceBind) +{ + stop_glerror(); + if (mIndex < 0) return false; + + if(!texture) + { + llwarns << "NULL LLTexUnit::bind texture" << llendl; + return false; + } + + if(!texture->getTexName()) + { + if(LLImageGL::sDefaultGLTexture && LLImageGL::sDefaultGLTexture->getTexName()) + { + return bind(LLImageGL::sDefaultGLTexture) ; + } + return false ; + } + + gGL.flush(); + if ((mCurrTexture != texture->getTexName()) || forceBind) { activate(); enable(texture->getTarget()); mCurrTexture = texture->getTexName(); glBindTexture(sGLTextureType[texture->getTarget()], mCurrTexture); - texture->updateBindStats(); - texture->setActive() ; + texture->updateBindStats(texture->mTextureMemory); mHasMipMaps = texture->mHasMipMaps; if (texture->mTexOptionsDirty) { @@ -238,7 +283,7 @@ bool LLTexUnit::bind(LLCubeMap* cubeMap) mCurrTexture = cubeMap->mImages[0]->getTexName(); glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, mCurrTexture); mHasMipMaps = cubeMap->mImages[0]->mHasMipMaps; - cubeMap->mImages[0]->updateBindStats(); + cubeMap->mImages[0]->updateBindStats(cubeMap->mImages[0]->mTextureMemory); if (cubeMap->mImages[0]->mTexOptionsDirty) { cubeMap->mImages[0]->mTexOptionsDirty = false; @@ -279,15 +324,21 @@ bool LLTexUnit::bind(LLRenderTarget* renderTarget, bool bindDepth) bool LLTexUnit::bindManual(eTextureType type, U32 texture, bool hasMips) { - if (mIndex < 0 || mCurrTexture == texture) return false; + if (mIndex < 0) + { + return false; + } - gGL.flush(); - - activate(); - enable(type); - mCurrTexture = texture; - glBindTexture(sGLTextureType[type], texture); - mHasMipMaps = hasMips; + if(mCurrTexture != texture) + { + gGL.flush(); + + activate(); + enable(type); + mCurrTexture = texture; + glBindTexture(sGLTextureType[type], texture); + mHasMipMaps = hasMips; + } return true; } @@ -785,6 +836,9 @@ void LLRender::setSceneBlendType(eBlendType type) case BT_MULT: glBlendFunc(GL_DST_COLOR, GL_ZERO); break; + case BT_MULT_ALPHA: + glBlendFunc(GL_DST_ALPHA, GL_ZERO); + break; case BT_MULT_X2: glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR); break; diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h index 437c715c2f..74f87f6d40 100644 --- a/indra/llrender/llrender.h +++ b/indra/llrender/llrender.h @@ -44,13 +44,14 @@ #include "v3math.h" #include "v4coloru.h" #include "llstrider.h" -#include "llmemory.h" +#include "llpointer.h" #include "llglheaders.h" class LLVertexBuffer; class LLCubeMap; class LLImageGL; class LLRenderTarget; +class LLTexture ; class LLTexUnit { @@ -149,6 +150,7 @@ public: // Binds the LLImageGL to this texture unit // (automatically enables the unit for the LLImageGL's texture type) bool bind(LLImageGL* texture, bool forceBind = false); + bool bind(LLTexture* texture, bool forceBind = false); // Binds a cubemap to this texture unit // (automatically enables the texture unit for cubemaps) @@ -252,6 +254,7 @@ public: BT_ADD, BT_ADD_WITH_ALPHA, // Additive blend modulated by the fragment's alpha. BT_MULT, + BT_MULT_ALPHA, BT_MULT_X2, BT_REPLACE } eBlendType; diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index b7f31779ca..dc052851ca 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -36,6 +36,9 @@ #include "llrender.h" #include "llgl.h" +LLRenderTarget* LLRenderTarget::sBoundTarget = NULL; + + void check_framebuffer_status() { @@ -46,11 +49,9 @@ void check_framebuffer_status() { case GL_FRAMEBUFFER_COMPLETE_EXT: break; - case GL_FRAMEBUFFER_UNSUPPORTED_EXT: - llerrs << "WTF?" << llendl; - break; default: - llerrs << "WTF?" << llendl; + ll_fail("check_framebuffer_status failed"); + break; } } } @@ -273,6 +274,7 @@ void LLRenderTarget::release() } mSampleBuffer = NULL; + sBoundTarget = NULL; } void LLRenderTarget::bindTarget() @@ -311,6 +313,7 @@ void LLRenderTarget::bindTarget() } glViewport(0, 0, mResX, mResY); + sBoundTarget = this; } // static @@ -320,6 +323,7 @@ void LLRenderTarget::unbindTarget() { glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } + sBoundTarget = NULL; } void LLRenderTarget::clear(U32 mask_in) @@ -532,6 +536,7 @@ void LLMultisampleBuffer::bindTarget(LLRenderTarget* ref) glViewport(0, 0, mResX, mResY); + sBoundTarget = this; } void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth, BOOL stencil, LLTexUnit::eTextureType usage, BOOL use_fbo ) diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index d5d809b791..98b608f834 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -140,6 +140,8 @@ public: //one renderable attachment (i.e. color buffer, depth buffer). BOOL isComplete() const; + static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } + protected: friend class LLMultisampleBuffer; U32 mResX; @@ -153,6 +155,8 @@ protected: LLTexUnit::eTextureType mUsage; U32 mSamples; LLMultisampleBuffer* mSampleBuffer; + + static LLRenderTarget* sBoundTarget; }; diff --git a/indra/llrender/lltexture.cpp b/indra/llrender/lltexture.cpp new file mode 100644 index 0000000000..156ffb953c --- /dev/null +++ b/indra/llrender/lltexture.cpp @@ -0,0 +1,37 @@ +/** + * @file lltexture.cpp + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "linden_common.h" +#include "lltexture.h" + +//virtual +LLTexture::~LLTexture() +{ +} diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h new file mode 100644 index 0000000000..c18917b663 --- /dev/null +++ b/indra/llrender/lltexture.h @@ -0,0 +1,77 @@ +/** + * @file lltexture.h + * @brief LLTexture definition + * + * This class acts as a wrapper for OpenGL calls. + * The goal of this class is to minimize the number of api calls due to legacy rendering + * code, to define an interface for a multiple rendering API abstraction of the UI + * rendering, and to abstract out direct rendering calls in a way that is cleaner and easier to maintain. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_TEXTURE_H +#define LL_TEXTURE_H + +#include "llrefcount.h" +class LLImageGL ; +class LLTexUnit ; +class LLFontGL ; + +// +//this is an abstract class as the parent for the class LLViewerTexture +//through the following virtual functions, the class LLViewerTexture can be reached from /llrender. +// +class LLTexture : public LLRefCount +{ + friend class LLTexUnit ; + friend class LLFontGL ; + +protected: + virtual ~LLTexture(); + +public: + LLTexture(){} + + // + //interfaces to access LLViewerTexture + // + virtual bool bindDefaultImage(const S32 stage = 0) const = 0 ; + virtual void forceImmediateUpdate() = 0 ; + virtual void setActive() = 0 ; + virtual S32 getWidth(S32 discard_level = -1) const = 0 ; + virtual S32 getHeight(S32 discard_level = -1) const = 0 ; + +private: + //note: do not make this function public. + virtual LLImageGL* getGLTexture() const = 0 ; + + virtual void updateBindStatsForTester() = 0 ; +}; +#endif + diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp index 5d88ea464d..db4189dfea 100644 --- a/indra/llrender/llvertexbuffer.cpp +++ b/indra/llrender/llvertexbuffer.cpp @@ -37,7 +37,6 @@ #include "llvertexbuffer.h" // #include "llrender.h" #include "llglheaders.h" -#include "llmemory.h" #include "llmemtype.h" #include "llrender.h" @@ -117,6 +116,7 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) GL_COLOR_ARRAY, }; + BOOL error = FALSE; for (U32 i = 0; i < 4; ++i) { if (sLastMask & mask[i]) @@ -129,7 +129,15 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) { //needs to be enabled, make sure it was (DEBUG TEMPORARY) if (i > 0 && !glIsEnabled(array[i])) { - llerrs << "Bad client state! " << array[i] << " disabled." << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Bad client state! " << array[i] << " disabled." << std::endl; + } + else + { + llerrs << "Bad client state! " << array[i] << " disabled." << llendl; + } } } } @@ -141,11 +149,24 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask) } else if (gDebugGL && glIsEnabled(array[i])) { //needs to be disabled, make sure it was (DEBUG TEMPORARY) - llerrs << "Bad client state! " << array[i] << " enabled." << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Bad client state! " << array[i] << " enabled." << std::endl; + } + else + { + llerrs << "Bad client state! " << array[i] << " enabled." << llendl; + } } } } + if (error) + { + ll_fail("LLVertexBuffer::setupClientArrays failed"); + } + U32 map_tc[] = { MAP_TEXCOORD1, @@ -315,7 +336,7 @@ void LLVertexBuffer::unbind() //static void LLVertexBuffer::cleanupClass() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_CLEANUP_CLASS); unbind(); clientCopy(); // deletes GL buffers } @@ -342,7 +363,7 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) : mResized(FALSE), mDynamicSize(FALSE) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_CONSTRUCTOR); if (!sEnableVBOs) { mUsage = 0 ; @@ -379,7 +400,7 @@ S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets) //virtual LLVertexBuffer::~LLVertexBuffer() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTRUCTOR); destroyGLBuffer(); destroyGLIndices(); sCount--; @@ -459,8 +480,8 @@ void LLVertexBuffer::releaseIndices() void LLVertexBuffer::createGLBuffer() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); - + LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_VERTICES); + U32 size = getSize(); if (mGLBuffer) { @@ -491,7 +512,7 @@ void LLVertexBuffer::createGLBuffer() void LLVertexBuffer::createGLIndices() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_CREATE_INDICES); U32 size = getIndicesSize(); if (mGLIndices) @@ -523,7 +544,7 @@ void LLVertexBuffer::createGLIndices() void LLVertexBuffer::destroyGLBuffer() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_BUFFER); if (mGLBuffer) { if (useVBOs()) @@ -550,7 +571,7 @@ void LLVertexBuffer::destroyGLBuffer() void LLVertexBuffer::destroyGLIndices() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_DESTROY_INDICES); if (mGLIndices) { if (useVBOs()) @@ -577,7 +598,7 @@ void LLVertexBuffer::destroyGLIndices() void LLVertexBuffer::updateNumVerts(S32 nverts) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_VERTS); if (nverts >= 65535) { @@ -606,7 +627,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts) void LLVertexBuffer::updateNumIndices(S32 nindices) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_UPDATE_INDICES); mRequestedNumIndices = nindices; if (!mDynamicSize) { @@ -627,7 +648,7 @@ void LLVertexBuffer::updateNumIndices(S32 nindices) void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER); updateNumVerts(nverts); updateNumIndices(nindices); @@ -650,7 +671,7 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices) mRequestedNumVerts = newnverts; mRequestedNumIndices = newnindices; - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_RESIZE_BUFFER); mDynamicSize = TRUE; if (mUsage == GL_STATIC_DRAW_ARB) { //always delete/allocate static buffers on resize @@ -779,7 +800,7 @@ BOOL LLVertexBuffer::useVBOs() const // Map for data access U8* LLVertexBuffer::mapBuffer(S32 access) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_MAP_BUFFER); if (mFinal) { llerrs << "LLVertexBuffer::mapBuffer() called on a finalized buffer." << llendl; @@ -791,13 +812,19 @@ U8* LLVertexBuffer::mapBuffer(S32 access) if (!mLocked && useVBOs()) { - setBuffer(0); - mLocked = TRUE; - stop_glerror(); - mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - stop_glerror(); - mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); - stop_glerror(); + { + LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_VERTICES); + setBuffer(0); + mLocked = TRUE; + stop_glerror(); + mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + stop_glerror(); + } + { + LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES); + mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); + stop_glerror(); + } if (!mMappedData) { @@ -840,7 +867,7 @@ U8* LLVertexBuffer::mapBuffer(S32 access) void LLVertexBuffer::unmapBuffer() { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_UNMAP_BUFFER); if (mMappedData || mMappedIndexData) { if (useVBOs() && mLocked) @@ -962,7 +989,7 @@ bool LLVertexBuffer::getClothWeightStrider(LLStrider& strider, S32 in void LLVertexBuffer::setStride(S32 type, S32 new_stride) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_STRIDE); if (mNumVerts) { llerrs << "LLVertexBuffer::setOffset called with mNumVerts = " << mNumVerts << llendl; @@ -984,7 +1011,7 @@ void LLVertexBuffer::setStride(S32 type, S32 new_stride) // Set for rendering void LLVertexBuffer::setBuffer(U32 data_mask) { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_SET_BUFFER); //set up pointers if the data mask is different ... BOOL setup = (sLastMask != data_mask); @@ -1016,19 +1043,36 @@ void LLVertexBuffer::setBuffer(U32 data_mask) sIBOActive = TRUE; } + BOOL error = FALSE; if (gDebugGL) { GLint buff; glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLBuffer) { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL vertex buffer bound: " << buff << std::endl; + } + else + { + llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + } } glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: " << buff << std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } @@ -1040,13 +1084,29 @@ void LLVertexBuffer::setBuffer(U32 data_mask) glGetIntegerv(GL_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLBuffer) { - llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL vertex buffer bound: " << std::endl; + } + else + { + llerrs << "Invalid GL vertex buffer bound: " << buff << llendl; + } } glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING_ARB, &buff); if ((GLuint)buff != mGLIndices) { - llerrs << "Invalid GL index buffer bound: " << buff << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Invalid GL index buffer bound: "<< std::endl; + } + else + { + llerrs << "Invalid GL index buffer bound: " << buff << llendl; + } } } @@ -1068,10 +1128,22 @@ void LLVertexBuffer::setBuffer(U32 data_mask) if (data_mask != 0) { - llerrs << "Buffer set for rendering before being filled after resize." << llendl; + if (gDebugSession) + { + error = TRUE; + gFailLog << "Buffer set for rendering before being filled after resize." << std::endl; + } + else + { + llerrs << "Buffer set for rendering before being filled after resize." << llendl; + } } } + if (error) + { + ll_fail("LLVertexBuffer::mapBuffer failed"); + } unmapBuffer(); } else @@ -1122,7 +1194,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask) // virtual (default) void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const { - LLMemType mt(LLMemType::MTYPE_VERTEX_DATA); + LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER); stop_glerror(); U8* base = useVBOs() ? NULL : mMappedData; S32 stride = mStride; diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h index aad948e17f..b785a22976 100644 --- a/indra/llrender/llvertexbuffer.h +++ b/indra/llrender/llvertexbuffer.h @@ -39,7 +39,6 @@ #include "v4math.h" #include "v4coloru.h" #include "llstrider.h" -#include "llmemory.h" #include "llrender.h" #include #include diff --git a/indra/llui/CMakeLists.txt b/indra/llui/CMakeLists.txt index 5de8dc76af..8b0fcc68c4 100644 --- a/indra/llui/CMakeLists.txt +++ b/indra/llui/CMakeLists.txt @@ -3,7 +3,6 @@ project(llui) include(00-Common) -include(LLAudio) include(LLCommon) include(LLImage) include(LLMath) @@ -12,9 +11,9 @@ include(LLRender) include(LLWindow) include(LLVFS) include(LLXML) +include(LLXUIXML) include_directories( - ${LLAUDIO_INCLUDE_DIRS} ${LLCOMMON_INCLUDE_DIRS} ${LLIMAGE_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} @@ -23,6 +22,7 @@ include_directories( ${LLWINDOW_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} ) set(llui_SOURCE_FILES @@ -31,17 +31,26 @@ set(llui_SOURCE_FILES llcheckboxctrl.cpp llclipboard.cpp llcombobox.cpp + llconsole.cpp + llcontainerview.cpp llctrlselectioninterface.cpp lldraghandle.cpp lleditmenuhandler.cpp + llf32uictrl.cpp + llfiltereditor.cpp llfloater.cpp + llfloaterreg.cpp + llflyoutbutton.cpp llfocusmgr.cpp llfunctorregistry.cpp lliconctrl.cpp llkeywords.cpp + lllayoutstack.cpp lllineeditor.cpp + lllink.cpp llmenugl.cpp llmodaldialog.cpp + llmultifloater.cpp llmultislider.cpp llmultisliderctrl.cpp llnotifications.cpp @@ -51,27 +60,37 @@ set(llui_SOURCE_FILES llresizebar.cpp llresizehandle.cpp llresmgr.cpp - llrootview.cpp + llrngwriter.cpp llscrollbar.cpp llscrollcontainer.cpp llscrollingpanellist.cpp + llscrolllistcell.cpp + llscrolllistcolumn.cpp llscrolllistctrl.cpp + llscrolllistitem.cpp + llsdparam.cpp + llsearcheditor.cpp llslider.cpp llsliderctrl.cpp llspinctrl.cpp + llstatbar.cpp + llstatgraph.cpp + llstatview.cpp llstyle.cpp lltabcontainer.cpp - lltabcontainervertical.cpp lltextbox.cpp lltexteditor.cpp lltextparser.cpp + lltransutil.cpp llui.cpp + lluicolortable.cpp lluictrl.cpp lluictrlfactory.cpp + lluiimage.cpp lluistring.cpp - lluitrans.cpp llundo.cpp llviewborder.cpp + llviewmodel.cpp llview.cpp llviewquery.cpp ) @@ -85,19 +104,29 @@ set(llui_HEADER_FILES llcheckboxctrl.h llclipboard.h llcombobox.h + llconsole.h + llcontainerview.h llctrlselectioninterface.h lldraghandle.h lleditmenuhandler.h + llf32uictrl.h + llfiltereditor.h llfloater.h + llfloaterreg.h + llflyoutbutton.h llfocusmgr.h llfunctorregistry.h + llhandle.h llhtmlhelp.h lliconctrl.h llkeywords.h + lllayoutstack.h + lllazyvalue.h lllineeditor.h - llmemberlistener.h + lllink.h llmenugl.h llmodaldialog.h + llmultifloater.h llmultisliderctrl.h llmultislider.h llnotifications.h @@ -107,30 +136,39 @@ set(llui_HEADER_FILES llresizebar.h llresizehandle.h llresmgr.h - llrootview.h + llrngwriter.h + llsearcheditor.h llscrollbar.h llscrollcontainer.h llscrollingpanellist.h + llscrolllistcell.h + llscrolllistcolumn.h llscrolllistctrl.h + llscrolllistitem.h + llsdparam.h llsliderctrl.h llslider.h llspinctrl.h + llstatbar.h + llstatgraph.h + llstatview.h llstyle.h lltabcontainer.h - lltabcontainervertical.h lltextbox.h lltexteditor.h lltextparser.h + lltransutil.h + lluicolortable.h lluiconstants.h lluictrlfactory.h lluictrl.h lluifwd.h llui.h + lluiimage.h lluistring.h - lluitrans.h - lluixmltags.h llundo.h llviewborder.h + llviewmodel.h llview.h llviewquery.h ) @@ -148,6 +186,7 @@ target_link_libraries(llui llwindow llimage llvfs # ugh, just for LLDir + llxuixml llxml llcommon # must be after llimage, llwindow, llrender llmath diff --git a/indra/llui/llbutton.cpp b/indra/llui/llbutton.cpp index 2c2c1c25d8..98e8c9a988 100644 --- a/indra/llui/llbutton.cpp +++ b/indra/llui/llbutton.cpp @@ -45,183 +45,194 @@ #include "lluiconstants.h" #include "llresmgr.h" #include "llcriticaldamp.h" +#include "llfloater.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llwindow.h" #include "llrender.h" +#include "lluictrlfactory.h" -static LLRegisterWidget r("button"); +static LLDefaultChildRegistry::Register r("button"); // globals loaded from settings.xml -S32 LLBUTTON_ORIG_H_PAD = 6; // Pre-zoomable UI S32 LLBUTTON_H_PAD = 0; S32 LLBUTTON_V_PAD = 0; S32 BTN_HEIGHT_SMALL= 0; S32 BTN_HEIGHT = 0; -S32 BTN_GRID = 12; -S32 BORDER_SIZE = 1; - -LLButton::LLButton( const std::string& name, const LLRect& rect, const std::string& control_name, void (*click_callback)(void*), void *callback_data) -: LLUICtrl(name, rect, TRUE, NULL, NULL), - mClickedCallback( click_callback ), - mMouseDownCallback( NULL ), - mMouseUpCallback( NULL ), - mHeldDownCallback( NULL ), - mGLFont( NULL ), - mMouseDownFrame( 0 ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected( NULL ), - mImageSelected( NULL ), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mImageDisabled( NULL ), - mImageDisabledSelected( NULL ), - mToggleState( FALSE ), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), - mBorderEnabled( FALSE ), - mFlashing( FALSE ), - mHAlign( LLFontGL::HCENTER ), - mLeftHPad( LLBUTTON_H_PAD ), - mRightHPad( LLBUTTON_H_PAD ), - mHoverGlowStrength(0.15f), - mCurGlowStrength(0.f), - mNeedsHighlight(FALSE), - mCommitOnReturn(TRUE), - mImagep( NULL ) +LLButton::Params::Params() +: label_selected("label_selected"), // requires is_toggle true + label_shadow("label_shadow", true), + auto_resize("auto_resize", false), + use_ellipses("use_ellipses", false), + image_unselected("image_unselected"), + image_selected("image_selected"), + image_hover_selected("image_hover_selected"), + image_hover_unselected("image_hover_unselected"), + image_disabled_selected("image_disabled_selected"), + image_disabled("image_disabled"), + image_pressed("image_pressed"), + image_pressed_selected("image_pressed_selected"), + image_overlay("image_overlay"), + image_overlay_alignment("image_overlay_alignment", std::string("center")), + label_color("label_color"), + label_color_selected("label_color_selected"), // requires is_toggle true + label_color_disabled("label_color_disabled"), + label_color_disabled_selected("label_color_disabled_selected"), + highlight_color("highlight_color"), + image_color("image_color"), + image_color_disabled("image_color_disabled"), + image_overlay_color("image_overlay_color", LLColor4::white), + flash_color("flash_color"), + pad_right("pad_right", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + pad_left("pad_left", LLUI::sSettingGroups["config"]->getS32("ButtonHPad")), + click_callback("click_callback"), + mouse_down_callback("mouse_down_callback"), + mouse_up_callback("mouse_up_callback"), + mouse_held_callback("mouse_held_callback"), + is_toggle("is_toggle", false), + scale_image("scale_image", true), + help_url("help_url"), + hover_glow_amount("hover_glow_amount"), + commit_on_return("commit_on_return", true), + picture_style("picture_style", false) { - mUnselectedLabel = name; - mSelectedLabel = name; - - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); - - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - - init(click_callback, callback_data, NULL, control_name); + addSynonym(is_toggle, "toggle"); + held_down_delay.seconds = 0.5f; + initial_value.set(LLSD(false), false); } -LLButton::LLButton(const std::string& name, const LLRect& rect, - const std::string &unselected_image_name, - const std::string &selected_image_name, - const std::string& control_name, - void (*click_callback)(void*), - void *callback_data, - const LLFontGL *font, - const std::string& unselected_label, - const std::string& selected_label ) -: LLUICtrl(name, rect, TRUE, NULL, NULL), - mClickedCallback( click_callback ), - mMouseDownCallback( NULL ), - mMouseUpCallback( NULL ), - mHeldDownCallback( NULL ), - mGLFont( NULL ), - mMouseDownFrame( 0 ), - mHeldDownDelay( 0.5f ), // seconds until held-down callback is called - mHeldDownFrameDelay( 0 ), - mImageUnselected( NULL ), - mImageSelected( NULL ), - mImageHoverSelected( NULL ), - mImageHoverUnselected( NULL ), - mImageDisabled( NULL ), - mImageDisabledSelected( NULL ), - mToggleState( FALSE ), - mIsToggle( FALSE ), - mScaleImage( TRUE ), - mDropShadowedText( TRUE ), +LLButton::LLButton(const LLButton::Params& p) +: LLUICtrl(p), + mMouseDownFrame(0), + mMouseHeldDownCount(0), mBorderEnabled( FALSE ), mFlashing( FALSE ), - mHAlign( LLFontGL::HCENTER ), - mLeftHPad( LLBUTTON_H_PAD ), - mRightHPad( LLBUTTON_H_PAD ), - mHoverGlowStrength(0.25f), mCurGlowStrength(0.f), mNeedsHighlight(FALSE), - mCommitOnReturn(TRUE), - mImagep( NULL ) + mUnselectedLabel(p.label()), + mSelectedLabel(p.label_selected()), + mGLFont(p.font), + mHeldDownDelay(p.held_down_delay.seconds), // seconds until held-down callback is called + mHeldDownFrameDelay(p.held_down_delay.frames), + mImageUnselected(p.image_unselected), + mImageSelected(p.image_selected), + mImageDisabled(p.image_disabled), + mImageDisabledSelected(p.image_disabled_selected), + mImagePressed(p.image_pressed), + mImagePressedSelected(p.image_pressed_selected), + mImageHoverSelected(p.image_hover_selected), + mImageHoverUnselected(p.image_hover_unselected), + mUnselectedLabelColor(p.label_color()), + mSelectedLabelColor(p.label_color_selected()), + mDisabledLabelColor(p.label_color_disabled()), + mDisabledSelectedLabelColor(p.label_color_disabled_selected()), + mHighlightColor(p.highlight_color()), + mImageColor(p.image_color()), + mFlashBgColor(p.flash_color()), + mDisabledImageColor(p.image_color_disabled()), + mImageOverlay(p.image_overlay()), + mImageOverlayColor(p.image_overlay_color()), + mImageOverlayAlignment(LLFontGL::hAlignFromName(p.image_overlay_alignment)), + mIsToggle(p.is_toggle), + mScaleImage(p.scale_image), + mDropShadowedText(p.label_shadow), + mAutoResize(p.auto_resize), + mUseEllipses( p.use_ellipses ), + mHAlign(p.font_halign), + mLeftHPad(p.pad_left), + mRightHPad(p.pad_right), + mHoverGlowStrength(p.hover_glow_amount), + mCommitOnReturn(p.commit_on_return), + mFadeWhenDisabled(FALSE) { - mUnselectedLabel = unselected_label; - mSelectedLabel = selected_label; + static LLUICachedControl llbutton_orig_h_pad ("UIButtonOrigHPad", 0); + static Params default_params(LLUICtrlFactory::getDefaultParams()); - // by default, disabled color is same as enabled - mImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - mDisabledImageColor = LLUI::sColorsGroup->getColor( "ButtonImageColor" ); - - if( unselected_image_name != "" ) + //if we aren't a picture_style button set label as name if not provided + if (!p.picture_style.isProvided() || !p.picture_style) { - // user-specified image - don't use fixed borders unless requested - setImageUnselected(unselected_image_name); - setImageDisabled(unselected_image_name); - - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; + if (!p.label.isProvided()) + { + mUnselectedLabel = p.name(); + } + if (!p.label_selected.isProvided()) + { + mSelectedLabel = mUnselectedLabel.getString(); + } } - else - { - setImageUnselected(std::string("button_enabled_32x128.tga")); - setImageDisabled(std::string("button_disabled_32x128.tga")); - } - - if( selected_image_name != "" ) - { - // user-specified image - don't use fixed borders unless requested - setImageSelected(selected_image_name); - setImageDisabledSelected(selected_image_name); - - mDisabledImageColor.mV[VALPHA] = 0.5f; - mScaleImage = FALSE; - } - else - { - setImageSelected(std::string("button_enabled_selected_32x128.tga")); - setImageDisabledSelected(std::string("button_disabled_32x128.tga")); - } - - init(click_callback, callback_data, font, control_name); -} - -void LLButton::init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name) -{ - mGLFont = ( font ? font : LLFontGL::getFontSansSerif()); // Hack to make sure there is space for at least one character if (getRect().getWidth() - (mRightHPad + mLeftHPad) < mGLFont->getWidth(std::string(" "))) { // Use old defaults - mLeftHPad = LLBUTTON_ORIG_H_PAD; - mRightHPad = LLBUTTON_ORIG_H_PAD; + mLeftHPad = llbutton_orig_h_pad; + mRightHPad = llbutton_orig_h_pad; } - mCallbackUserData = callback_data; mMouseDownTimer.stop(); - setControlName(control_name, NULL); - - mUnselectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelColor" ) ); - mSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedColor" ) ); - mDisabledLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelDisabledColor" ) ); - mDisabledSelectedLabelColor = ( LLUI::sColorsGroup->getColor( "ButtonLabelSelectedDisabledColor" ) ); - mHighlightColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedFgColor" ) ); - mUnselectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonUnselectedBgColor" ) ); - mSelectedBgColor = ( LLUI::sColorsGroup->getColor( "ButtonSelectedBgColor" ) ); - mFlashBgColor = ( LLUI::sColorsGroup->getColor( "ButtonFlashBgColor" ) ); - - mImageOverlayAlignment = LLFontGL::HCENTER; - mImageOverlayColor = LLColor4::white; -} - -LLButton::~LLButton() -{ - if( hasMouseCapture() ) + if (p.help_url.isProvided()) { - gFocusMgr.setMouseCapture( NULL ); + setHelpURLCallback(p.help_url); } + + // if custom unselected button image provided... + if (p.image_unselected != default_params.image_unselected) + { + //...fade it out for disabled image by default... + if (p.image_disabled() == default_params.image_disabled() ) + { + mImageDisabled = p.image_unselected; + mFadeWhenDisabled = TRUE; + } + + if (p.image_pressed_selected == default_params.image_pressed_selected) + { + mImagePressedSelected = mImageUnselected; + } + } + + // if custom selected button image provided... + if (p.image_selected != default_params.image_selected) + { + //...fade it out for disabled image by default... + if (p.image_disabled_selected() == default_params.image_disabled_selected()) + { + mImageDisabledSelected = p.image_selected; + mFadeWhenDisabled = TRUE; + } + + if (p.image_pressed == default_params.image_pressed) + { + mImagePressed = mImageSelected; + } + } + + if (!p.image_pressed.isProvided()) + { + mImagePressed = mImageSelected; + } + + if (!p.image_pressed_selected.isProvided()) + { + mImagePressedSelected = mImageUnselected; + } + + if (mImageUnselected.isNull()) + { + llwarns << "Button: " << getName() << " with no image!" << llendl; + } + + if (p.click_callback.isProvided()) + initCommitCallback(p.click_callback, mCommitSignal); // alias -> commit_callback + if (p.mouse_down_callback.isProvided()) + initCommitCallback(p.mouse_down_callback, mMouseDownSignal); + if (p.mouse_up_callback.isProvided()) + initCommitCallback(p.mouse_up_callback, mMouseUpSignal); + if (p.mouse_held_callback.isProvided()) + initCommitCallback(p.mouse_held_callback, mHeldDownSignal); } // HACK: Committing a button is the same as instantly clicking it. @@ -229,19 +240,12 @@ LLButton::~LLButton() void LLButton::onCommit() { // WARNING: Sometimes clicking a button destroys the floater or - // panel containing it. Therefore we need to call mClickedCallback + // panel containing it. Therefore we need to call LLUICtrl::onCommit() // LAST, otherwise this becomes deleted memory. - LLUICtrl::onCommit(); - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + mMouseDownSignal(this, LLSD()); - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + mMouseUpSignal(this, LLSD()); if (getSoundFlags() & MOUSE_DOWN) { @@ -259,14 +263,50 @@ void LLButton::onCommit() } // do this last, as it can result in destroying this button - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); +} + +boost::signals2::connection LLButton::setClickedCallback( const commit_signal_t::slot_type& cb ) +{ + return mCommitSignal.connect(cb); +} +boost::signals2::connection LLButton::setMouseDownCallback( const commit_signal_t::slot_type& cb ) +{ + return mMouseDownSignal.connect(cb); +} +boost::signals2::connection LLButton::setMouseUpCallback( const commit_signal_t::slot_type& cb ) +{ + return mMouseUpSignal.connect(cb); +} +boost::signals2::connection LLButton::setHeldDownCallback( const commit_signal_t::slot_type& cb ) +{ + return mHeldDownSignal.connect(cb); } +// *TODO: Deprecate (for backwards compatability only) +boost::signals2::connection LLButton::setClickedCallback( button_callback_t cb, void* data ) +{ + return setClickedCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseDownCallback( button_callback_t cb, void* data ) +{ + return setMouseDownCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setMouseUpCallback( button_callback_t cb, void* data ) +{ + return setMouseUpCallback(boost::bind(cb, data)); +} +boost::signals2::connection LLButton::setHeldDownCallback( button_callback_t cb, void* data ) +{ + return setHeldDownCallback(boost::bind(cb, data)); +} +BOOL LLButton::postBuild() +{ + autoResize(); + return TRUE; +} BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) { BOOL handled = FALSE; @@ -278,10 +318,8 @@ BOOL LLButton::handleUnicodeCharHere(llwchar uni_char) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); + handled = TRUE; } return handled; @@ -299,10 +337,7 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask ) handled = TRUE; - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } return handled; } @@ -310,27 +345,27 @@ BOOL LLButton::handleKeyHere(KEY key, MASK mask ) BOOL LLButton::handleMouseDown(S32 x, S32 y, MASK mask) { - // Route future Mouse messages here preemptively. (Release on mouse up.) - gFocusMgr.setMouseCapture( this ); - - if (hasTabStop() && !getIsChrome()) + if (!childrenHandleMouseDown(x, y, mask)) { - setFocus(TRUE); - } + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); - if (mMouseDownCallback) - { - (*mMouseDownCallback)(mCallbackUserData); - } + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } - mMouseDownTimer.start(); - mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); - - if (getSoundFlags() & MOUSE_DOWN) - { - make_ui_sound("UISndClick"); - } + mMouseDownSignal(this, LLSD()); + mMouseDownTimer.start(); + mMouseDownFrame = (S32) LLFrameTimer::getFrameCount(); + mMouseHeldDownCount = 0; + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } return TRUE; } @@ -344,13 +379,9 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) gFocusMgr.setMouseCapture( NULL ); // Regardless of where mouseup occurs, handle callback - if (mMouseUpCallback) - { - (*mMouseUpCallback)(mCallbackUserData); - } + mMouseUpSignal(this, LLSD()); - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + resetMouseDownTimer(); // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. // If mouseup in the widget, it's been clicked @@ -366,38 +397,97 @@ BOOL LLButton::handleMouseUp(S32 x, S32 y, MASK mask) toggleState(); } - if (mClickedCallback) - { - (*mClickedCallback)( mCallbackUserData ); - } + LLUICtrl::onCommit(); } } + else + { + childrenHandleMouseUp(x, y, mask); + } return TRUE; } +BOOL LLButton::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (!childrenHandleRightMouseDown(x, y, mask)) + { + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (hasTabStop() && !getIsChrome()) + { + setFocus(TRUE); + } + +// if (pointInView(x, y)) +// { +// } + } + // send the mouse down signal + LLUICtrl::handleRightMouseDown(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way + // if they are not mouse opaque. + return TRUE; +} + +BOOL LLButton::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + // We only handle the click if the click both started and ended within us + if( hasMouseCapture() ) + { + // Always release the mouse + gFocusMgr.setMouseCapture( NULL ); + +// if (pointInView(x, y)) +// { +// mRightMouseUpSignal(this, x,y,mask); +// } + } + else + { + childrenHandleRightMouseUp(x, y, mask); + } + // send the mouse up signal + LLUICtrl::handleRightMouseUp(x,y,mask); + // *TODO: Return result of LLUICtrl call above? Should defer to base class + // but this might change the mouse handling of existing buttons in a bad way. + // if they are not mouse opaque. + return TRUE; +} + + +void LLButton::onMouseEnter(S32 x, S32 y, MASK mask) +{ + if (isInEnabledChain()) + mNeedsHighlight = TRUE; +} + +void LLButton::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mNeedsHighlight = FALSE; +} BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) { - LLMouseHandler* other_captor = gFocusMgr.getMouseCapture(); - mNeedsHighlight = other_captor == NULL || - other_captor == this || - // this following bit is to support modal dialogs - (other_captor->isView() && hasAncestor((LLView*)other_captor)); - - if (mMouseDownTimer.getStarted() && NULL != mHeldDownCallback) + if (!childrenHandleHover(x, y, mask)) { - F32 elapsed = getHeldDownTime(); - if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + if (mMouseDownTimer.getStarted()) { - mHeldDownCallback( mCallbackUserData ); + F32 elapsed = getHeldDownTime(); + if( mHeldDownDelay <= elapsed && mHeldDownFrameDelay <= (S32)LLFrameTimer::getFrameCount() - mMouseDownFrame) + { + LLSD param; + param["count"] = mMouseHeldDownCount++; + mHeldDownSignal(this, param); + } } + + // We only handle the click if the click both started and ended within us + getWindow()->setCursor(UI_CURSOR_ARROW); + lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; } - - // We only handle the click if the click both started and ended within us - getWindow()->setCursor(UI_CURSOR_ARROW); - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << llendl; - return TRUE; } @@ -405,16 +495,19 @@ BOOL LLButton::handleHover(S32 x, S32 y, MASK mask) // virtual void LLButton::draw() { - BOOL flash = FALSE; + bool flash = FALSE; + static LLUICachedControl button_flash_rate("ButtonFlashRate", 0); + static LLUICachedControl button_flash_count("ButtonFlashCount", 0); + if( mFlashing ) { F32 elapsed = mFlashingTimer.getElapsedTimeF32(); - S32 flash_count = S32(elapsed * LLUI::sConfigGroup->getF32("ButtonFlashRate") * 2.f); + S32 flash_count = S32(elapsed * button_flash_rate * 2.f); // flash on or off? - flash = (flash_count % 2 == 0) || flash_count > S32((F32)LLUI::sConfigGroup->getS32("ButtonFlashCount") * 2.f); + flash = (flash_count % 2 == 0) || flash_count > S32((F32)button_flash_count * 2.f); } - BOOL pressed_by_keyboard = FALSE; + bool pressed_by_keyboard = FALSE; if (hasFocus()) { pressed_by_keyboard = gKeyboard->getKeyDown(' ') || (mCommitOnReturn && gKeyboard->getKeyDown(KEY_RETURN)); @@ -425,24 +518,31 @@ void LLButton::draw() S32 local_mouse_y; LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y); - BOOL pressed = pressed_by_keyboard - || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)) - || mToggleState; + bool enabled = isInEnabledChain(); + + bool pressed = pressed_by_keyboard + || (hasMouseCapture() && pointInView(local_mouse_x, local_mouse_y)); + bool selected = getToggleState(); - BOOL use_glow_effect = FALSE; + bool use_glow_effect = FALSE; LLColor4 glow_color = LLColor4::white; LLRender::eBlendType glow_type = LLRender::BT_ADD_WITH_ALPHA; - if ( mNeedsHighlight ) + LLUIImage* imagep = NULL; + if (pressed) { - if (pressed) + imagep = selected ? mImagePressedSelected : mImagePressed; + } + else if ( mNeedsHighlight ) + { + if (selected) { if (mImageHoverSelected) { - mImagep = mImageHoverSelected; + imagep = mImageHoverSelected; } else { - mImagep = mImageSelected; + imagep = mImageSelected; use_glow_effect = TRUE; } } @@ -450,32 +550,18 @@ void LLButton::draw() { if (mImageHoverUnselected) { - mImagep = mImageHoverUnselected; + imagep = mImageHoverUnselected; } else { - mImagep = mImageUnselected; + imagep = mImageUnselected; use_glow_effect = TRUE; } } } - else if ( pressed ) + else { - mImagep = mImageSelected; - } - else - { - mImagep = mImageUnselected; - } - - if (mFlashing) - { - use_glow_effect = TRUE; - glow_type = LLRender::BT_ALPHA; // blend the glow - if (mNeedsHighlight) // highlighted AND flashing - glow_color = (glow_color*0.5f + mFlashBgColor*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity - else - glow_color = mFlashBgColor; + imagep = selected ? mImageSelected : mImageUnselected; } // Override if more data is available @@ -485,19 +571,31 @@ void LLButton::draw() // disabled but checked if (!mImageDisabledSelected.isNull() && - ( (getEnabled() && getTentative()) - || (!getEnabled() && pressed ) ) ) + ( (enabled && getTentative()) + || (!enabled && selected ) ) ) { - mImagep = mImageDisabledSelected; + imagep = mImageDisabledSelected; } else if (!mImageDisabled.isNull() - && !getEnabled() - && !pressed) + && !enabled + && !selected) { - mImagep = mImageDisabled; + imagep = mImageDisabled; } - if (mNeedsHighlight && !mImagep) + if (mFlashing) + { + LLColor4 flash_color = mFlashBgColor.get(); + use_glow_effect = TRUE; + glow_type = LLRender::BT_ALPHA; // blend the glow + + if (mNeedsHighlight) // highlighted AND flashing + glow_color = (glow_color*0.5f + flash_color*0.5f) % 2.0f; // average between flash and highlight colour, with sum of the opacity + else + glow_color = flash_color; + } + + if (mNeedsHighlight && !imagep) { use_glow_effect = TRUE; } @@ -506,60 +604,46 @@ void LLButton::draw() LLColor4 label_color; // label changes when button state changes, not when pressed - if ( getEnabled() ) + if ( enabled ) { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mSelectedLabelColor; + label_color = mSelectedLabelColor.get(); } else { - label_color = mUnselectedLabelColor; + label_color = mUnselectedLabelColor.get(); } } else { - if ( mToggleState ) + if ( getToggleState() ) { - label_color = mDisabledSelectedLabelColor; + label_color = mDisabledSelectedLabelColor.get(); } else { - label_color = mDisabledLabelColor; + label_color = mDisabledLabelColor.get(); } } // Unselected label assignments LLWString label; - if( mToggleState ) + if( getToggleState() ) { - if( getEnabled() || mDisabledSelectedLabel.empty() ) - { - label = mSelectedLabel; - } - else - { - label = mDisabledSelectedLabel; - } + label = mSelectedLabel; } else { - if( getEnabled() || mDisabledLabel.empty() ) - { - label = mUnselectedLabel; - } - else - { - label = mDisabledLabel; - } + label = mUnselectedLabel; } // overlay with keyboard focus border if (hasFocus()) { F32 lerp_amt = gFocusMgr.getFocusFlashAmt(); - drawBorder(gFocusMgr.getFocusColor(), llround(lerp(1.f, 3.f, lerp_amt))); + drawBorder(imagep, gFocusMgr.getFocusColor(), llround(lerp(1.f, 3.f, lerp_amt))); } if (use_glow_effect) @@ -576,25 +660,27 @@ void LLButton::draw() // Draw button image, if available. // Otherwise draw basic rectangular button. - if (mImagep.notNull()) + if (imagep != NULL) { + // apply automatic 50% alpha fade to disabled image + LLColor4 disabled_color = mFadeWhenDisabled ? mDisabledImageColor.get() % 0.5f : mDisabledImageColor.get(); if ( mScaleImage) { - mImagep->draw(getLocalRect(), getEnabled() ? mImageColor : mDisabledImageColor ); + imagep->draw(getLocalRect(), enabled ? mImageColor.get() : disabled_color ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - mImagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % mCurGlowStrength); + imagep->drawSolid(0, 0, getRect().getWidth(), getRect().getHeight(), glow_color % mCurGlowStrength); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } else { - mImagep->draw(0, 0, getEnabled() ? mImageColor : mDisabledImageColor ); + imagep->draw(0, 0, enabled ? mImageColor.get() : disabled_color ); if (mCurGlowStrength > 0.01f) { gGL.setSceneBlendType(glow_type); - mImagep->drawSolid(0, 0, glow_color % mCurGlowStrength); + imagep->drawSolid(0, 0, glow_color % mCurGlowStrength); gGL.setSceneBlendType(LLRender::BT_ALPHA); } } @@ -602,7 +688,7 @@ void LLButton::draw() else { // no image - llwarns << "No image for button " << getName() << llendl; + lldebugs << "No image for button " << getName() << llendl; // draw it in pink so we can find it gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4::pink1, FALSE); } @@ -634,8 +720,8 @@ void LLButton::draw() } // fade out overlay images on disabled buttons - LLColor4 overlay_color = mImageOverlayColor; - if (!getEnabled()) + LLColor4 overlay_color = mImageOverlayColor.get(); + if (!enabled) { overlay_color.mV[VALPHA] = 0.5f; } @@ -704,52 +790,49 @@ void LLButton::draw() x++; } + // *NOTE: mantipov: before mUseEllipses is implemented in EXT-279 U32_MAX has been passed as + // max_chars. + // LLFontGL::render expects S32 max_chars variable but process in a separate way -1 value. + // Due to U32_MAX is equal to S32 -1 value I have rest this value for non-ellipses mode. + // Not sure if it is really needed. Probably S32_MAX should be always passed as max_chars. mGLFont->render(label, 0, (F32)x, (F32)(LLBUTTON_V_PAD + y_offset), label_color, mHAlign, LLFontGL::BOTTOM, - mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NORMAL, - U32_MAX, text_width, - NULL, FALSE, FALSE); + LLFontGL::NORMAL, + mDropShadowedText ? LLFontGL::DROP_SHADOW_SOFT : LLFontGL::NO_SHADOW, + S32_MAX, text_width, + NULL, mUseEllipses); } - if (sDebugRects - || (LLView::sEditingUI && this == LLView::sEditingUIView)) - { - drawDebugRect(); - } - - // reset hover status for next frame - mNeedsHighlight = FALSE; + LLUICtrl::draw(); } -void LLButton::drawBorder(const LLColor4& color, S32 size) +void LLButton::drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size) { + if (imagep == NULL) return; if (mScaleImage) { - mImagep->drawBorder(getLocalRect(), color, size); + imagep->drawBorder(getLocalRect(), color, size); } else { - mImagep->drawBorder(0, 0, color, size); + imagep->drawBorder(0, 0, color, size); } } -void LLButton::setClickedCallback(void (*cb)(void*), void* userdata) +BOOL LLButton::getToggleState() const { - mClickedCallback = cb; - if (userdata) - { - mCallbackUserData = userdata; - } + return getValue().asBoolean(); } - void LLButton::setToggleState(BOOL b) { - if( b != mToggleState ) + if( b != getToggleState() ) { setControlValue(b); // will fire LLControlVariable callbacks (if any) - mToggleState = b; // may or may not be redundant + setValue(b); // may or may not be redundant + // Unselected label assignments + autoResize(); } } @@ -764,19 +847,11 @@ void LLButton::setFlashing( BOOL b ) BOOL LLButton::toggleState() -{ - setToggleState( !mToggleState ); - return mToggleState; -} - -void LLButton::setValue(const LLSD& value ) { - mToggleState = value.asBoolean(); -} + bool flipped = ! getToggleState(); + setToggleState(flipped); -LLSD LLButton::getValue() const -{ - return mToggleState == TRUE; + return flipped; } void LLButton::setLabel( const LLStringExplicit& label ) @@ -803,26 +878,48 @@ void LLButton::setLabelSelected( const LLStringExplicit& label ) mSelectedLabel = label; } -void LLButton::setDisabledLabel( const LLStringExplicit& label ) -{ - mDisabledLabel = label; -} - -void LLButton::setDisabledSelectedLabel( const LLStringExplicit& label ) -{ - mDisabledSelectedLabel = label; -} - void LLButton::setImageUnselected(LLPointer image) { mImageUnselected = image; + if (mImageUnselected.isNull()) + { + llwarns << "Setting default button image for: " << getName() << " to NULL" << llendl; + } } +void LLButton::autoResize() +{ + LLUIString label; + if(getToggleState()) + { + label = mSelectedLabel; + } + else + { + label = mUnselectedLabel; + } + resize(label); +} + +void LLButton::resize(LLUIString label) +{ + // get label length + S32 label_width = mGLFont->getWidth(label.getString()); + // get current btn length + S32 btn_width =getRect().getWidth(); + // check if it need resize + if (mAutoResize == TRUE) + { + if (btn_width - (mRightHPad + mLeftHPad) < label_width) + { + setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mLeft + label_width + mLeftHPad + mRightHPad , getRect().mBottom)); + } + } +} void LLButton::setImages( const std::string &image_name, const std::string &selected_name ) { - setImageUnselected(image_name); - setImageSelected(selected_name); - + setImageUnselected(LLUI::getUIImage(image_name)); + setImageSelected(LLUI::getUIImage(selected_name)); } void LLButton::setImageSelected(LLPointer image) @@ -840,26 +937,29 @@ void LLButton::setColor(const LLColor4& color) setImageColor(color); } +void LLButton::setAlpha(F32 alpha) +{ + LLColor4 temp = mImageColor.get(); + temp.setAlpha(alpha); + mImageColor.set(temp); + + temp = mDisabledImageColor.get(); + temp.setAlpha(alpha * 0.5f); + mDisabledImageColor.set(temp); +} void LLButton::setImageDisabled(LLPointer image) { mImageDisabled = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; + mFadeWhenDisabled = TRUE; } void LLButton::setImageDisabledSelected(LLPointer image) { mImageDisabledSelected = image; mDisabledImageColor = mImageColor; - mDisabledImageColor.mV[VALPHA] *= 0.5f; -} - -void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name, const LLColor4& c ) -{ - setImageDisabled(image_name); - setImageDisabledSelected(selected_name); - mDisabledImageColor = c; + mFadeWhenDisabled = TRUE; } void LLButton::setImageHoverSelected(LLPointer image) @@ -867,24 +967,11 @@ void LLButton::setImageHoverSelected(LLPointer image) mImageHoverSelected = image; } -void LLButton::setDisabledImages( const std::string &image_name, const std::string &selected_name) -{ - LLColor4 clr = mImageColor; - clr.mV[VALPHA] *= .5f; - setDisabledImages( image_name, selected_name, clr ); -} - void LLButton::setImageHoverUnselected(LLPointer image) { mImageHoverUnselected = image; } -void LLButton::setHoverImages( const std::string& image_name, const std::string& selected_name ) -{ - setImageHoverUnselected(image_name); - setImageHoverSelected(selected_name); -} - void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment, const LLColor4& color) { if (image_name.empty()) @@ -899,11 +986,9 @@ void LLButton::setImageOverlay(const std::string& image_name, LLFontGL::HAlign a } } - void LLButton::onMouseCaptureLost() { - mMouseDownTimer.stop(); - mMouseDownTimer.reset(); + resetMouseDownTimer(); } //------------------------------------------------------------------------- @@ -924,42 +1009,6 @@ S32 round_up(S32 grid, S32 value) } } -void LLButton::setImageUnselected(const std::string &image_name) -{ - setImageUnselected(LLUI::getUIImage(image_name)); - mImageUnselectedName = image_name; -} - -void LLButton::setImageSelected(const std::string &image_name) -{ - setImageSelected(LLUI::getUIImage(image_name)); - mImageSelectedName = image_name; -} - -void LLButton::setImageHoverSelected(const std::string &image_name) -{ - setImageHoverSelected(LLUI::getUIImage(image_name)); - mImageHoverSelectedName = image_name; -} - -void LLButton::setImageHoverUnselected(const std::string &image_name) -{ - setImageHoverUnselected(LLUI::getUIImage(image_name)); - mImageHoverUnselectedName = image_name; -} - -void LLButton::setImageDisabled(const std::string &image_name) -{ - setImageDisabled(LLUI::getUIImage(image_name)); - mImageDisabledName = image_name; -} - -void LLButton::setImageDisabledSelected(const std::string &image_name) -{ - setImageDisabledSelected(LLUI::getUIImage(image_name)); - mImageDisabledSelectedName = image_name; -} - void LLButton::addImageAttributeToXML(LLXMLNodePtr node, const std::string& image_name, const LLUUID& image_id, @@ -975,28 +1024,6 @@ void LLButton::addImageAttributeToXML(LLXMLNodePtr node, } } -// virtual -LLXMLNodePtr LLButton::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("label", TRUE)->setStringValue(getLabelUnselected()); - node->createChild("label_selected", TRUE)->setStringValue(getLabelSelected()); - node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mGLFont)); - node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(mHAlign)); - - addImageAttributeToXML(node,mImageUnselectedName,mImageUnselectedID,std::string("image_unselected")); - addImageAttributeToXML(node,mImageSelectedName,mImageSelectedID,std::string("image_selected")); - addImageAttributeToXML(node,mImageHoverSelectedName,mImageHoverSelectedID,std::string("image_hover_selected")); - addImageAttributeToXML(node,mImageHoverUnselectedName,mImageHoverUnselectedID,std::string("image_hover_unselected")); - addImageAttributeToXML(node,mImageDisabledName,mImageDisabledID,std::string("image_disabled")); - addImageAttributeToXML(node,mImageDisabledSelectedName,mImageDisabledSelectedID,std::string("image_disabled_selected")); - - node->createChild("scale_image", TRUE)->setBoolValue(mScaleImage); - - return node; -} - void clicked_help(void* data) { LLButton* self = (LLButton*)data; @@ -1010,114 +1037,53 @@ void clicked_help(void* data) LLUI::sHtmlHelp->show(self->getHelpURL()); } -// static -LLView* LLButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("button"); - node->getAttributeString("name", name); - - std::string label = name; - node->getAttributeString("label", label); - - std::string label_selected = label; - node->getAttributeString("label_selected", label_selected); - - LLFontGL* font = selectFont(node); - - std::string image_unselected; - if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected); - - std::string image_selected; - if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected); - - std::string image_hover_selected; - if (node->hasAttribute("image_hover_selected")) node->getAttributeString("image_hover_selected",image_hover_selected); - - std::string image_hover_unselected; - if (node->hasAttribute("image_hover_unselected")) node->getAttributeString("image_hover_unselected",image_hover_unselected); - - std::string image_disabled_selected; - if (node->hasAttribute("image_disabled_selected")) node->getAttributeString("image_disabled_selected",image_disabled_selected); - - std::string image_disabled; - if (node->hasAttribute("image_disabled")) node->getAttributeString("image_disabled",image_disabled); - - std::string image_overlay; - node->getAttributeString("image_overlay", image_overlay); - - LLFontGL::HAlign image_overlay_alignment = LLFontGL::HCENTER; - std::string image_overlay_alignment_string; - if (node->hasAttribute("image_overlay_alignment")) - { - node->getAttributeString("image_overlay_alignment", image_overlay_alignment_string); - image_overlay_alignment = LLFontGL::hAlignFromName(image_overlay_alignment_string); - } - - - LLButton *button = new LLButton(name, - LLRect(), - image_unselected, - image_selected, - LLStringUtil::null, - NULL, - parent, - font, - label, - label_selected); - - node->getAttributeS32("pad_right", button->mRightHPad); - node->getAttributeS32("pad_left", button->mLeftHPad); - - BOOL is_toggle = button->getIsToggle(); - node->getAttributeBOOL("toggle", is_toggle); - button->setIsToggle(is_toggle); - - if(image_hover_selected != LLStringUtil::null) button->setImageHoverSelected(image_hover_selected); - - if(image_hover_unselected != LLStringUtil::null) button->setImageHoverUnselected(image_hover_unselected); - - if(image_disabled_selected != LLStringUtil::null) button->setImageDisabledSelected(image_disabled_selected ); - - if(image_disabled != LLStringUtil::null) button->setImageDisabled(image_disabled); - - if(image_overlay != LLStringUtil::null) button->setImageOverlay(image_overlay, image_overlay_alignment); - - if (node->hasAttribute("halign")) - { - LLFontGL::HAlign halign = selectFontHAlign(node); - button->setHAlign(halign); - } - - if (node->hasAttribute("scale_image")) - { - BOOL needsScale = FALSE; - node->getAttributeBOOL("scale_image",needsScale); - button->setScaleImage( needsScale ); - } - - if(label.empty()) - { - button->setLabelUnselected(node->getTextContents()); - } - if (label_selected.empty()) - { - button->setLabelSelected(node->getTextContents()); - } - - if (node->hasAttribute("help_url")) - { - std::string help_url; - node->getAttributeString("help_url",help_url); - button->setHelpURLCallback(help_url); - } - - button->initFromXML(node, parent); - - return button; -} - void LLButton::setHelpURLCallback(const std::string &help_url) { mHelpURL = help_url; setClickedCallback(clicked_help,this); } + +// static +void LLButton::toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname) +{ + bool floater_vis = LLFloaterReg::toggleInstance(sdname.asString()); + LLButton* button = dynamic_cast(ctrl); + if (button) + button->setToggleState(floater_vis); +} + +// static +// Gets called once +void LLButton::setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname) +{ + LLButton* button = dynamic_cast(ctrl); + if (!button) + return; + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the button control value (toggle state) to the floater visibility control (Sets the value as well) + button->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); + // Set the clicked callback to toggle the floater + button->setClickedCallback(boost::bind(&LLFloaterReg::toggleFloaterInstance, sdname)); +} + +void LLButton::resetMouseDownTimer() +{ + mMouseDownTimer.stop(); + mMouseDownTimer.reset(); +} + + +// *TODO: Remove this function after the initial XUI XML re-export pass. +// static +void LLButton::setupParamsForExport(Params& p, LLView* parent) +{ + std::string label = p.label; + if (label.empty()) + { + //if our label is empty this is a picture style button + p.picture_style = true; + } + + LLUICtrl::setupParamsForExport(p, parent); +} diff --git a/indra/llui/llbutton.h b/indra/llui/llbutton.h index 724b77541a..e51cd443fa 100644 --- a/indra/llui/llbutton.h +++ b/indra/llui/llbutton.h @@ -39,7 +39,7 @@ #include "v4color.h" #include "llframetimer.h" #include "llfontgl.h" -#include "llimage.h" +#include "lluiimage.h" #include "lluistring.h" // @@ -53,9 +53,6 @@ extern S32 LLBUTTON_V_PAD; extern S32 BTN_HEIGHT_SMALL; extern S32 BTN_HEIGHT; -// All button widths should be rounded up to this size -extern S32 BTN_GRID; - // // Helpful functions // @@ -72,55 +69,112 @@ class LLButton : public LLUICtrl { public: - // simple button with text label - LLButton(const std::string& name, const LLRect &rect, const std::string& control_name = std::string(), - void (*on_click)(void*) = NULL, void *data = NULL); + struct Params + : public LLInitParam::Block + { + // text label + Optional label_selected; + Optional label_shadow; + Optional auto_resize; + Optional use_ellipses; - LLButton(const std::string& name, const LLRect& rect, - const std::string &unselected_image, - const std::string &selected_image, - const std::string& control_name, - void (*click_callback)(void*), - void *callback_data = NULL, - const LLFontGL* mGLFont = NULL, - const std::string& unselected_label = LLStringUtil::null, - const std::string& selected_label = LLStringUtil::null ); + // images + Optional image_unselected, + image_selected, + image_hover_selected, + image_hover_unselected, + image_disabled_selected, + image_disabled, + image_pressed, + image_pressed_selected, + image_overlay; - virtual ~LLButton(); - void init(void (*click_callback)(void*), void *callback_data, const LLFontGL* font, const std::string& control_name); + Optional image_overlay_alignment; + + // colors + Optional label_color, + label_color_selected, + label_color_disabled, + label_color_disabled_selected, + highlight_color, + image_color, + image_color_disabled, + image_overlay_color, + flash_color; + // layout + Optional pad_right; + Optional pad_left; + + // callbacks + Optional click_callback, // alias -> commit_callback + mouse_down_callback, + mouse_up_callback, + mouse_held_callback; + + // misc + Optional is_toggle, + scale_image, + commit_on_return, + picture_style; //if true, don't display label + + Optional help_url; + Optional hover_glow_amount; + Optional held_down_delay; + + Params(); + }; +protected: + friend class LLUICtrlFactory; + LLButton(const Params&); + +public: + // For backward compatability only + typedef boost::function button_callback_t; + void addImageAttributeToXML(LLXMLNodePtr node, const std::string& imageName, const LLUUID& imageID,const std::string& xmlTagName) const; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual void draw(); + /*virtual*/ BOOL postBuild(); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); virtual void onMouseCaptureLost(); virtual void onCommit(); void setUnselectedLabelColor( const LLColor4& c ) { mUnselectedLabelColor = c; } void setSelectedLabelColor( const LLColor4& c ) { mSelectedLabelColor = c; } + void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } - void setClickedCallback( void (*cb)(void *data), void* data = NULL ); // mouse down and up within button - void setMouseDownCallback( void (*cb)(void *data) ) { mMouseDownCallback = cb; } // mouse down within button - void setMouseUpCallback( void (*cb)(void *data) ) { mMouseUpCallback = cb; } // mouse up, EVEN IF NOT IN BUTTON - void setHeldDownCallback( void (*cb)(void *data) ) { mHeldDownCallback = cb; } // Mouse button held down and in button + + boost::signals2::connection setClickedCallback( const commit_signal_t::slot_type& cb ); // mouse down and up within button + boost::signals2::connection setMouseDownCallback( const commit_signal_t::slot_type& cb ); + boost::signals2::connection setMouseUpCallback( const commit_signal_t::slot_type& cb ); // mouse up, EVEN IF NOT IN BUTTON + // Passes a 'count' parameter in the commit param payload, i.e. param["count"]) + boost::signals2::connection setHeldDownCallback( const commit_signal_t::slot_type& cb ); // Mouse button held down and in button + + + // *TODO: Deprecate (for backwards compatability only) + boost::signals2::connection setClickedCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseDownCallback( button_callback_t cb, void* data ); + boost::signals2::connection setMouseUpCallback( button_callback_t cb, void* data ); + boost::signals2::connection setHeldDownCallback( button_callback_t cb, void* data ); + void setHeldDownDelay( F32 seconds, S32 frames = 0) { mHeldDownDelay = seconds; mHeldDownFrameDelay = frames; } - + F32 getHeldDownTime() const { return mMouseDownTimer.getElapsedTimeF32(); } - BOOL getIsToggle() const { return mIsToggle; } - void setIsToggle(BOOL is_toggle) { mIsToggle = is_toggle; } BOOL toggleState(); - BOOL getToggleState() const { return mToggleState; } + BOOL getToggleState() const; void setToggleState(BOOL b); void setFlashing( BOOL b ); @@ -136,31 +190,24 @@ public: void setImageColor(const std::string& color_control); void setImageColor(const LLColor4& c); - virtual void setColor(const LLColor4& c); + /*virtual*/ void setColor(const LLColor4& c); + /*virtual*/ void setAlpha(F32 alpha); void setImages(const std::string &image_name, const std::string &selected_name); - void setDisabledImages(const std::string &image_name, const std::string &selected_name); - void setDisabledImages(const std::string &image_name, const std::string &selected_name, const LLColor4& c); - void setHoverImages(const std::string &image_name, const std::string &selected_name); - void setDisabledImageColor(const LLColor4& c) { mDisabledImageColor = c; } void setDisabledSelectedLabelColor( const LLColor4& c ) { mDisabledSelectedLabelColor = c; } void setImageOverlay(const std::string& image_name, LLFontGL::HAlign alignment = LLFontGL::HCENTER, const LLColor4& color = LLColor4::white); LLPointer getImageOverlay() { return mImageOverlay; } - - - virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; + void autoResize(); // resize with label of current btn state + void resize(LLUIString label); // resize with label input void setLabel( const LLStringExplicit& label); virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); void setLabelUnselected(const LLStringExplicit& label); void setLabelSelected(const LLStringExplicit& label); - void setDisabledLabel(const LLStringExplicit& disabled_label); - void setDisabledSelectedLabel(const LLStringExplicit& disabled_label); void setDisabledLabelColor( const LLColor4& c ) { mDisabledLabelColor = c; } void setFont(const LLFontGL *font) @@ -172,19 +219,8 @@ public: void setBorderEnabled(BOOL b) { mBorderEnabled = b; } - static void onHeldDown(void *userdata); // to be called by gIdleCallbacks - void setHoverGlowStrength(F32 strength) { mHoverGlowStrength = strength; } - void setImageUnselected(const std::string &image_name); - const std::string& getImageUnselectedName() const { return mImageUnselectedName; } - void setImageSelected(const std::string &image_name); - const std::string& getImageSelectedName() const { return mImageSelectedName; } - void setImageHoverSelected(const std::string &image_name); - void setImageHoverUnselected(const std::string &image_name); - void setImageDisabled(const std::string &image_name); - void setImageDisabledSelected(const std::string &image_name); - void setImageUnselected(LLPointer image); void setImageSelected(LLPointer image); void setImageHoverSelected(LLPointer image); @@ -198,106 +234,91 @@ public: void setHelpURLCallback(const std::string &help_url); const std::string& getHelpURL() const { return mHelpURL; } + static void onHeldDown(void *userdata); // to be called by gIdleCallbacks + static void toggleFloaterAndSetToggleState(LLUICtrl* ctrl, const LLSD& sdname); + static void setFloaterToggle(LLUICtrl* ctrl, const LLSD& sdname); + protected: - - virtual void drawBorder(const LLColor4& color, S32 size); - - void setImageUnselectedID(const LLUUID &image_id); - const LLUUID& getImageUnselectedID() const { return mImageUnselectedID; } - void setImageSelectedID(const LLUUID &image_id); - const LLUUID& getImageSelectedID() const { return mImageSelectedID; } - void setImageHoverSelectedID(const LLUUID &image_id); - void setImageHoverUnselectedID(const LLUUID &image_id); - void setImageDisabledID(const LLUUID &image_id); - void setImageDisabledSelectedID(const LLUUID &image_id); const LLPointer& getImageUnselected() const { return mImageUnselected; } const LLPointer& getImageSelected() const { return mImageSelected; } LLFrameTimer mMouseDownTimer; + // If the label is empty, set the picture_style attribute + static void setupParamsForExport(Params& p, LLView* parent); private: + void drawBorder(LLUIImage* imagep, const LLColor4& color, S32 size); + void resetMouseDownTimer(); - void (*mClickedCallback)(void* data ); - void (*mMouseDownCallback)(void *data); - void (*mMouseUpCallback)(void *data); - void (*mHeldDownCallback)(void *data); - - const LLFontGL *mGLFont; +private: + commit_signal_t mMouseDownSignal; + commit_signal_t mMouseUpSignal; + commit_signal_t mHeldDownSignal; - S32 mMouseDownFrame; - F32 mHeldDownDelay; // seconds, after which held-down callbacks get called - S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called + const LLFontGL* mGLFont; + + S32 mMouseDownFrame; + S32 mMouseHeldDownCount; // Counter for parameter passed to held-down callback + F32 mHeldDownDelay; // seconds, after which held-down callbacks get called + S32 mHeldDownFrameDelay; // frames, after which held-down callbacks get called - LLPointer mImageOverlay; - LLFontGL::HAlign mImageOverlayAlignment; - LLColor4 mImageOverlayColor; + LLPointer mImageOverlay; + LLFontGL::HAlign mImageOverlayAlignment; + LLUIColor mImageOverlayColor; - LLPointer mImageUnselected; - LLUIString mUnselectedLabel; - LLColor4 mUnselectedLabelColor; + LLPointer mImageUnselected; + LLUIString mUnselectedLabel; + LLUIColor mUnselectedLabelColor; - LLPointer mImageSelected; - LLUIString mSelectedLabel; - LLColor4 mSelectedLabelColor; + LLPointer mImageSelected; + LLUIString mSelectedLabel; + LLUIColor mSelectedLabelColor; - LLPointer mImageHoverSelected; + LLPointer mImageHoverSelected; - LLPointer mImageHoverUnselected; + LLPointer mImageHoverUnselected; - LLPointer mImageDisabled; - LLUIString mDisabledLabel; - LLColor4 mDisabledLabelColor; + LLPointer mImageDisabled; + LLUIColor mDisabledLabelColor; - LLPointer mImageDisabledSelected; - LLUIString mDisabledSelectedLabel; - LLColor4 mDisabledSelectedLabelColor; + LLPointer mImageDisabledSelected; + LLUIString mDisabledSelectedLabel; + LLUIColor mDisabledSelectedLabelColor; - LLUUID mImageUnselectedID; - LLUUID mImageSelectedID; - LLUUID mImageHoverSelectedID; - LLUUID mImageHoverUnselectedID; - LLUUID mImageDisabledID; - LLUUID mImageDisabledSelectedID; - std::string mImageUnselectedName; - std::string mImageSelectedName; - std::string mImageHoverSelectedName; - std::string mImageHoverUnselectedName; - std::string mImageDisabledName; - std::string mImageDisabledSelectedName; + LLPointer mImagePressed; + LLPointer mImagePressedSelected; - LLColor4 mHighlightColor; - LLColor4 mUnselectedBgColor; - LLColor4 mSelectedBgColor; - LLColor4 mFlashBgColor; + LLUIColor mHighlightColor; + LLUIColor mFlashBgColor; - LLColor4 mImageColor; - LLColor4 mDisabledImageColor; + LLUIColor mImageColor; + LLUIColor mDisabledImageColor; - BOOL mIsToggle; - BOOL mToggleState; - BOOL mScaleImage; + BOOL mIsToggle; + BOOL mScaleImage; - BOOL mDropShadowedText; + BOOL mDropShadowedText; + BOOL mAutoResize; + BOOL mUseEllipses; + BOOL mBorderEnabled; - BOOL mBorderEnabled; + BOOL mFlashing; - BOOL mFlashing; + LLFontGL::HAlign mHAlign; + S32 mLeftHPad; + S32 mRightHPad; - LLFontGL::HAlign mHAlign; - S32 mLeftHPad; - S32 mRightHPad; + F32 mHoverGlowStrength; + F32 mCurGlowStrength; - F32 mHoverGlowStrength; - F32 mCurGlowStrength; + BOOL mNeedsHighlight; + BOOL mCommitOnReturn; + BOOL mFadeWhenDisabled; - BOOL mNeedsHighlight; - BOOL mCommitOnReturn; + std::string mHelpURL; - std::string mHelpURL; - - LLPointer mImagep; - - LLFrameTimer mFlashingTimer; + LLFrameTimer mFlashingTimer; }; + #endif // LL_LLBUTTON_H diff --git a/indra/llui/llcallbackmap.h b/indra/llui/llcallbackmap.h index eadb9c98f3..97b1e2fc50 100644 --- a/indra/llui/llcallbackmap.h +++ b/indra/llui/llcallbackmap.h @@ -30,11 +30,11 @@ * $/LicenseInfo$ */ -#ifndef LL_CALLBACK_MAP_H -#define LL_CALLBACK_MAP_H +#ifndef LLCALLBACKMAP_H +#define LLCALLBACKMAP_H #include -#include "llstring.h" +#include class LLCallbackMap { @@ -45,12 +45,19 @@ public: typedef std::map map_t; typedef map_t::iterator map_iter_t; typedef map_t::const_iterator map_const_iter_t; - + + template + static void* buildPanel(void* data) + { + T* panel = new T(); + return (void*)panel; + } + LLCallbackMap() : mCallback(NULL), mData(NULL) { } - LLCallbackMap(callback_t callback, void* data) : mCallback(callback), mData(data) { } + LLCallbackMap(callback_t callback, void* data = NULL) : mCallback(callback), mData(data) { } callback_t mCallback; void* mData; }; -#endif // LL_CALLBACK_MAP_H +#endif // LLCALLBACKMAP_H diff --git a/indra/llui/llcheckboxctrl.cpp b/indra/llui/llcheckboxctrl.cpp index eda9467d87..455b17ffc7 100644 --- a/indra/llui/llcheckboxctrl.cpp +++ b/indra/llui/llcheckboxctrl.cpp @@ -31,7 +31,6 @@ */ // The mutants are coming! - #include "linden_common.h" #include "llcheckboxctrl.h" @@ -49,101 +48,86 @@ const U32 MAX_STRING_LENGTH = 10; -static LLRegisterWidget r("check_box"); +static LLDefaultChildRegistry::Register r("check_box"); - -LLCheckBoxCtrl::LLCheckBoxCtrl(const std::string& name, const LLRect& rect, - const std::string& label, - const LLFontGL* font, - void (*commit_callback)(LLUICtrl* ctrl, void* userdata), - void* callback_user_data, - BOOL initial_value, - BOOL use_radio_style, - const std::string& control_which) -: LLUICtrl(name, rect, TRUE, commit_callback, callback_user_data, FOLLOWS_LEFT | FOLLOWS_TOP), - mTextEnabledColor( LLUI::sColorsGroup->getColor( "LabelTextColor" ) ), - mTextDisabledColor( LLUI::sColorsGroup->getColor( "LabelDisabledColor" ) ), - mRadioStyle( use_radio_style ), - mInitialValue( initial_value ), - mSetValue( initial_value ) +LLCheckBoxCtrl::Params::Params() +: text_enabled_color("text_enabled_color"), + text_disabled_color("text_disabled_color"), + initial_value("initial_value", false), + label_text("label_text"), + check_button("check_button"), + radio_style("radio_style") +{} + + +LLCheckBoxCtrl::LLCheckBoxCtrl(const LLCheckBoxCtrl::Params& p) +: LLUICtrl(p), + mTextEnabledColor(p.text_enabled_color()), + mTextDisabledColor(p.text_disabled_color()), + mFont(p.font()) { - if (font) - { - mFont = font; - } - else - { - mFont = LLFontGL::getFontSansSerifSmall(); - } + mViewModel->setValue(LLSD(p.initial_value)); + mViewModel->resetDirty(); + static LLUICachedControl llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); + static LLUICachedControl llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); + static LLUICachedControl llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); + static LLUICachedControl llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); // must be big enough to hold all children setUseBoundingRect(TRUE); - mKeyboardFocusOnClick = TRUE; - // Label (add a little space to make sure text actually renders) const S32 FUDGE = 10; - S32 text_width = mFont->getWidth( label ) + FUDGE; + S32 text_width = mFont->getWidth( p.label ) + FUDGE; S32 text_height = llround(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING, - LLCHECKBOXCTRL_VPAD + 1, // padding to get better alignment - text_width + LLCHECKBOXCTRL_HPAD, + llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, + llcheckboxctrl_vpad + 1, // padding to get better alignment + text_width + llcheckboxctrl_hpad, text_height ); // *HACK Get rid of this with SL-55508... // this allows blank check boxes and radio boxes for now - std::string local_label = label; + std::string local_label = p.label; if(local_label.empty()) { local_label = " "; } - mLabel = new LLTextBox( std::string("CheckboxCtrl Label"), label_rect, local_label, mFont ); - mLabel->setFollowsLeft(); - mLabel->setFollowsBottom(); + LLTextBox::Params tbparams = p.label_text; + tbparams.rect(label_rect); + tbparams.text(local_label); + if (p.font.isProvided()) + { + tbparams.font(p.font); + } + mLabel = LLUICtrlFactory::create (tbparams); + addChild(mLabel); // Button // Note: button cover the label by extending all the way to the right. LLRect btn_rect; btn_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD, - LLCHECKBOXCTRL_VPAD, - LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width + LLCHECKBOXCTRL_HPAD, - llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) + LLCHECKBOXCTRL_VPAD); + llcheckboxctrl_hpad, + llcheckboxctrl_vpad, + llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width + llcheckboxctrl_hpad, + llmax( text_height, llcheckboxctrl_btn_size() ) + llcheckboxctrl_vpad); std::string active_true_id, active_false_id; std::string inactive_true_id, inactive_false_id; - if (mRadioStyle) - { - active_true_id = "UIImgRadioActiveSelectedUUID"; - active_false_id = "UIImgRadioActiveUUID"; - inactive_true_id = "UIImgRadioInactiveSelectedUUID"; - inactive_false_id = "UIImgRadioInactiveUUID"; - mButton = new LLButton(std::string("Radio control button"), btn_rect, - active_false_id, active_true_id, control_which, - &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); - mButton->setDisabledImages( inactive_false_id, inactive_true_id ); - mButton->setHoverGlowStrength(0.35f); - } - else - { - active_false_id = "UIImgCheckboxActiveUUID"; - active_true_id = "UIImgCheckboxActiveSelectedUUID"; - inactive_true_id = "UIImgCheckboxInactiveSelectedUUID"; - inactive_false_id = "UIImgCheckboxInactiveUUID"; - mButton = new LLButton(std::string("Checkbox control button"), btn_rect, - active_false_id, active_true_id, control_which, - &LLCheckBoxCtrl::onButtonPress, this, LLFontGL::getFontSansSerif() ); - mButton->setDisabledImages( inactive_false_id, inactive_true_id ); - mButton->setHoverGlowStrength(0.35f); - } - mButton->setIsToggle(TRUE); - mButton->setToggleState( initial_value ); - mButton->setFollowsLeft(); - mButton->setFollowsBottom(); - mButton->setCommitOnReturn(FALSE); + + LLButton::Params params = p.check_button; + params.rect(btn_rect); + //params.control_name(p.control_name); + params.click_callback.function(boost::bind(&LLCheckBoxCtrl::onButtonPress, this, _2)); + params.commit_on_return(false); + // Checkboxes only allow boolean initial values, but buttons can + // take any LLSD. + params.initial_value(LLSD(p.initial_value)); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM); + + mButton = LLUICtrlFactory::create(params); addChild(mButton); } @@ -154,24 +138,14 @@ LLCheckBoxCtrl::~LLCheckBoxCtrl() // static -void LLCheckBoxCtrl::onButtonPress( void *userdata ) +void LLCheckBoxCtrl::onButtonPress( const LLSD& data ) { - LLCheckBoxCtrl* self = (LLCheckBoxCtrl*) userdata; + //if (mRadioStyle) + //{ + // setValue(TRUE); + //} - if (self->mRadioStyle) - { - self->setValue(TRUE); - } - - self->setControlValue(self->getValue()); - // HACK: because buttons don't normally commit - self->onCommit(); - - if (self->mKeyboardFocusOnClick) - { - self->setFocus( TRUE ); - self->onFocusReceived(); - } + onCommit(); } void LLCheckBoxCtrl::onCommit() @@ -179,6 +153,7 @@ void LLCheckBoxCtrl::onCommit() if( getEnabled() ) { setTentative(FALSE); + setControlValue(getValue()); LLUICtrl::onCommit(); } } @@ -186,7 +161,15 @@ void LLCheckBoxCtrl::onCommit() void LLCheckBoxCtrl::setEnabled(BOOL b) { LLView::setEnabled(b); - mButton->setEnabled(b); + + if (b) + { + mLabel->setColor( mTextEnabledColor.get() ); + } + else + { + mLabel->setColor( mTextDisabledColor.get() ); + } } void LLCheckBoxCtrl::clear() @@ -197,43 +180,33 @@ void LLCheckBoxCtrl::clear() void LLCheckBoxCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) { //stretch or shrink bounding rectangle of label when rebuilding UI at new scale + static LLUICachedControl llcheckboxctrl_spacing ("UICheckboxctrlSpacing", 0); + static LLUICachedControl llcheckboxctrl_hpad ("UICheckboxctrlHPad", 0); + static LLUICachedControl llcheckboxctrl_vpad ("UICheckboxctrlVPad", 0); + static LLUICachedControl llcheckboxctrl_btn_size ("UICheckboxctrlBtnSize", 0); + const S32 FUDGE = 10; S32 text_width = mFont->getWidth( mLabel->getText() ) + FUDGE; S32 text_height = llround(mFont->getLineHeight()); LLRect label_rect; label_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD + LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING, - LLCHECKBOXCTRL_VPAD, + llcheckboxctrl_hpad + llcheckboxctrl_btn_size + llcheckboxctrl_spacing, + llcheckboxctrl_vpad, text_width, text_height ); mLabel->setRect(label_rect); LLRect btn_rect; btn_rect.setOriginAndSize( - LLCHECKBOXCTRL_HPAD, - LLCHECKBOXCTRL_VPAD, - LLCHECKBOXCTRL_BTN_SIZE + LLCHECKBOXCTRL_SPACING + text_width, - llmax( text_height, LLCHECKBOXCTRL_BTN_SIZE ) ); + llcheckboxctrl_hpad, + llcheckboxctrl_vpad, + llcheckboxctrl_btn_size + llcheckboxctrl_spacing + text_width, + llmax( text_height, llcheckboxctrl_btn_size() ) ); mButton->setRect( btn_rect ); LLUICtrl::reshape(width, height, called_from_parent); } -void LLCheckBoxCtrl::draw() -{ - if (getEnabled()) - { - mLabel->setColor( mTextEnabledColor ); - } - else - { - mLabel->setColor( mTextDisabledColor ); - } - - // Draw children - LLUICtrl::draw(); -} - //virtual void LLCheckBoxCtrl::setValue(const LLSD& value ) { @@ -246,6 +219,18 @@ LLSD LLCheckBoxCtrl::getValue() const return mButton->getValue(); } +//virtual +void LLCheckBoxCtrl::setTentative(BOOL b) +{ + mButton->setTentative(b); +} + +//virtual +BOOL LLCheckBoxCtrl::getTentative() const +{ + return mButton->getTentative(); +} + void LLCheckBoxCtrl::setLabel( const LLStringExplicit& label ) { mLabel->setText( label ); @@ -264,12 +249,6 @@ BOOL LLCheckBoxCtrl::setLabelArg( const std::string& key, const LLStringExplicit return res; } -//virtual -std::string LLCheckBoxCtrl::getControlName() const -{ - return mButton->getControlName(); -} - // virtual void LLCheckBoxCtrl::setControlName(const std::string& control_name, LLView* context) { @@ -282,7 +261,7 @@ BOOL LLCheckBoxCtrl::isDirty() const { if ( mButton ) { - return (mSetValue != mButton->getToggleState()); + return mButton->isDirty(); } return FALSE; // Shouldn't get here } @@ -293,78 +272,6 @@ void LLCheckBoxCtrl::resetDirty() { if ( mButton ) { - mSetValue = mButton->getToggleState(); + mButton->resetDirty(); } } - - - -// virtual -LLXMLNodePtr LLCheckBoxCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("label", TRUE)->setStringValue(mLabel->getText()); - - std::string control_name = mButton->getControlName(); - - node->createChild("initial_value", TRUE)->setBoolValue(mInitialValue); - - node->createChild("font", TRUE)->setStringValue(LLFontGL::nameFromFont(mFont)); - - node->createChild("radio_style", TRUE)->setBoolValue(mRadioStyle); - - return node; -} - -// static -LLView* LLCheckBoxCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("checkbox"); - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLFontGL* font = LLView::selectFont(node); - - BOOL radio_style = FALSE; - node->getAttributeBOOL("radio_style", radio_style); - - LLUICtrlCallback callback = NULL; - - if (label.empty()) - { - label.assign(node->getTextContents()); - } - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - LLCheckBoxCtrl* checkbox = new LLCheckboxCtrl(name, - rect, - label, - font, - callback, - NULL, - FALSE, - radio_style); // if true, draw radio button style icons - - BOOL initial_value = checkbox->getValue().asBoolean(); - node->getAttributeBOOL("initial_value", initial_value); - - LLColor4 color; - color = LLUI::sColorsGroup->getColor( "LabelTextColor" ); - LLUICtrlFactory::getAttributeColor(node,"text_enabled_color", color); - checkbox->setEnabledColor(color); - - color = LLUI::sColorsGroup->getColor( "LabelDisabledColor" ); - LLUICtrlFactory::getAttributeColor(node,"text_disabled_color", color); - checkbox->setDisabledColor(color); - - checkbox->setValue(initial_value); - - checkbox->initFromXML(node, parent); - - return checkbox; -} diff --git a/indra/llui/llcheckboxctrl.h b/indra/llui/llcheckboxctrl.h index ff867f5193..2f8e8fdd23 100644 --- a/indra/llui/llcheckboxctrl.h +++ b/indra/llui/llcheckboxctrl.h @@ -33,24 +33,14 @@ #ifndef LL_LLCHECKBOXCTRL_H #define LL_LLCHECKBOXCTRL_H - -#include "stdtypes.h" #include "lluictrl.h" #include "llbutton.h" +#include "lltextbox.h" #include "v4color.h" -#include "llrect.h" // // Constants // -const S32 LLCHECKBOXCTRL_BTN_SIZE = 13; -const S32 LLCHECKBOXCTRL_VPAD = 2; -const S32 LLCHECKBOXCTRL_HPAD = 2; -const S32 LLCHECKBOXCTRL_SPACING = 5; -const S32 LLCHECKBOXCTRL_HEIGHT = 16; - -// Deprecated, don't use. -#define CHECKBOXCTRL_HEIGHT LLCHECKBOXCTRL_HEIGHT const BOOL RADIO_STYLE = TRUE; const BOOL CHECK_STYLE = FALSE; @@ -59,30 +49,38 @@ const BOOL CHECK_STYLE = FALSE; // Classes // class LLFontGL; -class LLTextBox; class LLViewBorder; class LLCheckBoxCtrl : public LLUICtrl { public: - LLCheckBoxCtrl(const std::string& name, const LLRect& rect, const std::string& label, - const LLFontGL* font = NULL, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void* callback_userdata = NULL, - BOOL initial_value = FALSE, - BOOL use_radio_style = FALSE, // if true, draw radio button style icons - const std::string& control_which = LLStringUtil::null); + struct Params + : public LLInitParam::Block + { + Optional text_enabled_color; + Optional text_disabled_color; + Optional initial_value; // override LLUICtrl initial_value + + Optional label_text; + Optional check_button; + + Ignored radio_style; + + Params(); + }; + virtual ~LLCheckBoxCtrl(); - // LLView interface +protected: + LLCheckBoxCtrl(const Params&); + friend class LLUICtrlFactory; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); +public: + // LLView interface virtual void setEnabled( BOOL b ); - virtual void draw(); virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); // LLUICtrl interface @@ -91,8 +89,8 @@ public: BOOL get() { return (BOOL)getValue().asBoolean(); } void set(BOOL value) { setValue(value); } - virtual void setTentative(BOOL b) { mButton->setTentative(b); } - virtual BOOL getTentative() const { return mButton->getTentative(); } + virtual void setTentative(BOOL b); + virtual BOOL getTentative() const; virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); @@ -108,10 +106,11 @@ public: void setLabel( const LLStringExplicit& label ); std::string getLabel() const; + void setFont( const LLFontGL* font ) { mFont = font; } + virtual void setControlName(const std::string& control_name, LLView* context); - virtual std::string getControlName() const; - static void onButtonPress(void *userdata); + void onButtonPress(const LLSD& data); virtual BOOL isDirty() const; // Returns TRUE if the user has modified this control. virtual void resetDirty(); // Clear dirty state @@ -121,19 +120,10 @@ protected: LLButton* mButton; LLTextBox* mLabel; const LLFontGL* mFont; - LLColor4 mTextEnabledColor; - LLColor4 mTextDisabledColor; - BOOL mRadioStyle; - BOOL mInitialValue; // Value set in constructor - BOOL mSetValue; // Value set programmatically - BOOL mKeyboardFocusOnClick; - LLViewBorder* mBorder; + + LLUIColor mTextEnabledColor; + LLUIColor mTextDisabledColor; }; -// HACK: fix old capitalization problem -//typedef LLCheckBoxCtrl LLCheckboxCtrl; -#define LLCheckboxCtrl LLCheckBoxCtrl - - #endif // LL_LLCHECKBOXCTRL_H diff --git a/indra/llui/llclipboard.cpp b/indra/llui/llclipboard.cpp index 2cb8197a67..cbd4cb380f 100644 --- a/indra/llui/llclipboard.cpp +++ b/indra/llui/llclipboard.cpp @@ -61,6 +61,12 @@ void LLClipboard::copyFromSubstring(const LLWString &src, S32 pos, S32 len, cons LLView::getWindow()->copyTextToClipboard( mString ); } +void LLClipboard::copyFromString(const LLWString &src, const LLUUID& source_id ) +{ + mSourceID = source_id; + mString = src; + LLView::getWindow()->copyTextToClipboard( mString ); +} const LLWString& LLClipboard::getPasteWString( LLUUID* source_id ) { diff --git a/indra/llui/llclipboard.h b/indra/llui/llclipboard.h index 034a7a6aeb..d7ffeb33e0 100644 --- a/indra/llui/llclipboard.h +++ b/indra/llui/llclipboard.h @@ -50,6 +50,7 @@ public: (i.e. X11/Linux). */ void copyFromSubstring(const LLWString ©_from, S32 pos, S32 len, const LLUUID& source_id = LLUUID::null ); + void copyFromString(const LLWString ©_from, const LLUUID& source_id = LLUUID::null ); BOOL canPasteString() const; const LLWString& getPasteWString(LLUUID* source_id = NULL); diff --git a/indra/llui/llcombobox.cpp b/indra/llui/llcombobox.cpp index 28a05c13f5..ac56d15d1b 100644 --- a/indra/llui/llcombobox.cpp +++ b/indra/llui/llcombobox.cpp @@ -48,65 +48,131 @@ #include "llwindow.h" #include "llfloater.h" #include "llscrollbar.h" +#include "llscrolllistcell.h" +#include "llscrolllistitem.h" #include "llcontrol.h" #include "llfocusmgr.h" #include "lllineeditor.h" #include "v2math.h" +#include "lluictrlfactory.h" // Globals S32 LLCOMBOBOX_HEIGHT = 0; S32 LLCOMBOBOX_WIDTH = 0; S32 MAX_COMBO_WIDTH = 500; -static LLRegisterWidget r1("combo_box"); +static LLDefaultChildRegistry::Register register_combo_box("combo_box"); -LLComboBox::LLComboBox( const std::string& name, const LLRect &rect, const std::string& label, - void (*commit_callback)(LLUICtrl*,void*), - void *callback_userdata - ) -: LLUICtrl(name, rect, TRUE, commit_callback, callback_userdata, - FOLLOWS_LEFT | FOLLOWS_TOP), - mTextEntry(NULL), - mArrowImage(NULL), - mAllowTextEntry(FALSE), - mMaxChars(20), - mTextEntryTentative(TRUE), - mListPosition(BELOW), - mPrearrangeCallback( NULL ), - mTextEntryCallback( NULL ), - mLabel(label) +void LLComboBox::PreferredPositionValues::declareValues() { - // Always use text box - // Text label button - mButton = new LLButton(mLabel, - LLRect(), - LLStringUtil::null, - NULL, this); - mButton->setImageUnselected(std::string("square_btn_32x128.tga")); - mButton->setImageSelected(std::string("square_btn_selected_32x128.tga")); - mButton->setImageDisabled(std::string("square_btn_32x128.tga")); - mButton->setImageDisabledSelected(std::string("square_btn_selected_32x128.tga")); - mButton->setScaleImage(TRUE); + declare("above", ABOVE); + declare("below", BELOW); +} - mButton->setMouseDownCallback(onButtonDown); - mButton->setFont(LLFontGL::getFontSansSerifSmall()); - mButton->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_RIGHT); - mButton->setHAlign( LLFontGL::LEFT ); - mButton->setRightHPad(2); +LLComboBox::ItemParams::ItemParams() +: label("label") +{ +} + + +LLComboBox::Params::Params() +: allow_text_entry("allow_text_entry", false), + show_text_as_tentative("show_text_as_tentative", true), + max_chars("max_chars", 20), + list_position("list_position", BELOW), + items("item"), + combo_button("combo_button"), + combo_list("combo_list"), + combo_editor("combo_editor"), + drop_down_button("drop_down_button") +{ + addSynonym(items, "combo_item"); +} + + +LLComboBox::LLComboBox(const LLComboBox::Params& p) +: LLUICtrl(p), + mTextEntry(NULL), + mTextEntryTentative(p.show_text_as_tentative), + mHasAutocompletedText(false), + mAllowTextEntry(p.allow_text_entry), + mMaxChars(p.max_chars), + mPrearrangeCallback(p.prearrange_callback()), + mTextEntryCallback(p.text_entry_callback()), + mSelectionCallback(p.selection_callback()), + mListPosition(p.list_position), + mLastSelectedIndex(-1) +{ + // Text label button + + LLButton::Params button_params = (mAllowTextEntry ? p.combo_button : p.drop_down_button); + button_params.mouse_down_callback.function(boost::bind(&LLComboBox::onButtonDown, this)); + button_params.follows.flags(FOLLOWS_LEFT|FOLLOWS_BOTTOM|FOLLOWS_RIGHT); + button_params.rect(p.rect); + + if(mAllowTextEntry) + { + button_params.pad_right(2); + } + + mArrowImage = button_params.image_unselected; + + mButton = LLUICtrlFactory::create(button_params); + + + if(mAllowTextEntry) + { + //redo to compensate for button hack that leaves space for a character + //unless it is a "minimal combobox"(drop down) + mButton->setRightHPad(2); + } addChild(mButton); - // disallow multiple selection - mList = new LLScrollListCtrl(std::string("ComboBox"), LLRect(), - &LLComboBox::onItemSelected, this, FALSE); - mList->setVisible(FALSE); - mList->setBgWriteableColor( LLColor4(1,1,1,1) ); - mList->setCommitOnKeyboardMovement(FALSE); + LLScrollListCtrl::Params params = p.combo_list; + params.name("ComboBox"); + params.commit_callback.function(boost::bind(&LLComboBox::onItemSelected, this, _2)); + params.visible(false); + params.commit_on_keyboard_movement(false); + + mList = LLUICtrlFactory::create(params); addChild(mList); - mArrowImage = LLUI::sImageProvider->getUIImage("combobox_arrow.tga"); - mButton->setImageOverlay("combobox_arrow.tga", LLFontGL::RIGHT); + for (LLInitParam::ParamIterator::const_iterator it = p.items().begin(); + it != p.items().end(); + ++it) + { + LLScrollListItem::Params item_params = *it; + if (it->label.isProvided()) + { + item_params.columns.add().value(it->label()); + } - updateLayout(); + mList->addRow(item_params); + } + + createLineEditor(p); + + setTopLostCallback(boost::bind(&LLComboBox::hideList, this)); +} + +void LLComboBox::initFromParams(const LLComboBox::Params& p) +{ + LLUICtrl::initFromParams(p); + + if (!acceptsTextInput() && mLabel.empty()) + { + selectFirstItem(); + } +} + +// virtual +BOOL LLComboBox::postBuild() +{ + if (mControlVariable) + { + setValue(mControlVariable->getValue()); // selects the appropriate item + } + return TRUE; } @@ -115,105 +181,6 @@ LLComboBox::~LLComboBox() // children automatically deleted, including mMenu, mButton } -// virtual -LLXMLNodePtr LLComboBox::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - // Attributes - - node->createChild("allow_text_entry", TRUE)->setBoolValue(mAllowTextEntry); - - node->createChild("max_chars", TRUE)->setIntValue(mMaxChars); - - // Contents - - std::vector data_list = mList->getAllData(); - std::vector::iterator data_itor; - for (data_itor = data_list.begin(); data_itor != data_list.end(); ++data_itor) - { - LLScrollListItem* item = *data_itor; - LLScrollListCell* cell = item->getColumn(0); - if (cell) - { - LLXMLNodePtr item_node = node->createChild("combo_item", FALSE); - LLSD value = item->getValue(); - item_node->createChild("value", TRUE)->setStringValue(value.asString()); - item_node->createChild("enabled", TRUE)->setBoolValue(item->getEnabled()); - item_node->setStringValue(cell->getValue().asString()); - } - } - - return node; -} - -// static -LLView* LLComboBox::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("combo_box"); - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL allow_text_entry = FALSE; - node->getAttributeBOOL("allow_text_entry", allow_text_entry); - - S32 max_chars = 20; - node->getAttributeS32("max_chars", max_chars); - - LLUICtrlCallback callback = NULL; - - LLComboBox* combo_box = new LLComboBox(name, - rect, - label, - callback, - NULL); - combo_box->setAllowTextEntry(allow_text_entry, max_chars); - - combo_box->initFromXML(node, parent); - - const std::string& contents = node->getValue(); - - if (contents.find_first_not_of(" \n\t") != contents.npos) - { - llerrs << "Legacy combo box item format used! Please convert to tags!" << llendl; - } - else - { - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("combo_item")) - { - std::string label = child->getTextContents(); - - std::string value = label; - child->getAttributeString("value", value); - - combo_box->add(label, LLSD(value) ); - } - } - } - - // if providing user text entry or descriptive label - // don't select an item under the hood - if (!combo_box->acceptsTextInput() && combo_box->mLabel.empty()) - { - combo_box->selectFirstItem(); - } - - return combo_box; -} - -void LLComboBox::setEnabled(BOOL enabled) -{ - LLView::setEnabled(enabled); - mButton->setEnabled(enabled); -} void LLComboBox::clear() { @@ -223,9 +190,8 @@ void LLComboBox::clear() } mButton->setLabelSelected(LLStringUtil::null); mButton->setLabelUnselected(LLStringUtil::null); - mButton->setDisabledLabel(LLStringUtil::null); - mButton->setDisabledSelectedLabel(LLStringUtil::null); mList->deselectAllItems(); + mLastSelectedIndex = -1; } void LLComboBox::onCommit() @@ -237,6 +203,7 @@ void LLComboBox::onCommit() mTextEntry->setValue(getSimple()); mTextEntry->setTentative(FALSE); } + setControlValue(getValue()); LLUICtrl::onCommit(); } @@ -330,6 +297,7 @@ BOOL LLComboBox::setSimple(const LLStringExplicit& name) if (found) { setLabel(name); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -346,6 +314,7 @@ void LLComboBox::setValue(const LLSD& value) { setLabel( mList->getSelectedItemLabel() ); } + mLastSelectedIndex = mList->getFirstSelectedIndex(); } } @@ -393,6 +362,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name) if (mList->selectItemByLabel(name, FALSE)) { mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } else { @@ -402,10 +372,7 @@ void LLComboBox::setLabel(const LLStringExplicit& name) if (!mAllowTextEntry) { - mButton->setLabelUnselected(name); - mButton->setLabelSelected(name); - mButton->setDisabledLabel(name); - mButton->setDisabledSelectedLabel(name); + mButton->setLabel(name); } } @@ -421,6 +388,7 @@ BOOL LLComboBox::remove(const std::string& name) { mList->deleteSingleItem(mList->getItemIndex(item)); } + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -431,6 +399,7 @@ BOOL LLComboBox::remove(S32 index) if (index < mList->getItemCount()) { mList->deleteSingleItem(index); + setLabel(mList->getSelectedItemLabel()); return TRUE; } return FALSE; @@ -448,41 +417,31 @@ void LLComboBox::onFocusLost() LLUICtrl::onFocusLost(); } -void LLComboBox::onLostTop() -{ - hideList(); -} - - void LLComboBox::setButtonVisible(BOOL visible) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); + mButton->setVisible(visible); if (mTextEntry) { LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); if (visible) { - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; } //mTextEntry->setRect(text_entry_rect); mTextEntry->reshape(text_entry_rect.getWidth(), text_entry_rect.getHeight(), TRUE); } } -void LLComboBox::draw() -{ - mButton->setEnabled(getEnabled() /*&& !mList->isEmpty()*/); - - // Draw children normally - LLUICtrl::draw(); -} - BOOL LLComboBox::setCurrentByIndex( S32 index ) { BOOL found = mList->selectNthItem( index ); if (found) { setLabel(mList->getSelectedItemLabel()); + mLastSelectedIndex = index; } return found; } @@ -498,54 +457,48 @@ S32 LLComboBox::getCurrentIndex() const } -void LLComboBox::updateLayout() +void LLComboBox::createLineEditor(const LLComboBox::Params& p) { + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); LLRect rect = getLocalRect(); if (mAllowTextEntry) { - S32 shadow_size = LLUI::sConfigGroup->getS32("DropShadowButton"); - mButton->setRect(LLRect( getRect().getWidth() - llmax(8,mArrowImage->getWidth()) - 2 * shadow_size, + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + S32 shadow_size = drop_shadow_button; + mButton->setRect(LLRect( getRect().getWidth() - llmax(8,arrow_width) - 2 * shadow_size, rect.mTop, rect.mRight, rect.mBottom)); mButton->setTabStop(FALSE); + mButton->setHAlign(LLFontGL::HCENTER); - if (!mTextEntry) - { - LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); - text_entry_rect.mRight -= llmax(8,mArrowImage->getWidth()) + 2 * LLUI::sConfigGroup->getS32("DropShadowButton"); - // clear label on button - std::string cur_label = mButton->getLabelSelected(); - mTextEntry = new LLLineEditor(std::string("combo_text_entry"), - text_entry_rect, - LLStringUtil::null, - LLFontGL::getFontSansSerifSmall(), - mMaxChars, - onTextCommit, - onTextEntry, - NULL, - this); - mTextEntry->setSelectAllonFocusReceived(TRUE); - mTextEntry->setHandleEditKeysDirectly(TRUE); - mTextEntry->setCommitOnFocusLost(FALSE); - mTextEntry->setText(cur_label); - mTextEntry->setIgnoreTab(TRUE); - mTextEntry->setFollowsAll(); - addChild(mTextEntry); - } - else - { - mTextEntry->setVisible(TRUE); - mTextEntry->setMaxTextLength(mMaxChars); - } + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; + // clear label on button + std::string cur_label = mButton->getLabelSelected(); + LLLineEditor::Params params = p.combo_editor; + params.rect(text_entry_rect); + params.default_text(LLStringUtil::null); + params.max_length_bytes(mMaxChars); + params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); + params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); + params.focus_lost_callback(NULL); + params.handle_edit_keys_directly(true); + params.commit_on_focus_lost(false); + params.follows.flags(FOLLOWS_ALL); + mTextEntry = LLUICtrlFactory::create (params); + mTextEntry->setText(cur_label); + mTextEntry->setIgnoreTab(TRUE); + addChild(mTextEntry); // clear label on button setLabel(LLStringUtil::null); mButton->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP | FOLLOWS_RIGHT); } - else if (!mAllowTextEntry) + else { mButton->setRect(rect); mButton->setTabStop(TRUE); + mButton->setHAlign(LLFontGL::LEFT); if (mTextEntry) { @@ -664,91 +617,91 @@ void LLComboBox::showList() void LLComboBox::hideList() { - //*HACK: store the original value explicitly somewhere, not just in label - std::string orig_selection = mAllowTextEntry ? mTextEntry->getText() : mButton->getLabelSelected(); - - // assert selection in list - mList->selectItemByLabel(orig_selection, FALSE); - - mButton->setToggleState(FALSE); - mList->setVisible(FALSE); - mList->highlightNthItem(-1); - - setUseBoundingRect(FALSE); - if( gFocusMgr.getTopCtrl() == this ) + if (mList->getVisible()) { - gFocusMgr.setTopCtrl(NULL); + // assert selection in list + mList->selectNthItem(mLastSelectedIndex); + + mButton->setToggleState(FALSE); + mList->setVisible(FALSE); + mList->mouseOverHighlightNthItem(-1); + + setUseBoundingRect(FALSE); + if( gFocusMgr.getTopCtrl() == this ) + { + gFocusMgr.setTopCtrl(NULL); + } } } +void LLComboBox::onButtonDown() +{ + if (!mList->getVisible()) + { + // this might change selection, so do it first + prearrangeList(); + + // highlight the last selected item from the original selection before potentially selecting a new item + // as visual cue to original value of combo box + LLScrollListItem* last_selected_item = mList->getLastSelectedItem(); + if (last_selected_item) + { + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); + } + + if (mList->getItemCount() != 0) + { + showList(); + } + + setFocus( TRUE ); + + // pass mouse capture on to list if button is depressed + if (mButton->hasMouseCapture()) + { + gFocusMgr.setMouseCapture(mList); + } + } + else + { + hideList(); + } + +} + + //------------------------------------------------------------------ // static functions //------------------------------------------------------------------ -// static -void LLComboBox::onButtonDown(void *userdata) +void LLComboBox::onItemSelected(const LLSD& data) { - LLComboBox *self = (LLComboBox *)userdata; + const std::string name = mList->getSelectedItemLabel(); - if (!self->mList->getVisible()) - { - LLScrollListItem* last_selected_item = self->mList->getLastSelectedItem(); - if (last_selected_item) - { - // highlight the original selection before potentially selecting a new item - self->mList->highlightNthItem(self->mList->getItemIndex(last_selected_item)); - } - - if( self->mPrearrangeCallback ) - { - self->mPrearrangeCallback( self, self->mCallbackUserData ); - } - - if (self->mList->getItemCount() != 0) - { - self->showList(); - } - - self->setFocus( TRUE ); - - // pass mouse capture on to list if button is depressed - if (self->mButton->hasMouseCapture()) - { - gFocusMgr.setMouseCapture(self->mList); - } - } - else - { - self->hideList(); - } - -} - -// static -void LLComboBox::onItemSelected(LLUICtrl* item, void *userdata) -{ - // Note: item is the LLScrollListCtrl - LLComboBox *self = (LLComboBox *) userdata; - - const std::string name = self->mList->getSelectedItemLabel(); - - S32 cur_id = self->getCurrentIndex(); + S32 cur_id = getCurrentIndex(); + mLastSelectedIndex = cur_id; if (cur_id != -1) { - self->setLabel(name); + setLabel(name); - if (self->mAllowTextEntry) + if (mAllowTextEntry) { - gFocusMgr.setKeyboardFocus(self->mTextEntry); - self->mTextEntry->selectAll(); + gFocusMgr.setKeyboardFocus(mTextEntry); + mTextEntry->selectAll(); } } // hiding the list reasserts the old value stored in the text editor/dropdown button - self->hideList(); + hideList(); // commit does the reverse, asserting the value in the list - self->onCommit(); + onCommit(); + + // call the callback if it exists + if(mSelectionCallback) + { + mSelectionCallback(this, data); + } } BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) @@ -778,12 +731,7 @@ BOOL LLComboBox::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_re msg = tool_tip; // Convert rect local to screen coordinates - localPointToScreen( - 0, 0, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - localPointToScreen( - getRect().getWidth(), getRect().getHeight(), - &(sticky_rect_screen->mRight), &(sticky_rect_screen->mTop) ); + *sticky_rect_screen = calcScreenRect(); } return TRUE; } @@ -804,7 +752,7 @@ BOOL LLComboBox::handleKeyHere(KEY key, MASK mask) if (last_selected_item) { // highlight the original selection before potentially selecting a new item - mList->highlightNthItem(mList->getItemIndex(last_selected_item)); + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); } result = mList->handleKeyHere(key, mask); @@ -838,7 +786,7 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) if (last_selected_item) { // highlight the original selection before potentially selecting a new item - mList->highlightNthItem(mList->getItemIndex(last_selected_item)); + mList->mouseOverHighlightNthItem(mList->getItemIndex(last_selected_item)); } result = mList->handleUnicodeCharHere(uni_char); if (mList->getLastSelectedItem() != last_selected_item) @@ -850,46 +798,37 @@ BOOL LLComboBox::handleUnicodeCharHere(llwchar uni_char) return result; } -void LLComboBox::setAllowTextEntry(BOOL allow, S32 max_chars, BOOL set_tentative) -{ - mAllowTextEntry = allow; - mTextEntryTentative = set_tentative; - mMaxChars = max_chars; - - updateLayout(); -} - void LLComboBox::setTextEntry(const LLStringExplicit& text) { if (mTextEntry) { mTextEntry->setText(text); + mHasAutocompletedText = FALSE; updateSelection(); } } -//static -void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) +void LLComboBox::onTextEntry(LLLineEditor* line_editor) { - LLComboBox* self = (LLComboBox*)user_data; - - if (self->mTextEntryCallback) + if (mTextEntryCallback != NULL) { - (*self->mTextEntryCallback)(line_editor, self->mCallbackUserData); + (mTextEntryCallback)(line_editor, LLSD()); } KEY key = gKeyboard->currentKey(); if (key == KEY_BACKSPACE || key == KEY_DELETE) { - if (self->mList->selectItemByLabel(line_editor->getText(), FALSE)) + if (mList->selectItemByLabel(line_editor->getText(), FALSE)) { line_editor->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } else { - line_editor->setTentative(self->mTextEntryTentative); - self->mList->deselectAllItems(); + line_editor->setTentative(mTextEntryTentative); + mList->deselectAllItems(); + mLastSelectedIndex = -1; } return; } @@ -902,17 +841,14 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) if (key == KEY_DOWN) { - self->setCurrentByIndex(llmin(self->getItemCount() - 1, self->getCurrentIndex() + 1)); - if (!self->mList->getVisible()) + setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1)); + if (!mList->getVisible()) { - if( self->mPrearrangeCallback ) - { - self->mPrearrangeCallback( self, self->mCallbackUserData ); - } + prearrangeList(); - if (self->mList->getItemCount() != 0) + if (mList->getItemCount() != 0) { - self->showList(); + showList(); } } line_editor->selectAll(); @@ -920,17 +856,14 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) } else if (key == KEY_UP) { - self->setCurrentByIndex(llmax(0, self->getCurrentIndex() - 1)); - if (!self->mList->getVisible()) + setCurrentByIndex(llmax(0, getCurrentIndex() - 1)); + if (!mList->getVisible()) { - if( self->mPrearrangeCallback ) - { - self->mPrearrangeCallback( self, self->mCallbackUserData ); - } + prearrangeList(); - if (self->mList->getItemCount() != 0) + if (mList->getItemCount() != 0) { - self->showList(); + showList(); } } line_editor->selectAll(); @@ -939,7 +872,7 @@ void LLComboBox::onTextEntry(LLLineEditor* line_editor, void* user_data) else { // RN: presumably text entry - self->updateSelection(); + updateSelection(); } } @@ -948,7 +881,7 @@ void LLComboBox::updateSelection() LLWString left_wstring = mTextEntry->getWText().substr(0, mTextEntry->getCursor()); // user-entered portion of string, based on assumption that any selected // text was a result of auto-completion - LLWString user_wstring = mTextEntry->hasSelection() ? left_wstring : mTextEntry->getWText(); + LLWString user_wstring = mHasAutocompletedText ? left_wstring : mTextEntry->getWText(); std::string full_string = mTextEntry->getText(); // go ahead and arrange drop down list on first typed character, even @@ -956,23 +889,15 @@ void LLComboBox::updateSelection() // callback to populate content if( mTextEntry->getWText().size() == 1 ) { - if (mPrearrangeCallback) - { - mPrearrangeCallback( this, mCallbackUserData ); - } + prearrangeList(mTextEntry->getText()); } if (mList->selectItemByLabel(full_string, FALSE)) { mTextEntry->setTentative(FALSE); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } - else if (!mList->selectItemByPrefix(left_wstring, FALSE)) - { - mList->deselectAllItems(); - mTextEntry->setText(wstring_to_utf8str(user_wstring)); - mTextEntry->setTentative(mTextEntryTentative); - } - else + else if (mList->selectItemByPrefix(left_wstring, FALSE)) { LLWString selected_item = utf8str_to_wstring(mList->getSelectedItemLabel()); LLWString wtext = left_wstring + selected_item.substr(left_wstring.size(), selected_item.size()); @@ -980,17 +905,25 @@ void LLComboBox::updateSelection() mTextEntry->setSelection(left_wstring.size(), mTextEntry->getWText().size()); mTextEntry->endSelection(); mTextEntry->setTentative(FALSE); + mHasAutocompletedText = TRUE; + mLastSelectedIndex = mList->getFirstSelectedIndex(); + } + else // no matching items found + { + mList->deselectAllItems(); + mTextEntry->setText(wstring_to_utf8str(user_wstring)); // removes text added by autocompletion + mTextEntry->setTentative(mTextEntryTentative); + mHasAutocompletedText = FALSE; + mLastSelectedIndex = -1; } } -//static -void LLComboBox::onTextCommit(LLUICtrl* caller, void* user_data) +void LLComboBox::onTextCommit(const LLSD& data) { - LLComboBox* self = (LLComboBox*)user_data; - std::string text = self->mTextEntry->getText(); - self->setSimple(text); - self->onCommit(); - self->mTextEntry->selectAll(); + std::string text = mTextEntry->getText(); + setSimple(text); + onCommit(); + mTextEntry->selectAll(); } void LLComboBox::setFocus(BOOL b) @@ -1007,6 +940,14 @@ void LLComboBox::setFocus(BOOL b) } } +void LLComboBox::prearrangeList(std::string filter) +{ + if (mPrearrangeCallback) + { + mPrearrangeCallback(this, LLSD(filter)); + } +} + //============================================================================ // LLCtrlListInterface functions @@ -1061,6 +1002,7 @@ BOOL LLComboBox::setCurrentByID(const LLUUID& id) if (found) { setLabel(mList->getSelectedItemLabel()); + mLastSelectedIndex = mList->getFirstSelectedIndex(); } return found; @@ -1114,155 +1056,3 @@ BOOL LLComboBox::selectItemRange( S32 first, S32 last ) { return mList->selectItemRange(first, last); } - - -// -// LLFlyoutButton -// - -static LLRegisterWidget r2("flyout_button"); - -const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24; - -LLFlyoutButton::LLFlyoutButton( - const std::string& name, - const LLRect &rect, - const std::string& label, - void (*commit_callback)(LLUICtrl*, void*) , - void *callback_userdata) -: LLComboBox(name, rect, LLStringUtil::null, commit_callback, callback_userdata), - mToggleState(FALSE), - mActionButton(NULL) -{ - // Always use text box - // Text label button - mActionButton = new LLButton(label, - LLRect(), LLStringUtil::null, NULL, this); - mActionButton->setScaleImage(TRUE); - - mActionButton->setClickedCallback(onActionButtonClick); - mActionButton->setFollowsAll(); - mActionButton->setHAlign( LLFontGL::HCENTER ); - mActionButton->setLabel(label); - addChild(mActionButton); - - mActionButtonImage = LLUI::getUIImage("flyout_btn_left.tga"); - mExpanderButtonImage = LLUI::getUIImage("flyout_btn_right.tga"); - mActionButtonImageSelected = LLUI::getUIImage("flyout_btn_left_selected.tga"); - mExpanderButtonImageSelected = LLUI::getUIImage("flyout_btn_right_selected.tga"); - mActionButtonImageDisabled = LLUI::getUIImage("flyout_btn_left_disabled.tga"); - mExpanderButtonImageDisabled = LLUI::getUIImage("flyout_btn_right_disabled.tga"); - - mActionButton->setImageSelected(mActionButtonImageSelected); - mActionButton->setImageUnselected(mActionButtonImage); - mActionButton->setImageDisabled(mActionButtonImageDisabled); - mActionButton->setImageDisabledSelected(LLPointer(NULL)); - - mButton->setImageSelected(mExpanderButtonImageSelected); - mButton->setImageUnselected(mExpanderButtonImage); - mButton->setImageDisabled(mExpanderButtonImageDisabled); - mButton->setImageDisabledSelected(LLPointer(NULL)); - mButton->setRightHPad(6); - - updateLayout(); -} - -//static -LLView* LLFlyoutButton::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name = "flyout_button"; - node->getAttributeString("name", name); - - std::string label(""); - node->getAttributeString("label", label); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - LLUICtrlCallback callback = NULL; - - LLFlyoutButton* flyout_button = new LLFlyoutButton(name, - rect, - label, - callback, - NULL); - - std::string list_position; - node->getAttributeString("list_position", list_position); - if (list_position == "below") - { - flyout_button->mListPosition = BELOW; - } - else if (list_position == "above") - { - flyout_button->mListPosition = ABOVE; - } - - - flyout_button->initFromXML(node, parent); - - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("flyout_button_item")) - { - std::string label = child->getTextContents(); - - std::string value = label; - child->getAttributeString("value", value); - - flyout_button->add(label, LLSD(value) ); - } - } - - flyout_button->updateLayout(); - - return flyout_button; -} - -void LLFlyoutButton::updateLayout() -{ - LLComboBox::updateLayout(); - - mButton->setOrigin(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, 0); - mButton->reshape(FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight()); - mButton->setFollows(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); - mButton->setTabStop(FALSE); - mButton->setImageOverlay(mListPosition == BELOW ? "down_arrow.tga" : "up_arrow.tga", LLFontGL::RIGHT); - - mActionButton->setOrigin(0, 0); - mActionButton->reshape(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH, getRect().getHeight()); -} - -//static -void LLFlyoutButton::onActionButtonClick(void *user_data) -{ - LLFlyoutButton* buttonp = (LLFlyoutButton*)user_data; - // remember last list selection? - buttonp->mList->deselect(); - buttonp->onCommit(); -} - -void LLFlyoutButton::draw() -{ - mActionButton->setToggleState(mToggleState); - mButton->setToggleState(mToggleState); - - //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or - // the label reflects the last selected item, for now we have to manually remove the label - mButton->setLabel(LLStringUtil::null); - LLComboBox::draw(); -} - -void LLFlyoutButton::setEnabled(BOOL enabled) -{ - mActionButton->setEnabled(enabled); - LLComboBox::setEnabled(enabled); -} - - -void LLFlyoutButton::setToggleState(BOOL state) -{ - mToggleState = state; -} - diff --git a/indra/llui/llcombobox.h b/indra/llui/llcombobox.h index 33e1baa748..4becda195f 100644 --- a/indra/llui/llcombobox.h +++ b/indra/llui/llcombobox.h @@ -39,16 +39,14 @@ #include "llbutton.h" #include "lluictrl.h" #include "llctrlselectioninterface.h" -#include "llimagegl.h" #include "llrect.h" +#include "llscrolllistctrl.h" +#include "lllineeditor.h" +#include // Classes class LLFontGL; -class LLButton; -class LLSquareButton; -class LLScrollListCtrl; -class LLLineEditor; class LLViewBorder; extern S32 LLCOMBOBOX_HEIGHT; @@ -57,32 +55,62 @@ extern S32 LLCOMBOBOX_WIDTH; class LLComboBox : public LLUICtrl, public LLCtrlListInterface { -public: +public: typedef enum e_preferred_position { ABOVE, BELOW } EPreferredPosition; - LLComboBox( - const std::string& name, - const LLRect &rect, - const std::string& label, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void *callback_userdata = NULL - ); + struct PreferredPositionValues : public LLInitParam::TypeValuesHelper + { + static void declareValues(); + }; + + + struct ItemParams : public LLInitParam::Block + { + Optional label; + ItemParams(); + }; + + struct Params + : public LLInitParam::Block + { + Optional allow_text_entry, + show_text_as_tentative; + Optional max_chars; + Optional prearrange_callback, + text_entry_callback, + selection_callback; + + Optional list_position; + + // components + Optional combo_button; + Optional combo_list; + Optional combo_editor; + + Optional drop_down_button; + + Multiple items; + + Params(); + }; + + virtual ~LLComboBox(); + /*virtual*/ BOOL postBuild(); + +protected: + friend class LLUICtrlFactory; + LLComboBox(const Params&); + void initFromParams(const Params&); + void prearrangeList(std::string filter = ""); +public: // LLView interface - - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - - virtual void draw(); virtual void onFocusLost(); - virtual void onLostTop(); - - virtual void setEnabled(BOOL enabled); virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); virtual BOOL handleKeyHere(KEY key, MASK mask); @@ -105,7 +133,6 @@ public: // items, this is just the label. virtual LLSD getValue() const; - void setAllowTextEntry(BOOL allow, S32 max_chars = 50, BOOL make_tentative = TRUE); void setTextEntry(const LLStringExplicit& text); LLScrollListItem* add(const std::string& name, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); // add item "name" to menu @@ -134,7 +161,7 @@ public: BOOL setCurrentByIndex( S32 index ); S32 getCurrentIndex() const; - virtual void updateLayout(); + void createLineEditor(const Params&); //======================================================================== LLCtrlSelectionInterface* getSelectionInterface() { return (LLCtrlSelectionInterface*)this; }; @@ -170,66 +197,38 @@ public: void* getCurrentUserdata(); - void setPrearrangeCallback( void (*cb)(LLUICtrl*,void*) ) { mPrearrangeCallback = cb; } - void setTextEntryCallback( void (*cb)(LLLineEditor*, void*) ) { mTextEntryCallback = cb; } + void setPrearrangeCallback( commit_callback_t cb ) { mPrearrangeCallback = cb; } + void setTextEntryCallback( commit_callback_t cb ) { mTextEntryCallback = cb; } + void setSelectionCallback( commit_callback_t cb ) { mSelectionCallback = cb; } void setButtonVisible(BOOL visible); - static void onButtonDown(void *userdata); - static void onItemSelected(LLUICtrl* item, void *userdata); - static void onTextEntry(LLLineEditor* line_editor, void* user_data); - static void onTextCommit(LLUICtrl* caller, void* user_data); + void onButtonDown(); + void onItemSelected(const LLSD& data); + void onTextCommit(const LLSD& data); void updateSelection(); virtual void showList(); virtual void hideList(); - + + virtual void onTextEntry(LLLineEditor* line_editor); + protected: LLButton* mButton; + LLLineEditor* mTextEntry; LLScrollListCtrl* mList; EPreferredPosition mListPosition; LLPointer mArrowImage; - std::string mLabel; + LLUIString mLabel; + BOOL mHasAutocompletedText; private: - S32 mButtonPadding; - LLLineEditor* mTextEntry; BOOL mAllowTextEntry; S32 mMaxChars; BOOL mTextEntryTentative; - void (*mPrearrangeCallback)(LLUICtrl*,void*); - void (*mTextEntryCallback)(LLLineEditor*, void*); + commit_callback_t mPrearrangeCallback; + commit_callback_t mTextEntryCallback; + commit_callback_t mSelectionCallback; + S32 mLastSelectedIndex; }; - -class LLFlyoutButton : public LLComboBox -{ -public: - LLFlyoutButton( - const std::string& name, - const LLRect &rect, - const std::string& label, - void (*commit_callback)(LLUICtrl*, void*) = NULL, - void *callback_userdata = NULL); - - virtual void updateLayout(); - virtual void draw(); - virtual void setEnabled(BOOL enabled); - - void setToggleState(BOOL state); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - static void onActionButtonClick(void *userdata); - static void onSelectAction(LLUICtrl* ctrl, void *userdata); - -protected: - LLButton* mActionButton; - LLPointer mActionButtonImage; - LLPointer mExpanderButtonImage; - LLPointer mActionButtonImageSelected; - LLPointer mExpanderButtonImageSelected; - LLPointer mActionButtonImageDisabled; - LLPointer mExpanderButtonImageDisabled; - BOOL mToggleState; -}; - #endif diff --git a/indra/llui/llconsole.cpp b/indra/llui/llconsole.cpp new file mode 100644 index 0000000000..1e8b8a5537 --- /dev/null +++ b/indra/llui/llconsole.cpp @@ -0,0 +1,393 @@ +/** + * @file llconsole.cpp + * @brief a scrolling console output device + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +//#include "llviewerprecompiledheaders.h" +#include "linden_common.h" + +#include "llconsole.h" + +// linden library includes +#include "llmath.h" +//#include "llviewercontrol.h" +#include "llcriticaldamp.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llui.h" +#include "lluiimage.h" +//#include "llviewerimage.h" +//#include "llviewerimagelist.h" +//#include "llviewerwindow.h" +#include "llsd.h" +#include "llfontgl.h" +#include "llmath.h" + +//#include "llstartup.h" + +// Used for LCD display +extern void AddNewDebugConsoleToLCD(const LLWString &newLine); + +LLConsole* gConsole = NULL; // Created and destroyed in LLViewerWindow. + +const F32 FADE_DURATION = 2.f; +const S32 MIN_CONSOLE_WIDTH = 200; + +LLConsole::LLConsole(const LLConsole::Params& p) +: LLView(p), + LLFixedBuffer(p.max_lines), + mLinePersistTime(p.persist_time), // seconds + mFont(p.font) +{ + if (p.font_size_index.isProvided()) + { + setFontSize(p.font_size_index); + } + mFadeTime = mLinePersistTime - FADE_DURATION; + setMaxLines(LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")); +} + +void LLConsole::setLinePersistTime(F32 seconds) +{ + mLinePersistTime = seconds; + mFadeTime = mLinePersistTime - FADE_DURATION; +} + +void LLConsole::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + S32 new_width = llmax(50, llmin(getRect().getWidth(), width)); + S32 new_height = llmax(llfloor(mFont->getLineHeight()) + 15, llmin(getRect().getHeight(), height)); + + if ( mConsoleWidth == new_width + && mConsoleHeight == new_height ) + { + return; + } + + mConsoleWidth = new_width; + mConsoleHeight= new_height; + + LLView::reshape(new_width, new_height, called_from_parent); + + for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) + { + (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); + } +} + +void LLConsole::setFontSize(S32 size_index) +{ + if (-1 == size_index) + { + mFont = LLFontGL::getFontMonospace(); + } + else if (0 == size_index) + { + mFont = LLFontGL::getFontSansSerif(); + } + else if (1 == size_index) + { + mFont = LLFontGL::getFontSansSerifBig(); + } + else + { + mFont = LLFontGL::getFontSansSerifHuge(); + } + + for(paragraph_t::iterator paragraph_it = mParagraphs.begin(); paragraph_it != mParagraphs.end(); paragraph_it++) + { + (*paragraph_it).updateLines((F32)getRect().getWidth(), mFont, true); + } +} + +void LLConsole::draw() +{ + LLGLSUIDefault gls_ui; + + // skip lines added more than mLinePersistTime ago + F32 cur_time = mTimer.getElapsedTimeF32(); + + F32 skip_time = cur_time - mLinePersistTime; + F32 fade_time = cur_time - mFadeTime; + + if (mParagraphs.empty()) //No text to draw. + { + return; + } + + U32 num_lines=0; + + paragraph_t::reverse_iterator paragraph_it; + paragraph_it = mParagraphs.rbegin(); + U32 paragraph_num=mParagraphs.size(); + + while (!mParagraphs.empty() && paragraph_it != mParagraphs.rend()) + { + num_lines += (*paragraph_it).mLines.size(); + if(num_lines > mMaxLines + || ( (mLinePersistTime > (F32)0.f) && ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime) <= (F32)0.f)) + { //All lines above here are done. Lose them. + for (U32 i=0;igetF32("ConsoleBackgroundOpacity"), 0.f, 1.f); +// LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); + LLColor4 color = LLUIColorTable::instance().getColor("ConsoleBackground"); + color.mV[VALPHA] *= console_opacity; + + F32 line_height = mFont->getLineHeight(); + + for(paragraph_it = mParagraphs.rbegin(); paragraph_it != mParagraphs.rend(); paragraph_it++) + { + S32 target_height = llfloor( (*paragraph_it).mLines.size() * line_height + 8); + S32 target_width = llfloor( (*paragraph_it).mMaxWidth +15); + + y_pos += ((*paragraph_it).mLines.size()) * line_height; + imagep->drawSolid(-14, (S32)(y_pos + line_height - target_height), target_width, target_height, color); + + F32 y_off=0; + + F32 alpha; + + if ((mLinePersistTime > 0.f) && ((*paragraph_it).mAddTime < fade_time)) + { + alpha = ((*paragraph_it).mAddTime - skip_time)/(mLinePersistTime - mFadeTime); + } + else + { + alpha = 1.0f; + } + + if( alpha > 0.f ) + { + for (lines_t::iterator line_it=(*paragraph_it).mLines.begin(); + line_it != (*paragraph_it).mLines.end(); + line_it ++) + { + for (line_color_segments_t::iterator seg_it = (*line_it).mLineColorSegments.begin(); + seg_it != (*line_it).mLineColorSegments.end(); + seg_it++) + { + mFont->render((*seg_it).mText, 0, (*seg_it).mXPosition - 8, y_pos - y_off, + LLColor4( + (*seg_it).mColor.mV[VRED], + (*seg_it).mColor.mV[VGREEN], + (*seg_it).mColor.mV[VBLUE], + (*seg_it).mColor.mV[VALPHA]*alpha), + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::NORMAL, + LLFontGL::DROP_SHADOW, + S32_MAX, + target_width + ); + } + y_off += line_height; + } + } + y_pos += 8; + } +} + +void LLConsole::addLine(const std::string& utf8line) +{ + LLWString wline = utf8str_to_wstring(utf8line); + addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f)); +} + +void LLConsole::addLine(const LLWString& wline) +{ + addLine(wline, 0.f, LLColor4(1.f, 1.f, 1.f, 1.f)); +} + +void LLConsole::addLine(const std::string& utf8line, F32 size, const LLColor4 &color) +{ + LLWString wline = utf8str_to_wstring(utf8line); + addLine(wline, size, color); +} + +//Generate highlight color segments for this paragraph. Pass in default color of paragraph. +void LLConsole::Paragraph::makeParagraphColorSegments (const LLColor4 &color) +{ + LLSD paragraph_color_segments; + LLColor4 lcolor=color; + + paragraph_color_segments[0]["text"] =wstring_to_utf8str(mParagraphText); + LLSD color_sd = color.getValue(); + paragraph_color_segments[0]["color"]=color_sd; + + for(LLSD::array_const_iterator color_segment_it = paragraph_color_segments.beginArray(); + color_segment_it != paragraph_color_segments.endArray(); + ++color_segment_it) + { + LLSD color_llsd = (*color_segment_it)["color"]; + std::string color_str = (*color_segment_it)["text"].asString(); + + ParagraphColorSegment color_segment; + + color_segment.mColor.setValue(color_llsd); + color_segment.mNumChars = color_str.length(); + + mParagraphColorSegments.push_back(color_segment); + } +} + +//Called when a paragraph is added to the console or window is resized. +void LLConsole::Paragraph::updateLines(F32 screen_width, const LLFontGL* font, bool force_resize) +{ + if ( !force_resize ) + { + if ( mMaxWidth >= 0.0f + && mMaxWidth < screen_width ) + { + return; //No resize required. + } + } + + screen_width = screen_width - 30; //Margin for small windows. + + if ( mParagraphText.empty() + || mParagraphColorSegments.empty() + || font == NULL) + { + return; //Not enough info to complete. + } + + mLines.clear(); //Chuck everything. + mMaxWidth = 0.0f; + + paragraph_color_segments_t::iterator current_color = mParagraphColorSegments.begin(); + U32 current_color_length = (*current_color).mNumChars; + + S32 paragraph_offset = 0; //Offset into the paragraph text. + + // Wrap lines that are longer than the view is wide. + while( paragraph_offset < (S32)mParagraphText.length() ) + { + S32 skip_chars; // skip '\n' + // Figure out if a word-wrapped line fits here. + LLWString::size_type line_end = mParagraphText.find_first_of(llwchar('\n'), paragraph_offset); + if (line_end != LLWString::npos) + { + skip_chars = 1; // skip '\n' + } + else + { + line_end = mParagraphText.size(); + skip_chars = 0; + } + + U32 drawable = font->maxDrawableChars(mParagraphText.c_str()+paragraph_offset, screen_width, line_end - paragraph_offset, TRUE); + + if (drawable != 0) + { + F32 x_position = 0; //Screen X position of text. + + mMaxWidth = llmax( mMaxWidth, (F32)font->getWidth( mParagraphText.substr( paragraph_offset, drawable ).c_str() ) ); + Line line; + + U32 left_to_draw = drawable; + U32 drawn = 0; + + while (left_to_draw >= current_color_length + && current_color != mParagraphColorSegments.end() ) + { + LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, current_color_length ); + line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. + (*current_color).mColor, + x_position ) ); + + x_position += font->getWidth( color_text.c_str() ); //Set up next screen position. + + drawn += current_color_length; + left_to_draw -= current_color_length; + + current_color++; //Goto next paragraph color record. + + if (current_color != mParagraphColorSegments.end()) + { + current_color_length = (*current_color).mNumChars; + } + } + + if (left_to_draw > 0 && current_color != mParagraphColorSegments.end() ) + { + LLWString color_text = mParagraphText.substr( paragraph_offset + drawn, left_to_draw ); + + line.mLineColorSegments.push_back( LineColorSegment( color_text, //Append segment to line. + (*current_color).mColor, + x_position ) ); + + current_color_length -= left_to_draw; + } + mLines.push_back(line); //Append line to paragraph line list. + } + paragraph_offset += (drawable + skip_chars); + } +} + +//Pass in the string and the default color for this block of text. +LLConsole::Paragraph::Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width) + : mParagraphText(str), mAddTime(add_time), mMaxWidth(-1) +{ + makeParagraphColorSegments(color); + updateLines( screen_width, font ); +} + +void LLConsole::addLine(const LLWString& wline, F32 size, const LLColor4 &color) +{ + Paragraph paragraph(wline, color, mTimer.getElapsedTimeF32(), mFont, (F32)getRect().getWidth() ); + + mParagraphs.push_back ( paragraph ); + +#if LL_WINDOWS && LL_LCD_COMPILE + // add to LCD screen + AddNewDebugConsoleToLCD(wline); +#endif +} diff --git a/indra/llui/llconsole.h b/indra/llui/llconsole.h new file mode 100644 index 0000000000..56e1614948 --- /dev/null +++ b/indra/llui/llconsole.h @@ -0,0 +1,163 @@ +/** + * @file llconsole.h + * @brief a simple console-style output device + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCONSOLE_H +#define LL_LLCONSOLE_H + +#include "llfixedbuffer.h" +#include "llview.h" +#include "v4color.h" +#include + +class LLFontGL; +class LLSD; + +class LLConsole : public LLFixedBuffer, public LLView +{ +public: + typedef enum e_font_size + { + MONOSPACE = -1, + SMALL = 0, + BIG = 1 + } EFontSize; + + struct Params : public LLInitParam::Block + { + Optional max_lines; + Optional persist_time; + Optional font_size_index; + Params() + : max_lines("max_lines", LLUI::sSettingGroups["config"]->getS32("ConsoleMaxLines")), + persist_time("persist_time", 0.f), // forever + font_size_index("font_size_index") + { + mouse_opaque(false); + } + }; +protected: + LLConsole(const Params&); + friend class LLUICtrlFactory; + +public: + //A paragraph color segment defines the color of text in a line + //of text that was received for console display. It has no + //notion of line wraps, screen position, or the text it contains. + //It is only the number of characters that are a color and the + //color. + struct ParagraphColorSegment + { + S32 mNumChars; + LLColor4 mColor; + }; + + //A line color segment is a chunk of text, the color associated + //with it, and the X Position it was calculated to begin at + //on the screen. X Positions are re-calculated if the + //screen changes size. + class LineColorSegment + { + public: + LineColorSegment(LLWString text, LLColor4 color, F32 xpos) : mText(text), mColor(color), mXPosition(xpos) {} + public: + LLWString mText; + LLColor4 mColor; + F32 mXPosition; + }; + + typedef std::list line_color_segments_t; + + //A line is composed of one or more color segments. + class Line + { + public: + line_color_segments_t mLineColorSegments; + }; + + typedef std::list lines_t; + typedef std::list paragraph_color_segments_t; + + //A paragraph is a processed element containing the entire text of the + //message (used for recalculating positions on screen resize) + //The time this message was added to the console output + //The visual screen width of the longest line in this block + //And a list of one or more lines which are used to display this message. + class Paragraph + { + public: + Paragraph (LLWString str, const LLColor4 &color, F32 add_time, const LLFontGL* font, F32 screen_width); + void makeParagraphColorSegments ( const LLColor4 &color); + void updateLines ( F32 screen_width, const LLFontGL* font, bool force_resize=false ); + public: + LLWString mParagraphText; //The entire text of the paragraph + paragraph_color_segments_t mParagraphColorSegments; + F32 mAddTime; //Time this paragraph was added to the display. + F32 mMaxWidth; //Width of the widest line of text in this paragraph. + lines_t mLines; + + }; + + //The console contains a deque of paragraphs which represent the individual messages. + typedef std::deque paragraph_t; + paragraph_t mParagraphs; + + ~LLConsole(){}; + + // each line lasts this long after being added + void setLinePersistTime(F32 seconds); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + // -1 = monospace, 0 means small, font size = 1 means big + void setFontSize(S32 size_index); + + void addLine(const std::string& utf8line, F32 size, const LLColor4 &color); + void addLine(const LLWString& wline, F32 size, const LLColor4 &color); + + // Overrides + /*virtual*/ void draw(); + /*virtual*/ void addLine(const std::string& utf8line); + /*virtual*/ void addLine(const LLWString& line); +private: + F32 mLinePersistTime; // Age at which to stop drawing. + F32 mFadeTime; // Age at which to start fading + const LLFontGL* mFont; + S32 mLastBoxHeight; + S32 mLastBoxWidth; + S32 mConsoleWidth; + S32 mConsoleHeight; + +}; + +extern LLConsole* gConsole; + +#endif diff --git a/indra/llui/llcontainerview.cpp b/indra/llui/llcontainerview.cpp new file mode 100644 index 0000000000..51ef80f4b9 --- /dev/null +++ b/indra/llui/llcontainerview.cpp @@ -0,0 +1,302 @@ +/** + * @file llcontainerview.cpp + * @brief Container for all statistics info + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llcontainerview.h" + +#include "llerror.h" +#include "llfontgl.h" +#include "llgl.h" +#include "llui.h" +#include "llstring.h" +#include "llscrollcontainer.h" +#include "lluictrlfactory.h" + +static LLDefaultChildRegistry::Register r1("container_view"); + +#include "llpanel.h" +#include "llstatview.h" +static ContainerViewRegistry::Register r2("stat_view"); +static ContainerViewRegistry::Register r3("panel", &LLPanel::fromXML); + +LLContainerView::LLContainerView(const LLContainerView::Params& p) +: LLView(p), + mShowLabel(p.show_label), + mLabel(p.label), + mDisplayChildren(p.display_children) +{ + mCollapsible = TRUE; + mScrollContainer = NULL; +} + +LLContainerView::~LLContainerView() +{ + // Children all cleaned up by default view destructor. +} + +BOOL LLContainerView::postBuild() +{ + setDisplayChildren(mDisplayChildren); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + return TRUE; +} + +bool LLContainerView::addChild(LLView* child, S32 tab_group) +{ + bool res = LLView::addChild(child, tab_group); + if (res) + { + sendChildToBack(child); + } + return res; +} + +BOOL LLContainerView::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + if (mDisplayChildren) + { + handled = (LLView::childrenHandleMouseDown(x, y, mask) != NULL); + } + if (!handled) + { + if( mCollapsible && mShowLabel && (y >= getRect().getHeight() - 10) ) + { + setDisplayChildren(!mDisplayChildren); + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + handled = TRUE; + } + } + return handled; +} + +BOOL LLContainerView::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + if (mDisplayChildren) + { + handled = (LLView::childrenHandleMouseUp(x, y, mask) != NULL); + } + return handled; +} + + +void LLContainerView::draw() +{ + { + 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)); + } + + // Draw the label + if (mShowLabel) + { + LLFontGL::getFontMonospace()->renderUTF8( + mLabel, 0, 2, getRect().getHeight() - 2, LLColor4(1,1,1,1), LLFontGL::LEFT, LLFontGL::TOP); + } + + LLView::draw(); +} + + +void LLContainerView::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLRect scroller_rect; + scroller_rect.setOriginAndSize(0, 0, width, height); + + if (mScrollContainer) + { + scroller_rect = mScrollContainer->getContentWindowRect(); + } + else + { + // if we're uncontained - make height as small as possible + scroller_rect.mTop = 0; + } + + arrange(scroller_rect.getWidth(), scroller_rect.getHeight(), called_from_parent); + + // sometimes, after layout, our container will change size (scrollbars popping in and out) + // if so, attempt another layout + if (mScrollContainer) + { + LLRect new_container_rect = mScrollContainer->getContentWindowRect(); + + if ((new_container_rect.getWidth() != scroller_rect.getWidth()) || + (new_container_rect.getHeight() != scroller_rect.getHeight())) // the container size has changed, attempt to arrange again + { + arrange(new_container_rect.getWidth(), new_container_rect.getHeight(), called_from_parent); + } + } +} + +void LLContainerView::arrange(S32 width, S32 height, BOOL called_from_parent) +{ + // Determine the sizes and locations of all contained views + S32 total_height = 0; + S32 top, left, right, bottom; + //LLView *childp; + + // These will be used for the children + left = 4; + top = getRect().getHeight() - 4; + right = width - 2; + bottom = top; + + // Leave some space for the top label/grab handle + if (mShowLabel) + { + total_height += 20; + } + + if (mDisplayChildren) + { + // Determine total height + U32 child_height = 0; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + if (!childp->getVisible()) + { + llwarns << "Incorrect visibility!" << llendl; + } + LLRect child_rect = childp->getRequiredRect(); + child_height += child_rect.getHeight(); + child_height += 2; + } + total_height += child_height; + } + + if (total_height < height) + total_height = height; + + if (followsTop()) + { + // HACK: casting away const. Should use setRect or some helper function instead. + const_cast(getRect()).mBottom = getRect().mTop - total_height; + } + else + { + // HACK: casting away const. Should use setRect or some helper function instead. + const_cast(getRect()).mTop = getRect().mBottom + total_height; + } + // HACK: casting away const. Should use setRect or some helper function instead. + const_cast(getRect()).mRight = getRect().mLeft + width; + + top = total_height; + if (mShowLabel) + { + top -= 20; + } + + bottom = top; + + if (mDisplayChildren) + { + // Iterate through all children, and put in container from top down. + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + LLRect child_rect = childp->getRequiredRect(); + bottom -= child_rect.getHeight(); + LLRect r(left, bottom + child_rect.getHeight(), right, bottom); + childp->setRect(r); + childp->reshape(right - left, top - bottom); + top = bottom - 2; + bottom = top; + } + } + + if (!called_from_parent) + { + if (getParent()) + { + getParent()->reshape(getParent()->getRect().getWidth(), getParent()->getRect().getHeight(), FALSE); + } + } + +} + +LLRect LLContainerView::getRequiredRect() +{ + LLRect req_rect; + //LLView *childp; + U32 total_height = 0; + + // Determine the sizes and locations of all contained views + + // Leave some space for the top label/grab handle + + if (mShowLabel) + { + total_height = 20; + } + + + if (mDisplayChildren) + { + // Determine total height + U32 child_height = 0; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + LLRect child_rect = childp->getRequiredRect(); + child_height += child_rect.getHeight(); + child_height += 2; + } + + total_height += child_height; + } + req_rect.mTop = total_height; + return req_rect; +} + +void LLContainerView::setLabel(const std::string& label) +{ + mLabel = label; +} + +void LLContainerView::setDisplayChildren(const BOOL displayChildren) +{ + mDisplayChildren = displayChildren; + for (child_list_const_iter_t child_iter = getChildList()->begin(); + child_iter != getChildList()->end(); ++child_iter) + { + LLView *childp = *child_iter; + childp->setVisible(mDisplayChildren); + } +} diff --git a/indra/llui/llcontainerview.h b/indra/llui/llcontainerview.h new file mode 100644 index 0000000000..74e38e18bc --- /dev/null +++ b/indra/llui/llcontainerview.h @@ -0,0 +1,100 @@ +/** + * @file llcontainerview.h + * @brief Container for all statistics info. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCONTAINERVIEW_H +#define LL_LLCONTAINERVIEW_H + +#include "stdtypes.h" +#include "lltextbox.h" +#include "llstatbar.h" +#include "llview.h" + +class LLScrollContainer; + +struct ContainerViewRegistry : public LLChildRegistry +{}; + +class LLContainerView : public LLView +{ +public: + struct Params : public LLInitParam::Block + { + Optional label; + Optional show_label; + Optional display_children; + Params() + : label("label"), + show_label("show_label", FALSE), + display_children("display_children", TRUE) + { + mouse_opaque(false); + } + }; + + // my valid children are stored in this registry + typedef ContainerViewRegistry child_registry_t; + +protected: + LLContainerView(const Params& p); + friend class LLUICtrlFactory; +public: + ~LLContainerView(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ bool addChild(LLView* view, S32 tab_group = 0); + + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + + /*virtual*/ void draw(); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + /*virtual*/ LLRect getRequiredRect(); // Return the height of this object, given the set options. + + void setLabel(const std::string& label); + void showLabel(BOOL show) { mShowLabel = show; } + void setDisplayChildren(const BOOL displayChildren); + BOOL getDisplayChildren() { return mDisplayChildren; } + void setScrollContainer(LLScrollContainer* scroll) {mScrollContainer = scroll;} + + private: + LLScrollContainer* mScrollContainer; + void arrange(S32 width, S32 height, BOOL called_from_parent = TRUE); + BOOL mShowLabel; + +protected: + BOOL mDisplayChildren; + std::string mLabel; +public: + BOOL mCollapsible; + +}; +#endif // LL_CONTAINERVIEW_ diff --git a/indra/llui/lldraghandle.cpp b/indra/llui/lldraghandle.cpp index 6c92ea1ff7..6e8e37ded3 100644 --- a/indra/llui/lldraghandle.cpp +++ b/indra/llui/lldraghandle.cpp @@ -43,10 +43,10 @@ #include "llmenugl.h" #include "lltextbox.h" #include "llcontrol.h" -#include "llresmgr.h" #include "llfontgl.h" #include "llwindow.h" #include "llfocusmgr.h" +#include "lluictrlfactory.h" const S32 LEADING_PAD = 5; const S32 TITLE_PAD = 8; @@ -56,21 +56,33 @@ const S32 RIGHT_PAD = BORDER_PAD + 32; // HACK: space for close btn and minimize S32 LLDragHandle::sSnapMargin = 5; -LLDragHandle::LLDragHandle( const std::string& name, const LLRect& rect, const std::string& title ) -: LLView( name, rect, TRUE ), +LLDragHandle::LLDragHandle(const LLDragHandle::Params& p) +: LLView(p), mDragLastScreenX( 0 ), mDragLastScreenY( 0 ), mLastMouseScreenX( 0 ), mLastMouseScreenY( 0 ), - mDragHighlightColor( LLUI::sColorsGroup->getColor( "DefaultHighlightLight" ) ), - mDragShadowColor( LLUI::sColorsGroup->getColor( "DefaultShadowDark" ) ), mTitleBox( NULL ), mMaxTitleWidth( 0 ), - mForeground( TRUE ) -{ - sSnapMargin = LLUI::sConfigGroup->getS32("SnapMargin"); + mForeground( TRUE ), + mDragHighlightColor(p.drag_highlight_color()), + mDragShadowColor(p.drag_shadow_color()) - setSaveToXML(false); +{ + static LLUICachedControl snap_margin ("SnapMargin", 0); + sSnapMargin = snap_margin; +} + +LLDragHandle::~LLDragHandle() +{ + removeChild(mTitleBox); + delete mTitleBox; +} + +void LLDragHandle::initFromParams(const LLDragHandle::Params& p) +{ + LLView::initFromParams(p); + setTitle( p.label ); } void LLDragHandle::setTitleVisible(BOOL visible) @@ -81,58 +93,47 @@ void LLDragHandle::setTitleVisible(BOOL visible) } } -void LLDragHandle::setTitleBox(LLTextBox* titlebox) -{ - if( mTitleBox ) - { - removeChild(mTitleBox); - delete mTitleBox; - } - mTitleBox = titlebox; - if(mTitleBox) - { - addChild( mTitleBox ); - } -} - -LLDragHandleTop::LLDragHandleTop(const std::string& name, const LLRect &rect, const std::string& title) -: LLDragHandle(name, rect, title) -{ - setFollowsAll(); - setTitle( title ); -} - -LLDragHandleLeft::LLDragHandleLeft(const std::string& name, const LLRect &rect, const std::string& title) -: LLDragHandle(name, rect, title) -{ - setFollowsAll(); - setTitle( title ); -} - void LLDragHandleTop::setTitle(const std::string& title) { std::string trimmed_title = title; LLStringUtil::trim(trimmed_title); - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - LLTextBox* titlebox = new LLTextBox( std::string("Drag Handle Title"), getRect(), trimmed_title, font ); - titlebox->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); - titlebox->setFontStyle(LLFontGL::DROP_SHADOW_SOFT); + if( mTitleBox ) + { + mTitleBox->setText(trimmed_title); + } + else + { + const LLFontGL* font = LLFontGL::getFontSansSerif(); + LLTextBox::Params params; + params.name("Drag Handle Title"); + params.rect(getRect()); + params.text(trimmed_title); + params.font(font); + params.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT | FOLLOWS_RIGHT); + params.font_shadow(LLFontGL::DROP_SHADOW_SOFT); + mTitleBox = LLUICtrlFactory::create (params); + addChild( mTitleBox ); + } - setTitleBox(titlebox); reshapeTitleBox(); } const std::string& LLDragHandleTop::getTitle() const { - return getTitleBox() == NULL ? LLStringUtil::null : getTitleBox()->getText(); + return mTitleBox == NULL ? LLStringUtil::null : mTitleBox->getText(); } void LLDragHandleLeft::setTitle(const std::string& ) { - setTitleBox(NULL); + if( mTitleBox ) + { + removeChild(mTitleBox); + delete mTitleBox; + mTitleBox = NULL; + } /* no title on left edge */ } @@ -184,9 +185,9 @@ void LLDragHandleTop::draw() */ // Colorize the text to match the frontmost state - if (getTitleBox()) + if (mTitleBox) { - getTitleBox()->setEnabled(getForeground()); + mTitleBox->setEnabled(getForeground()); } LLView::draw(); @@ -229,9 +230,9 @@ void LLDragHandleLeft::draw() */ // Colorize the text to match the frontmost state - if (getTitleBox()) + if (mTitleBox) { - getTitleBox()->setEnabled(getForeground()); + mTitleBox->setEnabled(getForeground()); } LLView::draw(); @@ -239,12 +240,12 @@ void LLDragHandleLeft::draw() void LLDragHandleTop::reshapeTitleBox() { - if( ! getTitleBox()) + if( ! mTitleBox) { return; } - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - S32 title_width = font->getWidth( getTitleBox()->getText() ) + TITLE_PAD; + const LLFontGL* font = LLFontGL::getFontSansSerif(); + S32 title_width = font->getWidth( mTitleBox->getText() ) + TITLE_PAD; if (getMaxTitleWidth() > 0) title_width = llmin(title_width, getMaxTitleWidth()); S32 title_height = llround(font->getLineHeight()); @@ -255,7 +256,7 @@ void LLDragHandleTop::reshapeTitleBox() getRect().getWidth() - LEFT_PAD - RIGHT_PAD, title_height); - getTitleBox()->setRect( title_rect ); + mTitleBox->setRect( title_rect ); } void LLDragHandleTop::reshape(S32 width, S32 height, BOOL called_from_parent) @@ -316,6 +317,23 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask) S32 delta_x = screen_x - mDragLastScreenX; S32 delta_y = screen_y - mDragLastScreenY; + // if dragging a docked floater we want to undock + if (((LLFloater*)getParent())->isDocked()) + { + const S32 SLOP = 12; + + if (delta_y <= -SLOP || + delta_y >= SLOP) + { + ((LLFloater*)getParent())->setDocked(false, false); + return TRUE; + } + else + { + return FALSE; + } + } + LLRect original_rect = getParent()->getRect(); LLRect translated_rect = getParent()->getRect(); translated_rect.translate(delta_x, delta_y); @@ -337,14 +355,14 @@ BOOL LLDragHandle::handleHover(S32 x, S32 y, MASK mask) LLView* snap_view = getParent()->findSnapRect(new_rect, mouse_dir, SNAP_PARENT_AND_SIBLINGS, sSnapMargin); - getParent()->snappedTo(snap_view); + getParent()->setSnappedTo(snap_view); delta_x = new_rect.mLeft - pre_snap_x; delta_y = new_rect.mBottom - pre_snap_y; translated_rect.translate(delta_x, delta_y); // restore original rect so delta are detected, then call user reshape method to handle snapped floaters, etc getParent()->setRect(original_rect); - getParent()->userSetShape(translated_rect); + getParent()->setShape(translated_rect, true); mDragLastScreenX += delta_x; mDragLastScreenY += delta_y; diff --git a/indra/llui/lldraghandle.h b/indra/llui/lldraghandle.h index 9eb3e55a6c..88ec1d21f8 100644 --- a/indra/llui/lldraghandle.h +++ b/indra/llui/lldraghandle.h @@ -45,8 +45,25 @@ class LLTextBox; class LLDragHandle : public LLView { public: - LLDragHandle(const std::string& name, const LLRect& rect, const std::string& title ); - virtual ~LLDragHandle() { setTitleBox(NULL); } + struct Params + : public LLInitParam::Block + { + Optional label; + Optional drag_highlight_color; + Optional drag_shadow_color; + + Params() + : label("label"), + drag_highlight_color("drag_highlight_color", LLUIColorTable::instance().getColor("DefaultHighlightLight")), + drag_shadow_color("drag_shadow_color", LLUIColorTable::instance().getColor("DefaultShadowDark")) + { + mouse_opaque(true); + follows.flags(FOLLOWS_ALL); + } + }; + void initFromParams(const Params&); + + virtual ~LLDragHandle(); virtual void setValue(const LLSD& value); @@ -64,18 +81,20 @@ public: virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); protected: - LLTextBox* getTitleBox() const { return mTitleBox; } - void setTitleBox(LLTextBox*); - + LLDragHandle(const Params&); + friend class LLUICtrlFactory; + +protected: + LLTextBox* mTitleBox; + private: S32 mDragLastScreenX; S32 mDragLastScreenY; S32 mLastMouseScreenX; S32 mLastMouseScreenY; LLCoordGL mLastMouseDir; - LLColor4 mDragHighlightColor; - LLColor4 mDragShadowColor; - LLTextBox* mTitleBox; + LLUIColor mDragHighlightColor; + LLUIColor mDragShadowColor; S32 mMaxTitleWidth; BOOL mForeground; @@ -88,9 +107,10 @@ private: class LLDragHandleTop : public LLDragHandle { +protected: + LLDragHandleTop(const Params& p) : LLDragHandle(p) {} + friend class LLUICtrlFactory; public: - LLDragHandleTop(const std::string& name, const LLRect& rect, const std::string& title ); - virtual void setTitle( const std::string& title ); virtual const std::string& getTitle() const; virtual void draw(); @@ -105,9 +125,10 @@ private: class LLDragHandleLeft : public LLDragHandle { +protected: + LLDragHandleLeft(const Params& p) : LLDragHandle(p) {} + friend class LLUICtrlFactory; public: - LLDragHandleLeft(const std::string& name, const LLRect& rect, const std::string& title ); - virtual void setTitle( const std::string& title ); virtual const std::string& getTitle() const; virtual void draw(); diff --git a/indra/llui/llf32uictrl.cpp b/indra/llui/llf32uictrl.cpp new file mode 100644 index 0000000000..0978005b78 --- /dev/null +++ b/indra/llui/llf32uictrl.cpp @@ -0,0 +1,57 @@ +/** + * @file llf32uictrl.cpp + * @author Nat Goodspeed + * @date 2008-09-08 + * @brief Implementation for llf32uictrl. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llf32uictrl.h" +// STL headers +// std headers +// external library headers +// other Linden headers + +LLF32UICtrl::LLF32UICtrl(const Params& p) +: LLUICtrl(p), + mInitialValue(p.initial_value().asReal()), + mMinValue(p.min_value), + mMaxValue(p.max_value), + mIncrement(p.increment) +{ + mViewModel->setValue(p.initial_value); +} + +F32 LLF32UICtrl::getValueF32() const +{ + return mViewModel->getValue().asReal(); +} diff --git a/indra/llui/llf32uictrl.h b/indra/llui/llf32uictrl.h new file mode 100644 index 0000000000..0a54fe761b --- /dev/null +++ b/indra/llui/llf32uictrl.h @@ -0,0 +1,83 @@ +/** + * @file llf32uictrl.h + * @author Nat Goodspeed + * @date 2008-09-08 + * @brief Base class for float-valued LLUICtrl widgets + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLF32UICTRL_H) +#define LL_LLF32UICTRL_H + +#include "lluictrl.h" + +class LLF32UICtrl: public LLUICtrl +{ +public: + struct Params: public LLInitParam::Block + { + Optional min_value, + max_value, + increment; + + Params() + : min_value("min_val", 0.f), + max_value("max_val", 1.f), + increment("increment", 0.1f) + {} + }; + +protected: + LLF32UICtrl(const Params& p); + +public: + virtual F32 getValueF32() const; + + virtual void setValue(const LLSD& value ) { mViewModel->setValue(value); } + virtual LLSD getValue() const { return LLSD(getValueF32()); } + + virtual void setMinValue(const LLSD& min_value) { setMinValue((F32)min_value.asReal()); } + virtual void setMaxValue(const LLSD& max_value) { setMaxValue((F32)max_value.asReal()); } + + virtual F32 getInitialValue() const { return mInitialValue; } + virtual F32 getMinValue() const { return mMinValue; } + virtual F32 getMaxValue() const { return mMaxValue; } + virtual F32 getIncrement() const { return mIncrement; } + virtual void setMinValue(F32 min_value) { mMinValue = min_value; } + virtual void setMaxValue(F32 max_value) { mMaxValue = max_value; } + virtual void setIncrement(F32 increment) { mIncrement = increment;} + +protected: + F32 mInitialValue; + F32 mMinValue; + F32 mMaxValue; + F32 mIncrement; +}; + +#endif /* ! defined(LL_LLF32UICTRL_H) */ diff --git a/indra/llui/llfiltereditor.cpp b/indra/llui/llfiltereditor.cpp new file mode 100644 index 0000000000..7d6a4007a2 --- /dev/null +++ b/indra/llui/llfiltereditor.cpp @@ -0,0 +1,116 @@ +/** + * @file llfiltereditor.cpp + * @brief LLFilterEditor implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Text editor widget to let users enter a single line. + +#include "linden_common.h" + +#include "llfiltereditor.h" + +LLFilterEditor::LLFilterEditor(const LLFilterEditor::Params& p) +: LLUICtrl(p) +{ + LLLineEditor::Params line_editor_p(p); + line_editor_p.name("filter edit box"); + line_editor_p.rect(getLocalRect()); + line_editor_p.follows.flags(FOLLOWS_ALL); + line_editor_p.text_pad_right(getRect().getHeight()); + line_editor_p.keystroke_callback(boost::bind(&LLUICtrl::onCommit, this)); + + mFilterEditor = LLUICtrlFactory::create(line_editor_p); + addChild(mFilterEditor); + + S32 btn_width = getRect().getHeight(); // button is square, and as tall as search editor + LLRect clear_btn_rect(getRect().getWidth() - btn_width, getRect().getHeight(), getRect().getWidth(), 0); + LLButton::Params button_params(p.clear_filter_button); + button_params.name(std::string("clear filter")); + button_params.rect(clear_btn_rect) ; + button_params.follows.flags(FOLLOWS_RIGHT|FOLLOWS_TOP); + button_params.tab_stop(false); + button_params.click_callback.function(boost::bind(&LLFilterEditor::onClearFilter, this, _2)); + + mClearFilterButton = LLUICtrlFactory::create(button_params); + mFilterEditor->addChild(mClearFilterButton); +} + +//virtual +void LLFilterEditor::setValue(const LLSD& value ) +{ + mFilterEditor->setValue(value); +} + +//virtual +LLSD LLFilterEditor::getValue() const +{ + return mFilterEditor->getValue(); +} + +//virtual +BOOL LLFilterEditor::setTextArg( const std::string& key, const LLStringExplicit& text ) +{ + return mFilterEditor->setTextArg(key, text); +} + +//virtual +BOOL LLFilterEditor::setLabelArg( const std::string& key, const LLStringExplicit& text ) +{ + return mFilterEditor->setLabelArg(key, text); +} + +//virtual +void LLFilterEditor::setLabel( const LLStringExplicit &new_label ) +{ + mFilterEditor->setLabel(new_label); +} + +//virtual +void LLFilterEditor::clear() +{ + if (mFilterEditor) + { + mFilterEditor->clear(); + } +} + +void LLFilterEditor::draw() +{ + mClearFilterButton->setVisible(!mFilterEditor->getWText().empty()); + + LLUICtrl::draw(); +} + +void LLFilterEditor::onClearFilter(const LLSD& data) +{ + setText(LLStringUtil::null); + onCommit(); +} + diff --git a/indra/llui/llfiltereditor.h b/indra/llui/llfiltereditor.h new file mode 100644 index 0000000000..fceb82af8d --- /dev/null +++ b/indra/llui/llfiltereditor.h @@ -0,0 +1,87 @@ +/** + * @file llfiltereditor.h + * @brief Text editor widget that represents a filter operation + * + * Features: + * Text entry of a single line (text, delete, left and right arrow, insert, return). + * Callbacks either on every keystroke or just on the return key. + * Focus (allow multiple text entry widgets) + * Clipboard (cut, copy, and paste) + * Horizontal scrolling to allow strings longer than widget size allows + * Pre-validation (limit which keys can be used) + * Optional line history so previous entries can be recalled by CTRL UP/DOWN + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_FILTEREDITOR_H +#define LL_FILTEREDITOR_H + +#include "lllineeditor.h" +#include "llbutton.h" + +class LLFilterEditor : public LLUICtrl +{ +public: + struct Params : public LLInitParam::Block + { + Optional clear_filter_button; + + Params() + : clear_filter_button("clear_filter_button") + { + name = "filter_editor"; + } + }; + +protected: + LLFilterEditor(const Params&); + friend class LLUICtrlFactory; +public: + virtual ~LLFilterEditor() {} + + /*virtual*/ void draw(); + + void setText(const LLStringExplicit &new_text) { mFilterEditor->setText(new_text); } + + // LLUICtrl interface + virtual void setValue(const LLSD& value ); + virtual LLSD getValue() const; + virtual BOOL setTextArg( const std::string& key, const LLStringExplicit& text ); + virtual BOOL setLabelArg( const std::string& key, const LLStringExplicit& text ); + virtual void setLabel( const LLStringExplicit &new_label ); + virtual void clear(); + +private: + void onClearFilter(const LLSD& data); + + LLLineEditor* mFilterEditor; + LLButton* mClearFilterButton; +}; + +#endif // LL_FILTEREDITOR_H diff --git a/indra/llui/llfloater.cpp b/indra/llui/llfloater.cpp index 21f8f6e5f7..ca3829e1bd 100644 --- a/indra/llui/llfloater.cpp +++ b/indra/llui/llfloater.cpp @@ -43,11 +43,13 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "lldraghandle.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llresizebar.h" #include "llresizehandle.h" #include "llkeyboard.h" #include "llmenugl.h" // MENU_BAR_HEIGHT +#include "llmodaldialog.h" #include "lltextbox.h" #include "llresmgr.h" #include "llui.h" @@ -56,37 +58,45 @@ #include "llcontrol.h" #include "lltabcontainer.h" #include "v2math.h" +#include "lltrans.h" +#include "llmultifloater.h" -const S32 MINIMIZED_WIDTH = 160; -const S32 CLOSE_BOX_FROM_TOP = 1; // use this to control "jumping" behavior when Ctrl-Tabbing const S32 TABBED_FLOATER_OFFSET = 0; std::string LLFloater::sButtonActiveImageNames[BUTTON_COUNT] = { - "UIImgBtnCloseActiveUUID", //BUTTON_CLOSE - "UIImgBtnRestoreActiveUUID", //BUTTON_RESTORE - "UIImgBtnMinimizeActiveUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffActiveUUID", //BUTTON_TEAR_OFF - "UIImgBtnCloseActiveUUID", //BUTTON_EDIT + "Icon_Close_Foreground", //BUTTON_CLOSE + "restore.tga", //BUTTON_RESTORE + "minimize.tga", //BUTTON_MINIMIZE + "tearoffbox.tga", //BUTTON_TEAR_OFF + "closebox.tga", //BUTTON_EDIT + "Icon_Dock_Foreground", + "Icon_Undock_Foreground" }; -std::string LLFloater::sButtonInactiveImageNames[BUTTON_COUNT] = +// Empty string means programmatic glow effect, achieved by +// not setting explicit image. +std::string LLFloater::sButtonHoveredImageNames[BUTTON_COUNT] = { - "UIImgBtnCloseInactiveUUID", //BUTTON_CLOSE - "UIImgBtnRestoreInactiveUUID", //BUTTON_RESTORE - "UIImgBtnMinimizeInactiveUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffInactiveUUID", //BUTTON_TEAR_OFF - "UIImgBtnCloseInactiveUUID", //BUTTON_EDIT + "", //BUTTON_CLOSE + "restore_pressed.tga", //BUTTON_RESTORE + "minimize_pressed.tga", //BUTTON_MINIMIZE + "tearoff_pressed.tga", //BUTTON_TEAR_OFF + "close_in_blue.tga", //BUTTON_EDIT + "", //BUTTON_DOCK + "", //BUTTON_UNDOCK }; std::string LLFloater::sButtonPressedImageNames[BUTTON_COUNT] = { - "UIImgBtnClosePressedUUID", //BUTTON_CLOSE - "UIImgBtnRestorePressedUUID", //BUTTON_RESTORE - "UIImgBtnMinimizePressedUUID", //BUTTON_MINIMIZE - "UIImgBtnTearOffPressedUUID", //BUTTON_TEAR_OFF - "UIImgBtnClosePressedUUID", //BUTTON_EDIT + "Icon_Close_Press", //BUTTON_CLOSE + "restore_pressed.tga", //BUTTON_RESTORE + "minimize_pressed.tga", //BUTTON_MINIMIZE + "tearoff_pressed.tga", //BUTTON_TEAR_OFF + "close_in_blue.tga", //BUTTON_EDIT + "Icon_Dock_Press", + "Icon_Undock_Press" }; std::string LLFloater::sButtonNames[BUTTON_COUNT] = @@ -96,19 +106,25 @@ std::string LLFloater::sButtonNames[BUTTON_COUNT] = "llfloater_minimize_btn", //BUTTON_MINIMIZE "llfloater_tear_off_btn", //BUTTON_TEAR_OFF "llfloater_edit_btn", //BUTTON_EDIT + "llfloater_dock_btn", + "llfloater_undock_btn" }; -std::string LLFloater::sButtonToolTips[BUTTON_COUNT] = +std::string LLFloater::sButtonToolTips[BUTTON_COUNT]; + +std::string LLFloater::sButtonToolTipsIndex[BUTTON_COUNT]= { #ifdef LL_DARWIN - "Close (Cmd-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_DARWIN", //"Close (Cmd-W)", //BUTTON_CLOSE #else - "Close (Ctrl-W)", //BUTTON_CLOSE + "BUTTON_CLOSE_WIN", //"Close (Ctrl-W)", //BUTTON_CLOSE #endif - "Restore", //BUTTON_RESTORE - "Minimize", //BUTTON_MINIMIZE - "Tear Off", //BUTTON_TEAR_OFF - "Edit", //BUTTON_EDIT + "BUTTON_RESTORE", //"Restore", //BUTTON_RESTORE + "BUTTON_MINIMIZE", //"Minimize", //BUTTON_MINIMIZE + "BUTTON_TEAR_OFF", //"Tear Off", //BUTTON_TEAR_OFF + "BUTTON_EDIT", //"Edit", //BUTTON_EDIT + "BUTTON_DOCK", + "BUTTON_UNDOCK" }; LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = @@ -118,306 +134,205 @@ LLFloater::click_callback LLFloater::sButtonCallbacks[BUTTON_COUNT] = LLFloater::onClickMinimize, //BUTTON_MINIMIZE LLFloater::onClickTearOff, //BUTTON_TEAR_OFF LLFloater::onClickEdit, //BUTTON_EDIT + LLFloater::onClickDock, + LLFloater::onClickDock }; LLMultiFloater* LLFloater::sHostp = NULL; -BOOL LLFloater::sEditModeEnabled; +BOOL LLFloater::sEditModeEnabled = FALSE; +BOOL LLFloater::sQuitting = FALSE; // Flag to prevent storing visibility controls while quitting LLFloater::handle_map_t LLFloater::sFloaterMap; LLFloaterView* gFloaterView = NULL; -LLFloater::LLFloater() : - //FIXME: we should initialize *all* member variables here - LLPanel(), mAutoFocus(TRUE), - mResizable(FALSE), - mDragOnLeft(FALSE), - mMinWidth(0), - mMinHeight(0) +//static +bool LLFloater::KeyCompare::compare(const LLSD& a, const LLSD& b) { - // automatically take focus when opened - mAutoFocus = TRUE; + if (a.type() != b.type()) + { + //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl; + return false; + } + else if (a.isUndefined()) + return false; + else if (a.isInteger()) + return a.asInteger() < b.asInteger(); + else if (a.isReal()) + return a.asReal() < b.asReal(); + else if (a.isString()) + return a.asString() < b.asString(); + else if (a.isUUID()) + return a.asUUID() < b.asUUID(); + else if (a.isDate()) + return a.asDate() < b.asDate(); + else if (a.isURI()) + return a.asString() < b.asString(); // compare URIs as strings + else if (a.isBoolean()) + return a.asBoolean() < b.asBoolean(); + else + return false; // no valid operation for Binary +} + +bool LLFloater::KeyCompare::equate(const LLSD& a, const LLSD& b) +{ + if (a.type() != b.type()) + { + //llerrs << "Mismatched LLSD types: (" << a << ") mismatches (" << b << ")" << llendl; + return false; + } + else if (a.isUndefined()) + return true; + else if (a.isInteger()) + return a.asInteger() == b.asInteger(); + else if (a.isReal()) + return a.asReal() == b.asReal(); + else if (a.isString()) + return a.asString() == b.asString(); + else if (a.isUUID()) + return a.asUUID() == b.asUUID(); + else if (a.isDate()) + return a.asDate() == b.asDate(); + else if (a.isURI()) + return a.asString() == b.asString(); // compare URIs as strings + else if (a.isBoolean()) + return a.asBoolean() == b.asBoolean(); + else + return false; // no valid operation for Binary +} + +//************************************ + +LLFloater::Params::Params() +: title("title"), + short_title("short_title"), + single_instance("single_instance", false), + auto_tile("auto_tile", false), + can_resize("can_resize", false), + can_minimize("can_minimize", true), + can_close("can_close", true), + can_drag_on_left("can_drag_on_left", false), + can_tear_off("can_tear_off", true), + save_rect("save_rect", false), + save_visibility("save_visibility", false), + open_callback("open_callback"), + close_callback("close_callback"), + can_dock("can_dock", false) +{ + name = "floater"; + // defaults that differ from LLPanel: + background_visible = true; + visible = false; +} + + +//static +const LLFloater::Params& LLFloater::getDefaultParams() +{ + return LLUICtrlFactory::getDefaultParams(); +} + +//static +void LLFloater::initClass() +{ + // translate tooltips for floater buttons for (S32 i = 0; i < BUTTON_COUNT; i++) { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; + sButtonToolTips[i] = LLTrans::getString( sButtonToolTipsIndex[i] ); } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - mDragHandle = NULL; +} + +LLFloater::LLFloater(const LLSD& key, const LLFloater::Params& p) + : LLPanel(), + mDragHandle(NULL), + mTitle(p.title), + mShortTitle(p.short_title), + mSingleInstance(p.single_instance), + mKey(key), + mAutoTile(p.auto_tile), + mCanTearOff(p.can_tear_off), + mCanMinimize(p.can_minimize), + mCanClose(p.can_close), + mDragOnLeft(p.can_drag_on_left), + mResizable(p.can_resize), + mMinWidth(p.min_width), + mMinHeight(p.min_height), + mMinimized(FALSE), + mForeground(FALSE), + mFirstLook(TRUE), + mEditing(FALSE), + mButtonScale(1.0f), + mAutoFocus(TRUE), // automatically take focus when opened + mCanDock(false), + mDocked(false), + mHasBeenDraggedWhileMinimized(FALSE), + mPreviousMinimizedBottom(0), + mPreviousMinimizedLeft(0), + mNotificationContext(NULL) +{ + static LLUIColor default_background_color = LLUIColorTable::instance().getColor("FloaterDefaultBackgroundColor"); + static LLUIColor focus_background_color = LLUIColorTable::instance().getColor("FloaterFocusBackgroundColor"); + mHandle.bind(this); mNotificationContext = new LLFloaterNotificationContext(getHandle()); -} - -LLFloater::LLFloater(const std::string& name) -: LLPanel(name), mAutoFocus(TRUE) // automatically take focus when opened -{ - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - std::string title; // null string - initFloater(title, FALSE, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, FALSE, TRUE, TRUE); // defaults -} - - -LLFloater::LLFloater(const std::string& name, const LLRect& rect, const std::string& title, - BOOL resizable, - S32 min_width, - S32 min_height, - BOOL drag_on_left, - BOOL minimizable, - BOOL close_btn, - BOOL bordered) -: LLPanel(name, rect, bordered), mAutoFocus(TRUE) // automatically take focus when opened -{ - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn); -} - -LLFloater::LLFloater(const std::string& name, const std::string& rect_control, const std::string& title, - BOOL resizable, - S32 min_width, - S32 min_height, - BOOL drag_on_left, - BOOL minimizable, - BOOL close_btn, - BOOL bordered) -: LLPanel(name, rect_control, bordered), mAutoFocus(TRUE) // automatically take focus when opened -{ - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - mButtons[i] = NULL; - } - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - initFloater( title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn); -} - - -// Note: Floaters constructed from XML call init() twice! -void LLFloater::initFloater(const std::string& title, - BOOL resizable, S32 min_width, S32 min_height, - BOOL drag_on_left, BOOL minimizable, BOOL close_btn) -{ - mHandle.bind(this); - mNotificationContext = new LLFloaterNotificationContext(getHandle()); - - // Init function can be called more than once, so clear out old data. - for (S32 i = 0; i < BUTTON_COUNT; i++) - { - mButtonsEnabled[i] = FALSE; - if (mButtons[i] != NULL) - { - removeChild(mButtons[i]); - delete mButtons[i]; - mButtons[i] = NULL; - } - } - mButtonScale = 1.f; - - //sjb: Thia is a bit of a hack: - BOOL need_border = hasBorder(); - // remove the border since deleteAllChildren() will also delete the border (but not clear mBorder) - removeBorder(); - // this will delete mBorder too - deleteAllChildren(); - // add the border back if we want it - if (need_border) - { - addBorder(); - } - - // chrome floaters don't take focus at all - setFocusRoot(!getIsChrome()); - - // Reset cached pointers - mDragHandle = NULL; - for (S32 i = 0; i < 4; i++) - { - mResizeBar[i] = NULL; - mResizeHandle[i] = NULL; - } - mCanTearOff = TRUE; - mEditing = FALSE; + mBgColorAlpha = default_background_color; + mBgColorOpaque = focus_background_color; // Clicks stop here. setMouseOpaque(TRUE); - - mFirstLook = TRUE; - mForeground = FALSE; - mDragOnLeft = drag_on_left == TRUE; - + // Floaters always draw their background, unlike every other panel. setBackgroundVisible(TRUE); // Floaters start not minimized. When minimized, they save their // prior rectangle to be used on restore. - mMinimized = FALSE; mExpandedRect.set(0,0,0,0); - S32 close_pad; // space to the right of close box - S32 close_box_size; // For layout purposes, how big is the close box? - if (close_btn) + for (S32 i = 0; i < BUTTON_COUNT; i++) { - close_box_size = LLFLOATER_CLOSE_BOX_SIZE; - close_pad = 0; + mButtonsEnabled[i] = FALSE; + mButtons[i] = NULL; } - else + for (S32 i = 0; i < 4; i++) { - close_box_size = 0; - close_pad = 0; + mResizeBar[i] = NULL; + mResizeHandle[i] = NULL; } + + initFromParams(p); + + // chrome floaters don't take focus at all + setFocusRoot(!getIsChrome()); - S32 minimize_box_size; - S32 minimize_pad; - if (minimizable && !drag_on_left) - { - minimize_box_size = LLFLOATER_CLOSE_BOX_SIZE; - minimize_pad = 0; - } - else - { - minimize_box_size = 0; - minimize_pad = 0; - } + initFloater(); +} - // Drag Handle - // Add first so it's in the background. -// const S32 drag_pad = 2; - if (drag_on_left) - { - LLRect drag_handle_rect; - drag_handle_rect.setOriginAndSize( - 0, 0, - DRAG_HANDLE_WIDTH, - getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size); - mDragHandle = new LLDragHandleLeft(std::string("drag"), drag_handle_rect, title ); - } - else // drag on top - { - LLRect drag_handle_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - mDragHandle = new LLDragHandleTop( std::string("Drag Handle"), drag_handle_rect, title ); - } - addChild(mDragHandle); - - // Resize Handle - mResizable = resizable; - mMinWidth = min_width; - mMinHeight = min_height; - - if( mResizable ) - { - // Resize bars (sides) - const S32 RESIZE_BAR_THICKNESS = 3; - mResizeBar[LLResizeBar::LEFT] = new LLResizeBar( - std::string("resizebar_left"), - this, - LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0), - min_width, S32_MAX, LLResizeBar::LEFT ); - addChild( mResizeBar[0] ); - - mResizeBar[LLResizeBar::TOP] = new LLResizeBar( - std::string("resizebar_top"), - this, - LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS), - min_height, S32_MAX, LLResizeBar::TOP ); - addChild( mResizeBar[1] ); - - mResizeBar[LLResizeBar::RIGHT] = new LLResizeBar( - std::string("resizebar_right"), - this, - LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), - min_width, S32_MAX, LLResizeBar::RIGHT ); - addChild( mResizeBar[2] ); - - mResizeBar[LLResizeBar::BOTTOM] = new LLResizeBar( - std::string("resizebar_bottom"), - this, - LLRect( 0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0), - min_height, S32_MAX, LLResizeBar::BOTTOM ); - addChild( mResizeBar[3] ); - - - // Resize handles (corners) - mResizeHandle[0] = new LLResizeHandle( - std::string("Resize Handle"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0), - min_width, - min_height, - LLResizeHandle::RIGHT_BOTTOM); - addChild(mResizeHandle[0]); - - mResizeHandle[1] = new LLResizeHandle( - std::string("resize"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT), - min_width, - min_height, - LLResizeHandle::RIGHT_TOP ); - addChild(mResizeHandle[1]); - - mResizeHandle[2] = new LLResizeHandle( std::string("resize"), - LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ), - min_width, - min_height, - LLResizeHandle::LEFT_BOTTOM ); - addChild(mResizeHandle[2]); - - mResizeHandle[3] = new LLResizeHandle( std::string("resize"), - LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ), - min_width, - min_height, - LLResizeHandle::LEFT_TOP ); - addChild(mResizeHandle[3]); - } +// Note: Floaters constructed from XML call init() twice! +void LLFloater::initFloater() +{ + addDragHandle(); + + addResizeCtrls(); // Close button. - if (close_btn) + if (mCanClose) { mButtonsEnabled[BUTTON_CLOSE] = TRUE; } // Minimize button only for top draggers - if ( !drag_on_left && minimizable ) + if ( !mDragOnLeft && mCanMinimize ) { mButtonsEnabled[BUTTON_MINIMIZE] = TRUE; } - // Keep track of whether this window has ever been dragged while it - // was minimized. If it has, we'll remember its position for the - // next time it's minimized. - mHasBeenDraggedWhileMinimized = FALSE; - mPreviousMinimizedLeft = 0; - mPreviousMinimizedBottom = 0; + if(mCanDock) + { + mButtonsEnabled[BUTTON_DOCK] = TRUE; + } buildButtons(); - // JC - Don't do this here, because many floaters first construct themselves, - // then show themselves. Put it in setVisibleAndFrontmost. - // make_ui_sound("UISndWindowOpen"); - - // RN: floaters are created in the invisible state + // Floaters are created in the invisible state setVisible(FALSE); // add self to handle->floater map @@ -429,19 +344,137 @@ void LLFloater::initFloater(const std::string& title, } } +void LLFloater::addDragHandle() +{ + static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0); + S32 close_box_size = mCanClose ? floater_close_box_size : 0; + + if (!mDragHandle) + { + if (mDragOnLeft) + { + LLDragHandleLeft::Params p; + p.name("drag"); + p.follows.flags(FOLLOWS_ALL); + p.label(mTitle); + mDragHandle = LLUICtrlFactory::create(p); + } + else // drag on top + { + LLDragHandleTop::Params p; + p.name("Drag Handle"); + p.follows.flags(FOLLOWS_ALL); + p.label(mTitle); + mDragHandle = LLUICtrlFactory::create(p); + } + addChild(mDragHandle); + } + LLRect rect; + if (mDragOnLeft) + { + rect.setLeftTopAndSize(0, 0, DRAG_HANDLE_WIDTH, getRect().getHeight() - LLPANEL_BORDER_WIDTH - close_box_size); + } + else // drag on top + { + rect = getLocalRect(); + } + mDragHandle->setRect(rect); + updateButtons(); + applyTitle(); +} + +void LLFloater::addResizeCtrls() +{ + for (S32 i = 0; i < 4; i++) + { + if (mResizeBar[i]) + { + removeChild(mResizeBar[i]); + delete mResizeBar[i]; + mResizeBar[i] = NULL; + } + if (mResizeHandle[i]) + { + removeChild(mResizeHandle[i]); + delete mResizeHandle[i]; + mResizeHandle[i] = NULL; + } + } + if( !mResizable ) + { + return; + } + + // Resize bars (sides) + const S32 RESIZE_BAR_THICKNESS = 3; + LLResizeBar::Params p; + p.name("resizebar_left"); + p.resizing_view(this); + p.rect(LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0)); + p.min_size(mMinWidth); + p.side(LLResizeBar::LEFT); + mResizeBar[LLResizeBar::LEFT] = LLUICtrlFactory::create(p); + addChild( mResizeBar[LLResizeBar::LEFT] ); + + p.name("resizebar_top"); + p.rect(LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS)); + p.min_size(mMinHeight); + p.side(LLResizeBar::TOP); + + mResizeBar[LLResizeBar::TOP] = LLUICtrlFactory::create(p); + addChild( mResizeBar[LLResizeBar::TOP] ); + + p.name("resizebar_right"); + p.rect(LLRect(getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0)); + p.min_size(mMinWidth); + p.side(LLResizeBar::RIGHT); + + mResizeBar[LLResizeBar::RIGHT] = LLUICtrlFactory::create(p); + addChild( mResizeBar[LLResizeBar::RIGHT] ); + + p.name("resizebar_bottom"); + p.rect(LLRect(0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0)); + p.min_size(mMinHeight); + p.side(LLResizeBar::BOTTOM); + mResizeBar[LLResizeBar::BOTTOM] = LLUICtrlFactory::create(p); + addChild( mResizeBar[LLResizeBar::BOTTOM] ); + + // Resize handles (corners) + LLResizeHandle::Params handle_p; + // handles must not be mouse-opaque, otherwise they block hover events + // to other buttons like the close box. JC + handle_p.mouse_opaque(false); + handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0)); + handle_p.min_width(mMinWidth); + handle_p.min_height(mMinHeight); + handle_p.corner(LLResizeHandle::RIGHT_BOTTOM); + mResizeHandle[0] = LLUICtrlFactory::create(handle_p); + addChild(mResizeHandle[0]); + + handle_p.rect(LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT)); + handle_p.corner(LLResizeHandle::RIGHT_TOP); + mResizeHandle[1] = LLUICtrlFactory::create(handle_p); + addChild(mResizeHandle[1]); + + handle_p.rect(LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 )); + handle_p.corner(LLResizeHandle::LEFT_BOTTOM); + mResizeHandle[2] = LLUICtrlFactory::create(handle_p); + addChild(mResizeHandle[2]); + + handle_p.rect(LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT )); + handle_p.corner(LLResizeHandle::LEFT_TOP); + mResizeHandle[3] = LLUICtrlFactory::create(handle_p); + addChild(mResizeHandle[3]); +} + // virtual LLFloater::~LLFloater() { + LLFloaterReg::removeInstance(mInstanceName, mKey); + delete mNotificationContext; mNotificationContext = NULL; - control_map_t::iterator itor; - for (itor = mFloaterControls.begin(); itor != mFloaterControls.end(); ++itor) - { - delete itor->second; - } - mFloaterControls.clear(); - //// am I not hosted by another floater? //if (mHostHandle.isDead()) //{ @@ -469,12 +502,31 @@ LLFloater::~LLFloater() delete mResizeBar[i]; delete mResizeHandle[i]; } + + storeRectControl(); + setVisible(false); // We're not visible if we're destroyed + storeVisibilityControl(); } +void LLFloater::storeRectControl() +{ + if( mRectControl.size() > 1 ) + { + LLUI::sSettingGroups["floater"]->setRect( mRectControl, getRect() ); + } +} + +void LLFloater::storeVisibilityControl() +{ + if( !sQuitting && mVisibilityControl.size() > 1 ) + { + LLUI::sSettingGroups["floater"]->setBOOL( mVisibilityControl, getVisible() ); + } +} void LLFloater::setVisible( BOOL visible ) { - LLPanel::setVisible(visible); + LLPanel::setVisible(visible); // calls handleVisibilityChange() if( visible && mFirstLook ) { mFirstLook = FALSE; @@ -504,10 +556,25 @@ void LLFloater::setVisible( BOOL visible ) } ++dependent_it; } + + storeVisibilityControl(); } -void LLFloater::open() /* Flawfinder: ignore */ +// virtual +void LLFloater::handleVisibilityChange ( BOOL new_visibility ) { + if (new_visibility) + { + if (getHost()) + getHost()->setFloaterFlashing(this, FALSE); + } + LLPanel::handleVisibilityChange ( new_visibility ); +} + +void LLFloater::openFloater(const LLSD& key) +{ + mKey = key; // in case we need to open ourselves again + if (getSoundFlags() != SILENT // don't play open sound for hosted (tabbed) windows && !getHost() @@ -525,9 +592,11 @@ void LLFloater::open() /* Flawfinder: ignore */ // only select tabs if window they are hosted in is visible getFloaterHost()->addFloater(this, getFloaterHost()->getVisible()); } - else if (getHost() != NULL) + + if (getHost() != NULL) { - // already hosted + getHost()->setMinimized(FALSE); + getHost()->setVisibleAndFrontmost(mAutoFocus); getHost()->showFloater(this); } else @@ -536,11 +605,17 @@ void LLFloater::open() /* Flawfinder: ignore */ setVisibleAndFrontmost(mAutoFocus); } - onOpen(); + mOpenSignal(this, key); + onOpen(key); } -void LLFloater::close(bool app_quitting) +void LLFloater::closeFloater(bool app_quitting) { + if (app_quitting) + { + LLFloater::sQuitting = true; + } + // Always unminimize before trying to close. // Most of the time the user will never see this state. setMinimized(FALSE); @@ -570,7 +645,7 @@ void LLFloater::close(bool app_quitting) if (floaterp) { ++dependent_it; - floaterp->close(); + floaterp->closeFloater(app_quitting); } else { @@ -597,9 +672,28 @@ void LLFloater::close(bool app_quitting) } } } - - // Let floater do cleanup. - onClose(app_quitting); + + // Close callback + mCloseSignal(this, LLSD(app_quitting)); + + // Hide or Destroy + if (mSingleInstance) + { + // Hide the instance + if (getHost()) + { + getHost()->setVisible(FALSE); + } + else + { + setVisible(FALSE); + } + } + else + { + setVisible(FALSE); // hide before destroying (so handleVisibilityChange() gets called) + destroy(); + } } } @@ -607,6 +701,7 @@ void LLFloater::close(bool app_quitting) void LLFloater::reshape(S32 width, S32 height, BOOL called_from_parent) { LLPanel::reshape(width, height, called_from_parent); + storeRectControl(); } void LLFloater::releaseFocus() @@ -616,10 +711,7 @@ void LLFloater::releaseFocus() gFocusMgr.setTopCtrl(NULL); } - if( gFocusMgr.childHasKeyboardFocus( this ) ) - { - gFocusMgr.setKeyboardFocus(NULL); - } + setFocus(FALSE); if( gFocusMgr.childHasMouseCapture( this ) ) { @@ -664,15 +756,23 @@ void LLFloater::center() centerWithin(gFloaterView->getRect()); } +LLMultiFloater* LLFloater::getHost() +{ + return (LLMultiFloater*)mHostHandle.get(); +} + void LLFloater::applyRectControl() { - if (!getRectControl().empty()) + if (mRectControl.size() > 1) { - const LLRect& rect = LLUI::sConfigGroup->getRect(getRectControl()); - translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); - if (mResizable) + const LLRect& rect = LLUI::sSettingGroups["floater"]->getRect(mRectControl); + if (rect.getWidth() > 0 && rect.getHeight() > 0) { - reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + translate( rect.mLeft - getRect().mLeft, rect.mBottom - getRect().mBottom); + if (mResizable) + { + reshape(llmax(mMinWidth, rect.getWidth()), llmax(mMinHeight, rect.getHeight())); + } } } } @@ -763,7 +863,7 @@ BOOL LLFloater::canSnapTo(const LLView* other_view) return LLPanel::canSnapTo(other_view); } -void LLFloater::snappedTo(const LLView* snap_view) +void LLFloater::setSnappedTo(const LLView* snap_view) { if (!snap_view || snap_view == getParent()) { @@ -778,10 +878,10 @@ void LLFloater::snappedTo(const LLView* snap_view) } } -void LLFloater::userSetShape(const LLRect& new_rect) +void LLFloater::handleReshape(const LLRect& new_rect, bool by_user) { const LLRect old_rect = getRect(); - LLView::userSetShape(new_rect); + LLView::handleReshape(new_rect, by_user); // if not minimized, adjust all snapped dependents to new shape if (!isMinimized()) @@ -816,7 +916,7 @@ void LLFloater::userSetShape(const LLRect& new_rect) delta_y += new_rect.mBottom - old_rect.mBottom; dependent_rect.translate(delta_x, delta_y); - floaterp->userSetShape(dependent_rect); + floaterp->setShape(dependent_rect, by_user); } } } @@ -834,6 +934,9 @@ void LLFloater::userSetShape(const LLRect& new_rect) void LLFloater::setMinimized(BOOL minimize) { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + static LLUICachedControl minimized_width ("UIMinimizedWidth", 0); + if (minimize == mMinimized) return; if (minimize) @@ -902,7 +1005,7 @@ void LLFloater::setMinimized(BOOL minimize) mMinimized = TRUE; // Reshape *after* setting mMinimized - reshape( MINIMIZED_WIDTH, LLFLOATER_HEADER_SIZE, TRUE); + reshape( minimized_width, floater_header_size, TRUE); } else { @@ -968,7 +1071,7 @@ void LLFloater::setFocus( BOOL b ) } LLUICtrl* last_focus = gFocusMgr.getLastFocusForGroup(this); // a descendent already has focus - BOOL child_had_focus = gFocusMgr.childHasKeyboardFocus(this); + BOOL child_had_focus = hasFocus(); // give focus to first valid descendent LLPanel::setFocus(b); @@ -995,6 +1098,13 @@ void LLFloater::setFocus( BOOL b ) } } +// virtual +void LLFloater::setRect(const LLRect &rect) +{ + LLPanel::setRect(rect); + addDragHandle(); // re-add drag handle, sized based on rect +} + // virtual void LLFloater::setIsChrome(BOOL is_chrome) { @@ -1253,6 +1363,36 @@ void LLFloater::setFrontmost(BOOL take_focus) } } +void LLFloater::setCanDock(bool b) +{ + if(b != mCanDock) + { + mCanDock = b; + if(mCanDock) + { + mButtonsEnabled[BUTTON_DOCK] = !mDocked; + mButtonsEnabled[BUTTON_UNDOCK] = mDocked; + } + else + { + mButtonsEnabled[BUTTON_DOCK] = FALSE; + mButtonsEnabled[BUTTON_UNDOCK] = FALSE; + } + } + updateButtons(); +} + +void LLFloater::setDocked(bool docked, bool pop_on_undock) +{ + if(docked != mDocked && mCanDock) + { + mDocked = docked; + mButtonsEnabled[BUTTON_DOCK] = !mDocked; + mButtonsEnabled[BUTTON_UNDOCK] = mDocked; + updateButtons(); + } +} + //static void LLFloater::setEditModeEnabled(BOOL enable) { @@ -1276,19 +1416,18 @@ void LLFloater::setEditModeEnabled(BOOL enable) // static -void LLFloater::onClickMinimize(void *userdata) +void LLFloater::onClickMinimize(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + if (!self) + return; self->setMinimized( !self->isMinimized() ); } -void LLFloater::onClickTearOff(void *userdata) +void LLFloater::onClickTearOff(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + if (!self) + return; LLMultiFloater* host_floater = self->getHost(); if (host_floater) //Tear off { @@ -1297,12 +1436,12 @@ void LLFloater::onClickTearOff(void *userdata) // reparent to floater view gFloaterView->addChild(self); - self->open(); /* Flawfinder: ignore */ + self->openFloater(self->getKey()); // only force position for floaters that don't have that data saved - if (self->getRectControl().empty()) + if (self->mRectControl.size() <= 1) { - new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - LLFLOATER_HEADER_SIZE - 5, self->getRect().getWidth(), self->getRect().getHeight()); + new_rect.setLeftTopAndSize(host_floater->getRect().mLeft + 5, host_floater->getRect().mTop - floater_header_size - 5, self->getRect().getWidth(), self->getRect().getHeight()); self->setRect(new_rect); } gFloaterView->adjustToFitScreen(self, FALSE); @@ -1317,20 +1456,28 @@ void LLFloater::onClickTearOff(void *userdata) self->setMinimized(FALSE); // to reenable minimize button if it was minimized new_host->showFloater(self); // make sure host is visible - new_host->open(); + new_host->openFloater(new_host->getKey()); } } } // static -void LLFloater::onClickEdit(void *userdata) +void LLFloater::onClickEdit(LLFloater* self) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - + if (!self) + return; self->mEditing = self->mEditing ? FALSE : TRUE; } +// static +void LLFloater::onClickDock(LLFloater* self) +{ + if(self && self->mCanDock) + { + self->setDocked(!self->mDocked, true); + } +} + // static LLFloater* LLFloater::getClosableFloaterFromFocus() { @@ -1373,7 +1520,7 @@ void LLFloater::closeFocusedFloater() LLFloater* floater_to_close = LLFloater::getClosableFloaterFromFocus(); if(floater_to_close) { - floater_to_close->close(); + floater_to_close->closeFloater(); } // if nothing took focus after closing focused floater @@ -1388,12 +1535,11 @@ void LLFloater::closeFocusedFloater() // static -void LLFloater::onClickClose( void* userdata ) +void LLFloater::onClickClose( LLFloater* self ) { - LLFloater* self = (LLFloater*) userdata; - if (!self) return; - - self->close(); + if (!self) + return; + self->closeFloater(false); } @@ -1408,8 +1554,11 @@ void LLFloater::draw() S32 right = getRect().getWidth() - LLPANEL_BORDER_WIDTH; S32 bottom = LLPANEL_BORDER_WIDTH; - LLColor4 shadow_color = LLUI::sColorsGroup->getColor("ColorDropShadow"); - F32 shadow_offset = (F32)LLUI::sConfigGroup->getS32("DropShadowFloater"); + static LLUICachedControl shadow_offset_S32 ("DropShadowFloater", 0); + static LLUIColor shadow_color_cached = LLUIColorTable::instance().getColor("ColorDropShadow"); + LLColor4 shadow_color = shadow_color_cached; + F32 shadow_offset = (F32)shadow_offset_S32; + if (!isBackgroundOpaque()) { shadow_offset *= 0.2f; @@ -1422,20 +1571,21 @@ void LLFloater::draw() // No transparent windows in simple UI if (isBackgroundOpaque()) { - gl_rect_2d( left, top, right, bottom, getBackgroundColor() ); + gl_rect_2d( left, top, right, bottom, mBgColorOpaque ); } else { - gl_rect_2d( left, top, right, bottom, getTransparentColor() ); + gl_rect_2d( left, top, right, bottom, mBgColorAlpha ); } if(gFocusMgr.childHasKeyboardFocus(this) && !getIsChrome() && !getCurrentTitle().empty()) { + static LLUIColor titlebar_focus_color = LLUIColorTable::instance().getColor("TitleBarFocusColor"); // draw highlight on title bar to indicate focus. RDW - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); LLRect r = getRect(); gl_rect_2d_offset_local(0, r.getHeight(), r.getWidth(), r.getHeight() - (S32)font->getLineHeight() - 1, - LLUI::sColorsGroup->getColor("TitleBarFocusColor"), 0, TRUE); + titlebar_focus_color, 0, TRUE); } } @@ -1445,9 +1595,9 @@ void LLFloater::draw() { if (hasFocus() && getDefaultButton()->getEnabled()) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); // is this button a direct descendent and not a nested widget (e.g. checkbox)? - BOOL focus_is_child_button = dynamic_cast(focus_ctrl) != NULL && focus_ctrl->getParent() == this; + BOOL focus_is_child_button = dynamic_cast(focus_ctrl) != NULL && dynamic_cast(focus_ctrl)->getParent() == this; // only enable default button when current focus is not a button getDefaultButton()->setBorderEnabled(!focus_is_child_button); } @@ -1467,7 +1617,7 @@ void LLFloater::draw() else { // draw children - LLView* focused_child = gFocusMgr.getKeyboardFocus(); + LLView* focused_child = dynamic_cast(gFocusMgr.getKeyboardFocus()); BOOL focused_child_visible = FALSE; if (focused_child && focused_child->getParent() == this) { @@ -1489,8 +1639,10 @@ void LLFloater::draw() { // add in a border to improve spacialized visual aclarity ;) // use lines instead of gl_rect_2d so we can round the edges as per james' recommendation + static LLUIColor focus_border_color = LLUIColorTable::instance().getColor("FloaterFocusBorderColor"); + static LLUIColor unfocus_border_color = LLUIColorTable::instance().getColor("FloaterUnfocusBorderColor"); LLUI::setLineWidth(1.5f); - LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? LLUI::sColorsGroup->getColor("FloaterFocusBorderColor") : LLUI::sColorsGroup->getColor("FloaterUnfocusBorderColor"); + LLColor4 outlineColor = gFocusMgr.childHasKeyboardFocus(this) ? focus_border_color : unfocus_border_color; gl_rect_2d_offset_local(0, getRect().getHeight() + 1, getRect().getWidth() + 1, 0, outlineColor, -LLPANEL_BORDER_WIDTH, FALSE); LLUI::setLineWidth(1.f); } @@ -1511,6 +1663,7 @@ void LLFloater::setCanMinimize(BOOL can_minimize) { // if removing minimize/restore button programmatically, // go ahead and unminimize floater + mCanMinimize = can_minimize; if (!can_minimize) { setMinimized(FALSE); @@ -1524,6 +1677,7 @@ void LLFloater::setCanMinimize(BOOL can_minimize) void LLFloater::setCanClose(BOOL can_close) { + mCanClose = can_close; mButtonsEnabled[BUTTON_CLOSE] = can_close; updateButtons(); @@ -1538,83 +1692,10 @@ void LLFloater::setCanTearOff(BOOL can_tear_off) } -void LLFloater::setCanResize(BOOL can_resize) +void LLFloater::setCanResize(BOOL can_resize) { - if (mResizable && !can_resize) - { - for (S32 i = 0; i < 4; i++) - { - removeChild(mResizeBar[i], TRUE); - mResizeBar[i] = NULL; - - removeChild(mResizeHandle[i], TRUE); - mResizeHandle[i] = NULL; - } - } - else if (!mResizable && can_resize) - { - // Resize bars (sides) - const S32 RESIZE_BAR_THICKNESS = 3; - mResizeBar[0] = new LLResizeBar( - std::string("resizebar_left"), - this, - LLRect( 0, getRect().getHeight(), RESIZE_BAR_THICKNESS, 0), - mMinWidth, S32_MAX, LLResizeBar::LEFT ); - addChild( mResizeBar[0] ); - - mResizeBar[1] = new LLResizeBar( - std::string("resizebar_top"), - this, - LLRect( 0, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_BAR_THICKNESS), - mMinHeight, S32_MAX, LLResizeBar::TOP ); - addChild( mResizeBar[1] ); - - mResizeBar[2] = new LLResizeBar( - std::string("resizebar_right"), - this, - LLRect( getRect().getWidth() - RESIZE_BAR_THICKNESS, getRect().getHeight(), getRect().getWidth(), 0), - mMinWidth, S32_MAX, LLResizeBar::RIGHT ); - addChild( mResizeBar[2] ); - - mResizeBar[3] = new LLResizeBar( - std::string("resizebar_bottom"), - this, - LLRect( 0, RESIZE_BAR_THICKNESS, getRect().getWidth(), 0), - mMinHeight, S32_MAX, LLResizeBar::BOTTOM ); - addChild( mResizeBar[3] ); - - - // Resize handles (corners) - mResizeHandle[0] = new LLResizeHandle( - std::string("Resize Handle"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT, getRect().getWidth(), 0), - mMinWidth, - mMinHeight, - LLResizeHandle::RIGHT_BOTTOM); - addChild(mResizeHandle[0]); - - mResizeHandle[1] = new LLResizeHandle( std::string("resize"), - LLRect( getRect().getWidth() - RESIZE_HANDLE_WIDTH, getRect().getHeight(), getRect().getWidth(), getRect().getHeight() - RESIZE_HANDLE_HEIGHT), - mMinWidth, - mMinHeight, - LLResizeHandle::RIGHT_TOP ); - addChild(mResizeHandle[1]); - - mResizeHandle[2] = new LLResizeHandle( std::string("resize"), - LLRect( 0, RESIZE_HANDLE_HEIGHT, RESIZE_HANDLE_WIDTH, 0 ), - mMinWidth, - mMinHeight, - LLResizeHandle::LEFT_BOTTOM ); - addChild(mResizeHandle[2]); - - mResizeHandle[3] = new LLResizeHandle( std::string("resize"), - LLRect( 0, getRect().getHeight(), RESIZE_HANDLE_WIDTH, getRect().getHeight() - RESIZE_HANDLE_HEIGHT ), - mMinWidth, - mMinHeight, - LLResizeHandle::LEFT_TOP ); - addChild(mResizeHandle[3]); - } mResizable = can_resize; + addResizeCtrls(); } void LLFloater::setCanDrag(BOOL can_drag) @@ -1633,6 +1714,8 @@ void LLFloater::setCanDrag(BOOL can_drag) void LLFloater::updateButtons() { + static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl close_box_from_top ("UICloseBoxFromTop", 0); S32 button_count = 0; for (S32 i = 0; i < BUTTON_COUNT; i++) { @@ -1652,17 +1735,17 @@ void LLFloater::updateButtons() { btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH, - getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * button_count, + llround((F32)floater_close_box_size * mButtonScale), + llround((F32)floater_close_box_size * mButtonScale)); } else { btn_rect.setLeftTopAndSize( - getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * button_count, - getRect().getHeight() - CLOSE_BOX_FROM_TOP, - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround((F32)LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * button_count, + getRect().getHeight() - close_box_from_top, + llround((F32)floater_close_box_size * mButtonScale), + llround((F32)floater_close_box_size * mButtonScale)); } mButtons[i]->setRect(btn_rect); @@ -1676,50 +1759,66 @@ void LLFloater::updateButtons() } } if (mDragHandle) - mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (LLFLOATER_CLOSE_BOX_SIZE + 1))); + mDragHandle->setMaxTitleWidth(getRect().getWidth() - (button_count * (floater_close_box_size + 1))); } void LLFloater::buildButtons() { + static LLUICachedControl floater_close_box_size ("UIFloaterCloseBoxSize", 0); + static LLUICachedControl close_box_from_top ("UICloseBoxFromTop", 0); for (S32 i = 0; i < BUTTON_COUNT; i++) { + if (mButtons[i]) + { + removeChild(mButtons[i]); + delete mButtons[i]; + mButtons[i] = NULL; + } + LLRect btn_rect; if (mDragOnLeft) { btn_rect.setLeftTopAndSize( LLPANEL_BORDER_WIDTH, - getRect().getHeight() - CLOSE_BOX_FROM_TOP - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getHeight() - close_box_from_top - (floater_close_box_size + 1) * (i + 1), + llround(floater_close_box_size * mButtonScale), + llround(floater_close_box_size * mButtonScale)); } else { btn_rect.setLeftTopAndSize( - getRect().getWidth() - LLPANEL_BORDER_WIDTH - (LLFLOATER_CLOSE_BOX_SIZE + 1) * (i + 1), - getRect().getHeight() - CLOSE_BOX_FROM_TOP, - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale), - llround(LLFLOATER_CLOSE_BOX_SIZE * mButtonScale)); + getRect().getWidth() - LLPANEL_BORDER_WIDTH - (floater_close_box_size + 1) * (i + 1), + getRect().getHeight() - close_box_from_top, + llround(floater_close_box_size * mButtonScale), + llround(floater_close_box_size * mButtonScale)); } - LLButton* buttonp = new LLButton( - sButtonNames[i], - btn_rect, - sButtonActiveImageNames[i], - sButtonPressedImageNames[i], - LLStringUtil::null, - sButtonCallbacks[i], - this, - LLFontGL::getFontSansSerif()); + LLButton::Params p; + p.name(sButtonNames[i]); + p.rect(btn_rect); + p.label(""); + p.image_unselected.name(sButtonActiveImageNames[i]); + // Selected, no matter if hovered or not, is "pressed" + p.image_selected.name(sButtonPressedImageNames[i]); + p.image_hover_selected.name(sButtonPressedImageNames[i]); + // Empty string means programmatic glow effect, achieved by + // not setting explicit image. + if (sButtonHoveredImageNames[i].empty()) + { + // These icons are really small, need glow amount increased + p.hover_glow_amount( 0.22f ); + } + else + { + p.image_hover_unselected.name(sButtonHoveredImageNames[i]); + } + p.click_callback.function(boost::bind(sButtonCallbacks[i], this)); + p.tab_stop(false); + p.follows.flags(FOLLOWS_TOP|FOLLOWS_RIGHT); + p.tool_tip(sButtonToolTips[i]); + p.scale_image(true); - buttonp->setTabStop(FALSE); - buttonp->setFollowsTop(); - buttonp->setFollowsRight(); - buttonp->setToolTip( sButtonToolTips[i] ); - buttonp->setImageColor(LLUI::sColorsGroup->getColor("FloaterButtonImageColor")); - buttonp->setHoverImages(sButtonPressedImageNames[i], - sButtonPressedImageNames[i]); - buttonp->setScaleImage(TRUE); - buttonp->setSaveToXML(false); + LLButton* buttonp = LLUICtrlFactory::create(p); addChild(buttonp); mButtons[i] = buttonp; } @@ -1730,13 +1829,12 @@ void LLFloater::buildButtons() ///////////////////////////////////////////////////// // LLFloaterView -LLFloaterView::LLFloaterView( const std::string& name, const LLRect& rect ) -: LLUICtrl( name, rect, FALSE, NULL, NULL, FOLLOWS_ALL ), +LLFloaterView::LLFloaterView (const Params& p) +: LLUICtrl (p), mFocusCycleMode(FALSE), mSnapOffsetBottom(0) + ,mSnapOffsetRight(0) { - setTabStop(FALSE); - resetStartingFloaterPosition(); } // By default, adjust vertical. @@ -1830,69 +1928,6 @@ void LLFloaterView::restoreAll() } -void LLFloaterView::getNewFloaterPosition(S32* left,S32* top) -{ - // Workaround: mRect may change between when this object is created and the first time it is used. - static BOOL first = TRUE; - if( first ) - { - resetStartingFloaterPosition(); - first = FALSE; - } - - const S32 FLOATER_PAD = 16; - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - LLRect full_window(0, window_size.mY, window_size.mX, 0); - LLRect floater_creation_rect( - 160, - full_window.getHeight() - 2 * MENU_BAR_HEIGHT, - full_window.getWidth() * 2 / 3, - 130 ); - floater_creation_rect.stretch( -FLOATER_PAD ); - - *left = mNextLeft; - *top = mNextTop; - - const S32 STEP = 25; - S32 bottom = floater_creation_rect.mBottom + 2 * STEP; - S32 right = floater_creation_rect.mRight - 4 * STEP; - - mNextTop -= STEP; - mNextLeft += STEP; - - if( (mNextTop < bottom ) || (mNextLeft > right) ) - { - mColumn++; - mNextTop = floater_creation_rect.mTop; - mNextLeft = STEP * mColumn; - - if( (mNextTop < bottom) || (mNextLeft > right) ) - { - // Advancing the column didn't work, so start back at the beginning - resetStartingFloaterPosition(); - } - } -} - -void LLFloaterView::resetStartingFloaterPosition() -{ - const S32 FLOATER_PAD = 16; - LLCoordWindow window_size; - getWindow()->getSize(&window_size); - LLRect full_window(0, window_size.mY, window_size.mX, 0); - LLRect floater_creation_rect( - 160, - full_window.getHeight() - 2 * MENU_BAR_HEIGHT, - full_window.getWidth() * 2 / 3, - 130 ); - floater_creation_rect.stretch( -FLOATER_PAD ); - - mNextLeft = floater_creation_rect.mLeft; - mNextTop = floater_creation_rect.mTop; - mColumn = 0; -} - LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ) { LLRect base_rect = reference_floater->getRect(); @@ -1910,7 +1945,7 @@ LLRect LLFloaterView::findNeighboringPosition( LLFloater* reference_floater, LLF if (sibling && sibling != neighbor && sibling->getVisible() && - expanded_base_rect.rectInRect(&sibling->getRect())) + expanded_base_rect.overlaps(sibling->getRect())) { base_rect.unionWith(sibling->getRect()); } @@ -2104,15 +2139,17 @@ void LLFloaterView::focusFrontFloater() void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + static LLUICachedControl minimized_width ("UIMinimizedWidth", 0); S32 col = 0; LLRect snap_rect_local = getLocalSnapRect(); for(S32 row = snap_rect_local.mBottom; - row < snap_rect_local.getHeight() - LLFLOATER_HEADER_SIZE; - row += LLFLOATER_HEADER_SIZE ) //loop rows + row < snap_rect_local.getHeight() - floater_header_size; + row += floater_header_size ) //loop rows { for(col = snap_rect_local.mLeft; - col < snap_rect_local.getWidth() - MINIMIZED_WIDTH; - col += MINIMIZED_WIDTH) + col < snap_rect_local.getWidth() - minimized_width; + col += minimized_width) { bool foundGap = TRUE; for(child_list_const_iter_t child_it = getChildList()->begin(); @@ -2124,10 +2161,10 @@ void LLFloaterView::getMinimizePosition(S32 *left, S32 *bottom) if(floater->isMinimized()) { LLRect r = floater->getRect(); - if((r.mBottom < (row + LLFLOATER_HEADER_SIZE)) - && (r.mBottom > (row - LLFLOATER_HEADER_SIZE)) - && (r.mLeft < (col + MINIMIZED_WIDTH)) - && (r.mLeft > (col - MINIMIZED_WIDTH))) + if((r.mBottom < (row + floater_header_size)) + && (r.mBottom > (row - floater_header_size)) + && (r.mLeft < (col + minimized_width)) + && (r.mLeft > (col - minimized_width))) { // needs the check for off grid. can't drag, // but window resize makes them off @@ -2179,7 +2216,7 @@ void LLFloaterView::closeAllChildren(bool app_quitting) // dialogs to appear. if (floaterp->canClose() && !floaterp->isDead()) { - floaterp->close(app_quitting); + floaterp->closeFloater(app_quitting); } } } @@ -2202,14 +2239,13 @@ BOOL LLFloaterView::allChildrenClosed() return true; } - void LLFloaterView::refresh() { // Constrain children to be entirely on the screen for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { - LLFloater* floaterp = (LLFloater*)*child_it; - if( floaterp->getVisible() ) + LLFloater* floaterp = dynamic_cast(*child_it); + if (floaterp && floaterp->getVisible() ) { // minimized floaters are kept fully onscreen adjustToFitScreen(floaterp, !floaterp->isMinimized()); @@ -2229,7 +2265,8 @@ void LLFloaterView::adjustToFitScreen(LLFloater* floater, BOOL allow_partial_out // convert to local coordinate frame LLRect snap_rect_local = getLocalSnapRect(); - if( floater->isResizable() ) + // only automatically resize non-minimized, resizable floaters + if( floater->isResizable() && !floater->isMinimized() ) { LLRect view_rect = floater->getRect(); S32 old_width = view_rect.getWidth(); @@ -2302,11 +2339,12 @@ LLRect LLFloaterView::getSnapRect() const { LLRect snap_rect = getRect(); snap_rect.mBottom += mSnapOffsetBottom; + snap_rect.mRight -= mSnapOffsetRight; return snap_rect; } -LLFloater *LLFloaterView::getFocusedFloater() +LLFloater *LLFloaterView::getFocusedFloater() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2319,7 +2357,7 @@ LLFloater *LLFloaterView::getFocusedFloater() return NULL; } -LLFloater *LLFloaterView::getFrontmost() +LLFloater *LLFloaterView::getFrontmost() const { for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { @@ -2332,7 +2370,7 @@ LLFloater *LLFloaterView::getFrontmost() return NULL; } -LLFloater *LLFloaterView::getBackmost() +LLFloater *LLFloaterView::getBackmost() const { LLFloater* back_most = NULL; for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) @@ -2348,18 +2386,51 @@ LLFloater *LLFloaterView::getBackmost() void LLFloaterView::syncFloaterTabOrder() { - // bring focused floater to front - for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) + // look for a visible modal dialog, starting from first (should be only one) + LLModalDialog* modal_dialog = NULL; + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ++child_it) { - LLFloater* floaterp = (LLFloater*)*child_it; - if (gFocusMgr.childHasKeyboardFocus(floaterp)) + LLModalDialog* dialog = dynamic_cast(*child_it); + if (dialog && dialog->isModal() && dialog->getVisible()) { - bringToFront(floaterp, FALSE); + modal_dialog = dialog; break; } } - // then sync draw order to tab order + if (modal_dialog) + { + // If we have a visible modal dialog, make sure that it has focus + if( gFocusMgr.getTopCtrl() != modal_dialog ) + { + gFocusMgr.setTopCtrl( modal_dialog ); + } + + if( !gFocusMgr.childHasKeyboardFocus( modal_dialog ) ) + { + modal_dialog->setFocus(TRUE); + } + + if( !gFocusMgr.childHasMouseCapture( modal_dialog ) ) + { + gFocusMgr.setMouseCapture( modal_dialog ); + } + } + else + { + // otherwise, make sure the focused floater is in the front of the child list + for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) + { + LLFloater* floaterp = (LLFloater*)*child_it; + if (gFocusMgr.childHasKeyboardFocus(floaterp)) + { + bringToFront(floaterp, FALSE); + break; + } + } + } + + // sync draw order to tab order for ( child_list_const_reverse_iter_t child_it = getChildList()->rbegin(); child_it != getChildList()->rend(); ++child_it) { LLFloater* floaterp = (LLFloater*)*child_it; @@ -2367,7 +2438,7 @@ void LLFloaterView::syncFloaterTabOrder() } } -LLFloater* LLFloaterView::getParentFloater(LLView* viewp) +LLFloater* LLFloaterView::getParentFloater(LLView* viewp) const { LLView* parentp = viewp->getParent(); @@ -2426,641 +2497,149 @@ void LLFloaterView::popVisibleAll(const skip_list_t& skip_list) } } -// -// LLMultiFloater -// - -LLMultiFloater::LLMultiFloater() : - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(TRUE), - mOrigMinWidth(0), - mOrigMinHeight(0) +void LLFloater::setInstanceName(const std::string& name) { - -} - -LLMultiFloater::LLMultiFloater(LLTabContainer::TabPosition tab_pos) : - mTabContainer(NULL), - mTabPos(tab_pos), - mAutoResize(TRUE), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - -} - -LLMultiFloater::LLMultiFloater(const std::string &name) : - LLFloater(name), - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(FALSE), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ -} - -LLMultiFloater::LLMultiFloater( - const std::string& name, - const LLRect& rect, - LLTabContainer::TabPosition tab_pos, - BOOL auto_resize) : - LLFloater(name, rect, name), - mTabContainer(NULL), - mTabPos(LLTabContainer::TOP), - mAutoResize(auto_resize), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - mTabContainer = new LLTabContainer(std::string("Preview Tabs"), - LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), - mTabPos, - FALSE, - FALSE); - mTabContainer->setFollowsAll(); - if (isResizable()) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - - addChild(mTabContainer); -} - -LLMultiFloater::LLMultiFloater( - const std::string& name, - const std::string& rect_control, - LLTabContainer::TabPosition tab_pos, - BOOL auto_resize) : - LLFloater(name, rect_control, name), - mTabContainer(NULL), - mTabPos(tab_pos), - mAutoResize(auto_resize), - mOrigMinWidth(0), - mOrigMinHeight(0) -{ - mTabContainer = new LLTabContainer(std::string("Preview Tabs"), - LLRect(LLPANEL_BORDER_WIDTH, getRect().getHeight() - LLFLOATER_HEADER_SIZE, getRect().getWidth() - LLPANEL_BORDER_WIDTH, 0), - mTabPos, - FALSE, - FALSE); - mTabContainer->setFollowsAll(); - if (isResizable() && mTabPos == LLTabContainer::BOTTOM) - { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - - addChild(mTabContainer); - -} - - -void LLMultiFloater::open() /* Flawfinder: ignore */ -{ - if (mTabContainer->getTabCount() > 0) - { - LLFloater::open(); /* Flawfinder: ignore */ - } - else - { - // for now, don't allow multifloaters - // without any child floaters - close(); - } -} - -void LLMultiFloater::onClose(bool app_quitting) -{ - if(closeAllFloaters() == TRUE) - { - LLFloater::onClose(app_quitting); - }//else not all tabs could be closed... -} - -void LLMultiFloater::draw() -{ - if (mTabContainer->getTabCount() == 0) - { - //RN: could this potentially crash in draw hierarchy? - close(); - } - else - { - for (S32 i = 0; i < mTabContainer->getTabCount(); i++) - { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(i); - if (floaterp->getShortTitle() != mTabContainer->getPanelTitle(i)) - { - mTabContainer->setPanelTitle(i, floaterp->getShortTitle()); - } - } - LLFloater::draw(); - } -} - -BOOL LLMultiFloater::closeAllFloaters() -{ - S32 tabToClose = 0; - S32 lastTabCount = mTabContainer->getTabCount(); - while (tabToClose < mTabContainer->getTabCount()) - { - LLFloater* first_floater = (LLFloater*)mTabContainer->getPanelByIndex(tabToClose); - first_floater->close(); - if(lastTabCount == mTabContainer->getTabCount()) - { - //Tab did not actually close, possibly due to a pending Save Confirmation dialog.. - //so try and close the next one in the list... - tabToClose++; - }else - { - //Tab closed ok. - lastTabCount = mTabContainer->getTabCount(); - } - } - if( mTabContainer->getTabCount() != 0 ) - return FALSE; // Couldn't close all the tabs (pending save dialog?) so return FALSE. - return TRUE; //else all tabs were successfully closed... -} - -void LLMultiFloater::growToFit(S32 content_width, S32 content_height) -{ - S32 new_width = llmax(getRect().getWidth(), content_width + LLPANEL_BORDER_WIDTH * 2); - S32 new_height = llmax(getRect().getHeight(), content_height + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - - if (isMinimized()) - { - LLRect newrect; - newrect.setLeftTopAndSize(getExpandedRect().mLeft, getExpandedRect().mTop, new_width, new_height); - setExpandedRect(newrect); - } - else - { - S32 old_height = getRect().getHeight(); - reshape(new_width, new_height); - // keep top left corner in same position - translate(0, old_height - new_height); - } -} - -/** - void addFloater(LLFloater* floaterp, BOOL select_added_floater) - - Adds the LLFloater pointed to by floaterp to this. - If floaterp is already hosted by this, then it is re-added to get - new titles, etc. - If select_added_floater is true, the LLFloater pointed to by floaterp will - become the selected tab in this - - Affects: mTabContainer, floaterp -**/ -void LLMultiFloater::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point) -{ - if (!floaterp) - { + if (name == mInstanceName) return; - } - - if (!mTabContainer) + llassert_always(mInstanceName.empty()); + mInstanceName = name; + if (!mInstanceName.empty()) { - llerrs << "Tab Container used without having been initialized." << llendl; - return; - } - - if (floaterp->getHost() == this) - { - // already hosted by me, remove - // do this so we get updated title, etc. - mFloaterDataMap.erase(floaterp->getHandle()); - mTabContainer->removeTabPanel(floaterp); - } - else if (floaterp->getHost()) - { - // floaterp is hosted by somebody else and - // this is adding it, so remove it from it's old host - floaterp->getHost()->removeFloater(floaterp); - } - else if (floaterp->getParent() == gFloaterView) - { - // rehost preview floater as child panel - gFloaterView->removeChild(floaterp); - } - - // store original configuration - LLFloaterData floater_data; - floater_data.mWidth = floaterp->getRect().getWidth(); - floater_data.mHeight = floaterp->getRect().getHeight(); - floater_data.mCanMinimize = floaterp->isMinimizeable(); - floater_data.mCanResize = floaterp->isResizable(); - - // remove minimize and close buttons - floaterp->setCanMinimize(FALSE); - floaterp->setCanResize(FALSE); - floaterp->setCanDrag(FALSE); - floaterp->storeRectControl(); - // avoid double rendering of floater background (makes it more opaque) - floaterp->setBackgroundVisible(FALSE); - - if (mAutoResize) - { - growToFit(floater_data.mWidth, floater_data.mHeight); - } - - //add the panel, add it to proper maps - mTabContainer->addTabPanel(floaterp, floaterp->getShortTitle(), FALSE, onTabSelected, this, 0, FALSE, insertion_point); - mFloaterDataMap[floaterp->getHandle()] = floater_data; - - updateResizeLimits(); - - if ( select_added_floater ) - { - mTabContainer->selectTabPanel(floaterp); - } - else - { - // reassert visible tab (hiding new floater if necessary) - mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex()); - } - - floaterp->setHost(this); - if (isMinimized()) - { - floaterp->setVisible(FALSE); - } -} - -/** - BOOL selectFloater(LLFloater* floaterp) - - If the LLFloater pointed to by floaterp is hosted by this, - then its tab is selected and returns true. Otherwise returns false. - - Affects: mTabContainer -**/ -BOOL LLMultiFloater::selectFloater(LLFloater* floaterp) -{ - return mTabContainer->selectTabPanel(floaterp); -} - -// virtual -void LLMultiFloater::selectNextFloater() -{ - mTabContainer->selectNextTab(); -} - -// virtual -void LLMultiFloater::selectPrevFloater() -{ - mTabContainer->selectPrevTab(); -} - -void LLMultiFloater::showFloater(LLFloater* floaterp) -{ - // we won't select a panel that already is selected - // it is hard to do this internally to tab container - // as tab selection is handled via index and the tab at a given - // index might have changed - if (floaterp != mTabContainer->getCurrentPanel() && - !mTabContainer->selectTabPanel(floaterp)) - { - addFloater(floaterp, TRUE); - } -} - -void LLMultiFloater::removeFloater(LLFloater* floaterp) -{ - if ( floaterp->getHost() != this ) - return; - - floater_data_map_t::iterator found_data_it = mFloaterDataMap.find(floaterp->getHandle()); - if (found_data_it != mFloaterDataMap.end()) - { - LLFloaterData& floater_data = found_data_it->second; - floaterp->setCanMinimize(floater_data.mCanMinimize); - if (!floater_data.mCanResize) + // save_rect and save_visibility only apply to registered floaters + if (!mRectControl.empty()) { - // restore original size - floaterp->reshape(floater_data.mWidth, floater_data.mHeight); + mRectControl = LLFloaterReg::declareRectControl(mInstanceName); } - floaterp->setCanResize(floater_data.mCanResize); - mFloaterDataMap.erase(found_data_it); - } - mTabContainer->removeTabPanel(floaterp); - floaterp->setBackgroundVisible(TRUE); - floaterp->setCanDrag(TRUE); - floaterp->setHost(NULL); - floaterp->applyRectControl(); - - updateResizeLimits(); - - tabOpen((LLFloater*)mTabContainer->getCurrentPanel(), false); -} - -void LLMultiFloater::tabOpen(LLFloater* opened_floater, bool from_click) -{ - // default implementation does nothing -} - -void LLMultiFloater::tabClose() -{ - if (mTabContainer->getTabCount() == 0) - { - // no more children, close myself - close(); - } -} - -void LLMultiFloater::setVisible(BOOL visible) -{ - // *FIX: shouldn't have to do this, fix adding to minimized multifloater - LLFloater::setVisible(visible); - - if (mTabContainer) - { - LLPanel* cur_floaterp = mTabContainer->getCurrentPanel(); - - if (cur_floaterp) + if (!mVisibilityControl.empty()) { - cur_floaterp->setVisible(visible); - } - - // if no tab selected, and we're being shown, - // select last tab to be added - if (visible && !cur_floaterp) - { - mTabContainer->selectLastTab(); + mVisibilityControl = LLFloaterReg::declareVisibilityControl(mInstanceName); } } } -BOOL LLMultiFloater::handleKeyHere(KEY key, MASK mask) +void LLFloater::setKey(const LLSD& newkey) { - if (key == 'W' && mask == MASK_CONTROL) - { - LLFloater* floater = getActiveFloater(); - // is user closeable and is system closeable - if (floater && floater->canClose() && floater->isCloseable()) - { - floater->close(); - } - return TRUE; - } - - return LLFloater::handleKeyHere(key, mask); -} - -LLFloater* LLMultiFloater::getActiveFloater() -{ - return (LLFloater*)mTabContainer->getCurrentPanel(); -} - -S32 LLMultiFloater::getFloaterCount() -{ - return mTabContainer->getTabCount(); -} - -/** - BOOL isFloaterFlashing(LLFloater* floaterp) - - Returns true if the LLFloater pointed to by floaterp - is currently in a flashing state and is hosted by this. - False otherwise. - - Requires: floaterp != NULL -**/ -BOOL LLMultiFloater::isFloaterFlashing(LLFloater* floaterp) -{ - if ( floaterp && floaterp->getHost() == this ) - return mTabContainer->getTabPanelFlashing(floaterp); - - return FALSE; -} - -/** - BOOL setFloaterFlashing(LLFloater* floaterp, BOOL flashing) - - Sets the current flashing state of the LLFloater pointed - to by floaterp to be the BOOL flashing if the LLFloater pointed - to by floaterp is hosted by this. - - Requires: floaterp != NULL -**/ -void LLMultiFloater::setFloaterFlashing(LLFloater* floaterp, BOOL flashing) -{ - if ( floaterp && floaterp->getHost() == this ) - mTabContainer->setTabPanelFlashing(floaterp, flashing); + // Note: We don't have to do anything special with registration when we change keys + mKey = newkey; } //static -void LLMultiFloater::onTabSelected(void* userdata, bool from_click) +void LLFloater::setupParamsForExport(Params& p, LLView* parent) { - LLMultiFloater* floaterp = (LLMultiFloater*)userdata; + // Do rectangle munging to topleft layout first + LLPanel::setupParamsForExport(p, parent); - floaterp->tabOpen((LLFloater*)floaterp->mTabContainer->getCurrentPanel(), from_click); -} + // Copy the rectangle out to apply layout constraints + LLRect rect = p.rect; -void LLMultiFloater::setCanResize(BOOL can_resize) -{ - LLFloater::setCanResize(can_resize); - if (isResizable() && mTabContainer->getTabPosition() == LLTabContainer::BOTTOM) + // Null out other settings + p.rect.left.setProvided(false); + p.rect.top.setProvided(false); + p.rect.right.setProvided(false); + p.rect.bottom.setProvided(false); + + // Explicitly set width/height + p.rect.width.set( rect.getWidth(), true ); + p.rect.height.set( rect.getHeight(), true ); + + // If you can't resize this floater, don't export min_height + // and min_width + bool can_resize = p.can_resize; + if (!can_resize) { - mTabContainer->setRightTabBtnOffset(RESIZE_HANDLE_WIDTH); - } - else - { - mTabContainer->setRightTabBtnOffset(0); + p.min_height.setProvided(false); + p.min_width.setProvided(false); } } -BOOL LLMultiFloater::postBuild() +void LLFloater::initFromParams(const LLFloater::Params& p) { - // remember any original xml minimum size - getResizeLimits(&mOrigMinWidth, &mOrigMinHeight); + // control_name, tab_stop, focus_lost_callback, initial_value, rect, enabled, visible + LLPanel::initFromParams(p); - if (mTabContainer) - { - return TRUE; - } + mTitle = p.title; + mShortTitle = p.short_title; + applyTitle(); - requires("Preview Tabs"); - if (checkRequirements()) - { - mTabContainer = getChild("Preview Tabs"); - return TRUE; - } - - return FALSE; -} - -void LLMultiFloater::updateResizeLimits() -{ - // initialize minimum size constraint to the original xml values. - S32 new_min_width = mOrigMinWidth; - S32 new_min_height = mOrigMinHeight; - // possibly increase minimum size constraint due to children's minimums. - for (S32 tab_idx = 0; tab_idx < mTabContainer->getTabCount(); ++tab_idx) - { - LLFloater* floaterp = (LLFloater*)mTabContainer->getPanelByIndex(tab_idx); - if (floaterp) - { - new_min_width = llmax(new_min_width, floaterp->getMinWidth() + LLPANEL_BORDER_WIDTH * 2); - new_min_height = llmax(new_min_height, floaterp->getMinHeight() + LLFLOATER_HEADER_SIZE + TABCNTR_HEADER_HEIGHT); - } - } - setResizeLimits(new_min_width, new_min_height); - - S32 cur_height = getRect().getHeight(); - S32 new_width = llmax(getRect().getWidth(), new_min_width); - S32 new_height = llmax(getRect().getHeight(), new_min_height); - - if (isMinimized()) - { - const LLRect& expanded = getExpandedRect(); - LLRect newrect; - newrect.setLeftTopAndSize(expanded.mLeft, expanded.mTop, llmax(expanded.getWidth(), new_width), llmax(expanded.getHeight(), new_height)); - setExpandedRect(newrect); - } - else - { - reshape(new_width, new_height); - - // make sure upper left corner doesn't move - translate(0, cur_height - getRect().getHeight()); - - // make sure this window is visible on screen when it has been modified - // (tab added, etc) - gFloaterView->adjustToFitScreen(this, TRUE); - } -} - -// virtual -LLXMLNodePtr LLFloater::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLPanel::getXML(); - - node->createChild("title", TRUE)->setStringValue(getCurrentTitle()); - - node->createChild("can_resize", TRUE)->setBoolValue(isResizable()); - - node->createChild("can_minimize", TRUE)->setBoolValue(isMinimizeable()); - - node->createChild("can_close", TRUE)->setBoolValue(isCloseable()); - - node->createChild("can_drag_on_left", TRUE)->setBoolValue(isDragOnLeft()); - - node->createChild("min_width", TRUE)->setIntValue(getMinWidth()); - - node->createChild("min_height", TRUE)->setIntValue(getMinHeight()); - - node->createChild("can_tear_off", TRUE)->setBoolValue(mCanTearOff); + setCanTearOff(p.can_tear_off); + setCanMinimize(p.can_minimize); + setCanClose(p.can_close); + setCanDock(p.can_dock); - return node; -} + mDragOnLeft = p.can_drag_on_left; + mResizable = p.can_resize; + mMinWidth = p.min_width; + mMinHeight = p.min_height; + mSingleInstance = p.single_instance; + mAutoTile = p.auto_tile; -// static -LLView* LLFloater::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("floater"); - node->getAttributeString("name", name); - - LLFloater *floaterp = new LLFloater(name); - - std::string filename; - node->getAttributeString("filename", filename); - - if (filename.empty()) + if (p.save_rect) { - // Load from node - floaterp->initFloaterXML(node, parent, factory); + mRectControl = "t"; // flag to build mRectControl name once mInstanceName is set } - else + if (p.save_visibility) { - // Load from file - factory->buildFloater(floaterp, filename); - } - - return floaterp; -} - -void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open) /* Flawfinder: ignore */ -{ - std::string name(getName()); - std::string title(getCurrentTitle()); - std::string short_title(getShortTitle()); - std::string rect_control(""); - BOOL resizable = isResizable(); - S32 min_width = getMinWidth(); - S32 min_height = getMinHeight(); - BOOL drag_on_left = isDragOnLeft(); - BOOL minimizable = isMinimizeable(); - BOOL close_btn = isCloseable(); - LLRect rect; - - node->getAttributeString("name", name); - node->getAttributeString("title", title); - node->getAttributeString("short_title", short_title); - node->getAttributeString("rect_control", rect_control); - node->getAttributeBOOL("can_resize", resizable); - node->getAttributeBOOL("can_minimize", minimizable); - node->getAttributeBOOL("can_close", close_btn); - node->getAttributeBOOL("can_drag_on_left", drag_on_left); - node->getAttributeS32("min_width", min_width); - node->getAttributeS32("min_height", min_height); - - if (! rect_control.empty()) - { - setRectControl(rect_control); - } - - createRect(node, rect, parent, LLRect()); - - setRect(rect); - setName(name); - - initFloater(title, - resizable, - min_width, - min_height, - drag_on_left, - minimizable, - close_btn); - - setTitle(title); - applyTitle (); - - setShortTitle(short_title); - - BOOL can_tear_off; - if (node->getAttributeBOOL("can_tear_off", can_tear_off)) - { - setCanTearOff(can_tear_off); + mVisibilityControl = "t"; // flag to build mVisibilityControl name once mInstanceName is set } - initFromXML(node, parent); + // open callback + if (p.open_callback.isProvided()) + initCommitCallback(p.open_callback, mOpenSignal); + // close callback + if (p.close_callback.isProvided()) + initCommitCallback(p.close_callback, mCloseSignal); +} +LLFastTimer::DeclareTimer POST_BUILD("Floater Post Build"); + +void LLFloater::initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) +{ + Params params(LLUICtrlFactory::getDefaultParams()); + LLXUIParser::instance().readXUI(node, params); + + if (output_node) + { + Params output_params(params); + setupParamsForExport(output_params, parent); + Params default_params(LLUICtrlFactory::getDefaultParams()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); + } + + setupParams(params, parent); + initFromParams(params); + + initFloater(); + LLMultiFloater* last_host = LLFloater::getFloaterHost(); if (node->hasName("multi_floater")) { LLFloater::setFloaterHost((LLMultiFloater*) this); } - initChildrenXML(node, factory); + LLUICtrlFactory::createChildren(this, node, child_registry_t::instance(), output_node); if (node->hasName("multi_floater")) { LLFloater::setFloaterHost(last_host); } + + BOOL result; + { + LLFastTimer ft(POST_BUILD); - BOOL result = postBuild(); + result = postBuild(); + } if (!result) { - llerrs << "Failed to construct floater " << name << llendl; + llerrs << "Failed to construct floater " << getName() << llendl; } - applyRectControl(); - if (open) /* Flawfinder: ignore */ - { - this->open(); /* Flawfinder: ignore */ - } + applyRectControl(); // If we have a saved rect control, apply it + gFloaterView->adjustToFitScreen(this, FALSE); // Floaters loaded from XML should all fit on screen moveResizeHandlesToFront(); } + diff --git a/indra/llui/llfloater.h b/indra/llui/llfloater.h index 0e3d148b09..ee066317e0 100644 --- a/indra/llui/llfloater.h +++ b/indra/llui/llfloater.h @@ -39,7 +39,6 @@ #include "llpanel.h" #include "lluuid.h" -#include "lltabcontainer.h" #include "llnotifications.h" #include @@ -50,17 +49,10 @@ class LLButton; class LLMultiFloater; class LLFloater; -const S32 LLFLOATER_VPAD = 6; -const S32 LLFLOATER_HPAD = 6; -const S32 LLFLOATER_CLOSE_BOX_SIZE = 16; -const S32 LLFLOATER_HEADER_SIZE = 18; const BOOL RESIZE_YES = TRUE; const BOOL RESIZE_NO = FALSE; -const S32 DEFAULT_MIN_WIDTH = 100; -const S32 DEFAULT_MIN_HEIGHT = 100; - const BOOL DRAG_ON_TOP = FALSE; const BOOL DRAG_ON_LEFT = TRUE; @@ -87,64 +79,86 @@ private: LLHandle mFloaterHandle; }; - class LLFloater : public LLPanel { friend class LLFloaterView; +friend class LLFloaterReg; +friend class LLMultiFloater; public: + struct KeyCompare + { + static bool compare(const LLSD& a, const LLSD& b); + static bool equate(const LLSD& a, const LLSD& b); + bool operator()(const LLSD& a, const LLSD& b) const + { + return compare(a, b); + } + }; + enum EFloaterButtons { - BUTTON_CLOSE, + BUTTON_CLOSE = 0, BUTTON_RESTORE, BUTTON_MINIMIZE, BUTTON_TEAR_OFF, BUTTON_EDIT, + BUTTON_DOCK, + BUTTON_UNDOCK, BUTTON_COUNT }; - LLFloater(); - LLFloater(const std::string& name); //simple constructor for data-driven initialization - LLFloater( const std::string& name, const LLRect& rect, const std::string& title, - BOOL resizable = FALSE, - S32 min_width = DEFAULT_MIN_WIDTH, - S32 min_height = DEFAULT_MIN_HEIGHT, - BOOL drag_on_left = FALSE, - BOOL minimizable = TRUE, - BOOL close_btn = TRUE, - BOOL bordered = BORDER_NO); + struct Params + : public LLInitParam::Block + { + Optional title, + short_title; + + Optional single_instance, + auto_tile, + can_resize, + can_minimize, + can_close, + can_drag_on_left, + can_tear_off, + save_rect, + save_visibility, + can_dock; + + Optional open_callback, + close_callback; + + Params(); + }; + + // use this to avoid creating your own default LLFloater::Param instance + static const Params& getDefaultParams(); - LLFloater( const std::string& name, const std::string& rect_control, const std::string& title, - BOOL resizable = FALSE, - S32 min_width = DEFAULT_MIN_WIDTH, - S32 min_height = DEFAULT_MIN_HEIGHT, - BOOL drag_on_left = FALSE, - BOOL minimizable = TRUE, - BOOL close_btn = TRUE, - BOOL bordered = BORDER_NO); + // Load translations for tooltips for standard buttons + static void initClass(); + + LLFloater(const LLSD& key, const Params& params = getDefaultParams()); virtual ~LLFloater(); - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - void initFloaterXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory, BOOL open = TRUE); + // Don't export top/left for rect, only height/width + static void setupParamsForExport(Params& p, LLView* parent); - /*virtual*/ void userSetShape(const LLRect& new_rect); + void initFromParams(const LLFloater::Params& p); + void initFloaterXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node = NULL); + + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); /*virtual*/ BOOL canSnapTo(const LLView* other_view); - /*virtual*/ void snappedTo(const LLView* snap_view); + /*virtual*/ void setSnappedTo(const LLView* snap_view); /*virtual*/ void setFocus( BOOL b ); /*virtual*/ void setIsChrome(BOOL is_chrome); + /*virtual*/ void setRect(const LLRect &rect); - // Can be called multiple times to reset floater parameters. - // Deletes all children of the floater. - virtual void initFloater(const std::string& title, BOOL resizable, - S32 min_width, S32 min_height, BOOL drag_on_left, - BOOL minimizable, BOOL close_btn); + void initFloater(); - virtual void open(); /* Flawfinder: ignore */ + void openFloater(const LLSD& key = LLSD()); // If allowed, close the floater cleanly, releasing focus. - // app_quitting is passed to onClose() below. - virtual void close(bool app_quitting = false); + void closeFloater(bool app_quitting = false); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); @@ -153,11 +167,8 @@ public: // moves to center of gFloaterView void center(); - // applies rectangle stored in mRectControl, if any - void applyRectControl(); - - LLMultiFloater* getHost() { return (LLMultiFloater*)mHostHandle.get(); } + LLMultiFloater* getHost(); void applyTitle(); const std::string& getCurrentTitle() const; @@ -185,9 +196,8 @@ public: void setResizeLimits( S32 min_width, S32 min_height ); void getResizeLimits( S32* min_width, S32* min_height ) { *min_width = mMinWidth; *min_height = mMinHeight; } - bool isMinimizeable() const{ return mButtonsEnabled[BUTTON_MINIMIZE]; } - // Does this window have a close button, NOT can we close it right now. - bool isCloseable() const{ return (mButtonsEnabled[BUTTON_CLOSE]); } + bool isMinimizeable() const{ return mCanMinimize; } + bool isCloseable() const{ return mCanClose; } bool isDragOnLeft() const{ return mDragOnLeft; } S32 getMinWidth() const{ return mMinWidth; } S32 getMinHeight() const{ return mMinHeight; } @@ -197,21 +207,19 @@ public: virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); virtual BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask); virtual void draw(); - - virtual void onOpen() {} - - // Call destroy() to free memory, or setVisible(FALSE) to keep it - // If app_quitting, you might not want to save your visibility. - // Defaults to destroy(). - virtual void onClose(bool app_quitting) { destroy(); } + + // *TODO: Eliminate this in favor of mOpenSignal + virtual void onOpen(const LLSD& key) {} // This cannot be "const" until all derived floater canClose() // methods are const as well. JC virtual BOOL canClose() { return TRUE; } - virtual void setVisible(BOOL visible); + /*virtual*/ void setVisible(BOOL visible); // do not override + /*virtual*/ void handleVisibilityChange ( BOOL new_visibility ); // do not override + void setFrontmost(BOOL take_focus = TRUE); - + // Defaults to false. virtual BOOL canSaveAs() const { return FALSE; } @@ -222,6 +230,16 @@ public: LLHandle getSnapTarget() const { return mSnappedTo; } LLHandle getHandle() const { return mHandle; } + const LLSD& getKey() { return mKey; } + BOOL matchesKey(const LLSD& key) { return mSingleInstance || KeyCompare::equate(key, mKey); } + + const std::string& getInstanceName() { return mInstanceName; } + + bool isDockable() const { return mCanDock; } + void setCanDock(bool b); + + bool isDocked() const { return mDocked; } + virtual void setDocked(bool docked, bool pop_on_undock = true); // Return a closeable floater, if any, given the current focus. static LLFloater* getClosableFloaterFromFocus(); @@ -235,62 +253,89 @@ public: return LLNotification::Params(name).context(mNotificationContext); } - static void onClickClose(void *userdata); - static void onClickMinimize(void *userdata); - static void onClickTearOff(void *userdata); - static void onClickEdit(void *userdata); + static void onClickClose(LLFloater* floater); + static void onClickMinimize(LLFloater* floater); + static void onClickTearOff(LLFloater* floater); + static void onClickEdit(LLFloater* floater); + static void onClickDock(LLFloater* floater); static void setFloaterHost(LLMultiFloater* hostp) {sHostp = hostp; } static void setEditModeEnabled(BOOL enable); static BOOL getEditModeEnabled() { return sEditModeEnabled; } - static LLMultiFloater* getFloaterHost() {return sHostp; } - + static LLMultiFloater* getFloaterHost() {return sHostp; } + protected: + void setRectControl(const std::string& rectname) { mRectControl = rectname; }; + void applyRectControl(); + void storeRectControl(); + void storeVisibilityControl(); + + void setKey(const LLSD& key); + void setInstanceName(const std::string& name); + virtual void bringToFront(S32 x, S32 y); virtual void setVisibleAndFrontmost(BOOL take_focus=TRUE); - void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized + void setExpandedRect(const LLRect& rect) { mExpandedRect = rect; } // size when not minimized const LLRect& getExpandedRect() const { return mExpandedRect; } void setAutoFocus(BOOL focus) { mAutoFocus = focus; } // whether to automatically take focus when opened LLDragHandle* getDragHandle() const { return mDragHandle; } - void destroy() { die(); } // Don't call this directly. You probably want to call close(). JC + void destroy() { die(); } // Don't call this directly. You probably want to call closeFloater() private: - void setForeground(BOOL b); // called only by floaterview void cleanupHandles(); // remove handles to dead floaters void createMinimizeButton(); void updateButtons(); void buildButtons(); BOOL offerClickToButton(S32 x, S32 y, MASK mask, EFloaterButtons index); + void addResizeCtrls(); + void addDragHandle(); + +protected: + std::string mRectControl; + std::string mVisibilityControl; + commit_signal_t mOpenSignal; // Called when floater is opened, passes mKey + commit_signal_t mCloseSignal; // Called when floater is closed, passes app_qitting as LLSD() + LLSD mKey; // Key used for retrieving instances; set (for now) by LLFLoaterReg - LLRect mExpandedRect; LLDragHandle* mDragHandle; LLResizeBar* mResizeBar[4]; LLResizeHandle* mResizeHandle[4]; - LLButton *mMinimizeButton; + +private: + LLRect mExpandedRect; + + LLUIString mTitle; + LLUIString mShortTitle; + + BOOL mSingleInstance; // TRUE if there is only ever one instance of the floater + std::string mInstanceName; // Store the instance name so we can remove ourselves from the list + BOOL mAutoTile; // TRUE if placement of new instances tiles + BOOL mCanTearOff; + BOOL mCanMinimize; + BOOL mCanClose; + BOOL mDragOnLeft; + BOOL mResizable; + + S32 mMinWidth; + S32 mMinHeight; + BOOL mMinimized; BOOL mForeground; LLHandle mDependeeHandle; - std::string mTitle; - std::string mShortTitle; + BOOL mFirstLook; // TRUE if the _next_ time this floater is visible will be the first time in the session that it is visible. - - BOOL mResizable; - S32 mMinWidth; - S32 mMinHeight; - BOOL mEditing; typedef std::set > handle_set_t; typedef std::set >::iterator handle_set_iter_t; handle_set_t mDependents; - bool mDragOnLeft; BOOL mButtonsEnabled[BUTTON_COUNT]; LLButton* mButtons[BUTTON_COUNT]; @@ -301,14 +346,21 @@ private: LLHandle mHostHandle; LLHandle mLastHostHandle; + bool mCanDock; + bool mDocked; + static LLMultiFloater* sHostp; static BOOL sEditModeEnabled; + static BOOL sQuitting; static std::string sButtonActiveImageNames[BUTTON_COUNT]; - static std::string sButtonInactiveImageNames[BUTTON_COUNT]; + // Images to use when cursor hovered over an enabled button + static std::string sButtonHoveredImageNames[BUTTON_COUNT]; static std::string sButtonPressedImageNames[BUTTON_COUNT]; static std::string sButtonNames[BUTTON_COUNT]; static std::string sButtonToolTips[BUTTON_COUNT]; - typedef void (*click_callback)(void *); + static std::string sButtonToolTipsIndex[BUTTON_COUNT]; + + typedef void(*click_callback)(LLFloater*); static click_callback sButtonCallbacks[BUTTON_COUNT]; typedef std::map, LLFloater*> handle_map_t; @@ -320,29 +372,33 @@ private: BOOL mHasBeenDraggedWhileMinimized; S32 mPreviousMinimizedBottom; S32 mPreviousMinimizedLeft; - + + LLColor4 mBgColorAlpha; + LLColor4 mBgColorOpaque; + LLFloaterNotificationContext* mNotificationContext; LLRootHandle mHandle; }; + ///////////////////////////////////////////////////////////// // LLFloaterView // Parent of all floating panels class LLFloaterView : public LLUICtrl { -public: - LLFloaterView( const std::string& name, const LLRect& rect ); +protected: + LLFloaterView (const Params& p); + friend class LLUICtrlFactory; +public: /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); void reshapeFloater(S32 width, S32 height, BOOL called_from_parent, BOOL adjust_vertical); /*virtual*/ void draw(); /*virtual*/ LLRect getSnapRect() const; - void refresh(); + /*virtual*/ void refresh(); - void getNewFloaterPosition( S32* left, S32* top ); - void resetStartingFloaterPosition(); LLRect findNeighboringPosition( LLFloater* reference_floater, LLFloater* neighbor ); // Given a child of gFloaterView, make sure this view can fit entirely onscreen. @@ -365,10 +421,10 @@ public: void closeAllChildren(bool app_quitting); BOOL allChildrenClosed(); - LLFloater* getFrontmost(); - LLFloater* getBackmost(); - LLFloater* getParentFloater(LLView* viewp); - LLFloater* getFocusedFloater(); + LLFloater* getFrontmost() const; + LLFloater* getBackmost() const; + LLFloater* getParentFloater(LLView* viewp) const; + LLFloater* getFocusedFloater() const; void syncFloaterTabOrder(); // Returns z order of child provided. 0 is closest, larger numbers @@ -377,6 +433,7 @@ public: S32 getZOrder(LLFloater* child); void setSnapOffsetBottom(S32 offset) { mSnapOffsetBottom = offset; } + void setSnapOffsetRight(S32 offset) { mSnapOffsetRight = offset; } private: S32 mColumn; @@ -384,110 +441,12 @@ private: S32 mNextTop; BOOL mFocusCycleMode; S32 mSnapOffsetBottom; + S32 mSnapOffsetRight; }; -// https://wiki.lindenlab.com/mediawiki/index.php?title=LLMultiFloater&oldid=81376 -class LLMultiFloater : public LLFloater -{ -public: - LLMultiFloater(); - LLMultiFloater(LLTabContainer::TabPosition tab_pos); - LLMultiFloater(const std::string& name); - LLMultiFloater(const std::string& name, const LLRect& rect, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); - LLMultiFloater(const std::string& name, const std::string& rect_control, LLTabContainer::TabPosition tab_pos = LLTabContainer::TOP, BOOL auto_resize = TRUE); - virtual ~LLMultiFloater() {}; - - virtual BOOL postBuild(); - /*virtual*/ void open(); /* Flawfinder: ignore */ - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void draw(); - /*virtual*/ void setVisible(BOOL visible); - /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); - - virtual void setCanResize(BOOL can_resize); - virtual void growToFit(S32 content_width, S32 content_height); - virtual void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); - - virtual void showFloater(LLFloater* floaterp); - virtual void removeFloater(LLFloater* floaterp); - - virtual void tabOpen(LLFloater* opened_floater, bool from_click); - virtual void tabClose(); - - virtual BOOL selectFloater(LLFloater* floaterp); - virtual void selectNextFloater(); - virtual void selectPrevFloater(); - - virtual LLFloater* getActiveFloater(); - virtual BOOL isFloaterFlashing(LLFloater* floaterp); - virtual S32 getFloaterCount(); - - virtual void setFloaterFlashing(LLFloater* floaterp, BOOL flashing); - virtual BOOL closeAllFloaters(); //Returns FALSE if the floater could not be closed due to pending confirmation dialogs - void setTabContainer(LLTabContainer* tab_container) { if (!mTabContainer) mTabContainer = tab_container; } - static void onTabSelected(void* userdata, bool); - - virtual void updateResizeLimits(); - -protected: - struct LLFloaterData - { - S32 mWidth; - S32 mHeight; - BOOL mCanMinimize; - BOOL mCanResize; - }; - - LLTabContainer* mTabContainer; - - typedef std::map, LLFloaterData> floater_data_map_t; - floater_data_map_t mFloaterDataMap; - - LLTabContainer::TabPosition mTabPos; - BOOL mAutoResize; - S32 mOrigMinWidth, mOrigMinHeight; // logically const but initialized late -}; - -// visibility policy specialized for floaters -template<> -class VisibilityPolicy -{ -public: - // visibility methods - static bool visible(LLFloater* instance, const LLSD& key) - { - if (instance) - { - return !instance->isMinimized() && instance->isInVisibleChain(); - } - return FALSE; - } - - static void show(LLFloater* instance, const LLSD& key) - { - if (instance) - { - instance->open(); - if (instance->getHost()) - { - instance->getHost()->open(); - } - } - } - - static void hide(LLFloater* instance, const LLSD& key) - { - if (instance) instance->close(); - } -}; - - -// singleton implementation for floaters (provides visibility policy) -// https://wiki.lindenlab.com/mediawiki/index.php?title=LLFloaterSingleton&oldid=164990 - -template class LLFloaterSingleton : public LLUISingleton > -{ -}; +// +// Globals +// extern LLFloaterView* gFloaterView; diff --git a/indra/llui/llfloaterreg.cpp b/indra/llui/llfloaterreg.cpp new file mode 100644 index 0000000000..a63b1b085c --- /dev/null +++ b/indra/llui/llfloaterreg.cpp @@ -0,0 +1,440 @@ +/** + * @file llfloaterreg.cpp + * @brief LLFloaterReg Floater Registration Class + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfloaterreg.h" + +#include "llfloater.h" +#include "llmultifloater.h" + +//******************************************************* + +//static +LLFloaterReg::instance_list_t LLFloaterReg::sNullInstanceList; +LLFloaterReg::instance_map_t LLFloaterReg::sInstanceMap; +LLFloaterReg::build_map_t LLFloaterReg::sBuildMap; +std::map LLFloaterReg::sGroupMap; + +//******************************************************* + +//static +void LLFloaterReg::add(const std::string& name, const std::string& filename, const LLFloaterBuildFunc& func, const std::string& groupname) +{ + sBuildMap[name].mFunc = func; + sBuildMap[name].mFile = filename; + sGroupMap[name] = groupname.empty() ? name : groupname; + sGroupMap[groupname] = groupname; // for referencing directly by group name +} + +//static +LLRect LLFloaterReg::getFloaterRect(const std::string& name) +{ + LLRect rect; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + if (!list.empty()) + { + static LLUICachedControl floater_offset ("UIFloaterOffset", 16); + LLFloater* last_floater = list.back(); + if (last_floater->getHost()) + { + rect = last_floater->getHost()->getRect(); + } + else + { + rect = last_floater->getRect(); + } + rect.translate(floater_offset, -floater_offset); + } + } + return rect; +} + +//static +LLFloater* LLFloaterReg::findInstance(const std::string& name, const LLSD& key) +{ + LLFloater* res = NULL; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* inst = *iter; + if (inst->matchesKey(key)) + { + res = inst; + break; + } + } + } + return res; +} + +//static +LLFloater* LLFloaterReg::getInstance(const std::string& name, const LLSD& key) +{ + LLFloater* res = findInstance(name, key); + if (!res) + { + const LLFloaterBuildFunc& build_func = sBuildMap[name].mFunc; + const std::string& xui_file = sBuildMap[name].mFile; + if (build_func) + { + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + int index = list.size(); + + res = build_func(key); + + LLUICtrlFactory::getInstance()->buildFloater(res, xui_file, NULL); + + // Note: key should eventually be a non optional LLFloater arg; for now, set mKey to be safe + res->mKey = key; + res->setInstanceName(name); + res->applyRectControl(); // Can't apply rect control until setting instance name + if (res->mAutoTile && !res->getHost() && index > 0) + { + const LLRect& cur_rect = res->getRect(); + LLRect next_rect = getFloaterRect(groupname); + next_rect.setLeftTopAndSize(next_rect.mLeft, next_rect.mTop, cur_rect.getWidth(), cur_rect.getHeight()); + res->setRect(next_rect); + res->setRectControl(LLStringUtil::null); // don't save rect of tiled floaters + gFloaterView->adjustToFitScreen(res, true); + } + else + { + gFloaterView->adjustToFitScreen(res, false); + } + list.push_back(res); + } + } + if (!res) + { + llwarns << "Floater type: '" << name << "' not registered." << llendl; + } + } + return res; +} + +//static +LLFloater* LLFloaterReg::removeInstance(const std::string& name, const LLSD& key) +{ + LLFloater* res = NULL; + const std::string& groupname = sGroupMap[name]; + if (!groupname.empty()) + { + instance_list_t& list = sInstanceMap[groupname]; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* inst = *iter; + if (inst->matchesKey(key)) + { + res = inst; + list.erase(iter); + break; + } + } + } + return res; +} + +//static +// returns true if the instance existed +bool LLFloaterReg::destroyInstance(const std::string& name, const LLSD& key) +{ + LLFloater* inst = removeInstance(name, key); + if (inst) + { + delete inst; + return true; + } + else + { + return false; + } +} + +// Iterators +//static +LLFloaterReg::const_instance_list_t& LLFloaterReg::getFloaterList(const std::string& name) +{ + instance_map_t::iterator iter = sInstanceMap.find(name); + if (iter != sInstanceMap.end()) + { + return iter->second; + } + else + { + return sNullInstanceList; + } +} + +// Visibility Management + +//static +LLFloater* LLFloaterReg::showInstance(const std::string& name, const LLSD& key, BOOL focus) +{ + LLFloater* instance = getInstance(name, key); + if (instance) + { + instance->openFloater(key); + if (focus) + instance->setFocus(TRUE); + } + return instance; +} + +//static +// returns true if the instance exists +bool LLFloaterReg::hideInstance(const std::string& name, const LLSD& key) +{ + LLFloater* instance = findInstance(name, key); + if (instance) + { + // When toggling *visibility*, close the host instead of the floater when hosted + if (instance->getHost()) + instance->getHost()->closeFloater(); + else + instance->closeFloater(); + return true; + } + else + { + return false; + } +} + +//static +// returns true if the instance is visible when completed +bool LLFloaterReg::toggleInstance(const std::string& name, const LLSD& key) +{ + LLFloater* instance = findInstance(name, key); + if (instance && !instance->isMinimized() && instance->isInVisibleChain()) + { + // When toggling *visibility*, close the host instead of the floater when hosted + if (instance->getHost()) + instance->getHost()->closeFloater(); + else + instance->closeFloater(); + return false; + } + else + { + return showInstance(name, key, TRUE) ? true : false; + } +} + +//static +// returns true if the instance exists and is visible +bool LLFloaterReg::instanceVisible(const std::string& name, const LLSD& key) +{ + LLFloater* instance = findInstance(name, key); + if (instance && !instance->isMinimized() && instance->isInVisibleChain()) + { + return true; + } + else + { + return false; + } +} + +//static +void LLFloaterReg::showInitialVisibleInstances() +{ + // Iterate through alll registered instance names and show any with a save visible state + for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) + { + const std::string& name = iter->first; + std::string controlname = getVisibilityControlName(name); + if (LLUI::sSettingGroups["floater"]->controlExists(controlname)) + { + BOOL isvis = LLUI::sSettingGroups["floater"]->getBOOL(controlname); + if (isvis) + { + showInstance(name, LLSD()); // keyed floaters shouldn't set save_vis to true + } + } + } +} + +//static +void LLFloaterReg::hideVisibleInstances(const std::set& exceptions) +{ + // Iterate through alll active instances and hide them + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + const std::string& name = iter->first; + if (exceptions.find(name) != exceptions.end()) + continue; + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->pushVisible(FALSE); + } + } +} + +//static +void LLFloaterReg::restoreVisibleInstances() +{ + // Iterate through all active instances and restore visibility + for (instance_map_t::iterator iter = sInstanceMap.begin(); iter != sInstanceMap.end(); ++iter) + { + instance_list_t& list = iter->second; + for (instance_list_t::iterator iter = list.begin(); iter != list.end(); ++iter) + { + LLFloater* floater = *iter; + floater->popVisible(); + } + } +} + +//static +std::string LLFloaterReg::getRectControlName(const std::string& name) +{ + std::string res = std::string("floater_rect_") + name; + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; +} + +//static +std::string LLFloaterReg::declareRectControl(const std::string& name) +{ + std::string controlname = getRectControlName(name); + LLUI::sSettingGroups["floater"]->declareRect(controlname, LLRect(), + llformat("Window Position and Size for %s", name.c_str()), + TRUE); + return controlname; +} + +//static +std::string LLFloaterReg::getVisibilityControlName(const std::string& name) +{ + std::string res = std::string("floater_vis_") + name; + LLStringUtil::replaceChar( res, ' ', '_' ); + return res; +} + +//static +std::string LLFloaterReg::declareVisibilityControl(const std::string& name) +{ + std::string controlname = getVisibilityControlName(name); + LLUI::sSettingGroups["floater"]->declareBOOL(controlname, FALSE, + llformat("Window Visibility for %s", name.c_str()), + TRUE); + return controlname; +} + +//static +void LLFloaterReg::registerControlVariables() +{ + // Iterate through alll registered instance names and register rect and visibility control variables + for (build_map_t::iterator iter = sBuildMap.begin(); iter != sBuildMap.end(); ++iter) + { + const std::string& name = iter->first; + if (LLUI::sSettingGroups["floater"]->controlExists(getRectControlName(name))) + { + declareRectControl(name); + } + if (LLUI::sSettingGroups["floater"]->controlExists(getVisibilityControlName(name))) + { + declareVisibilityControl(name); + } + } +} + +// Callbacks + +// static +// Call once (i.e use for init callbacks) +void LLFloaterReg::initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname) +{ + // Get the visibility control name for the floater + std::string vis_control_name = LLFloaterReg::declareVisibilityControl(sdname.asString()); + // Set the control value to the floater visibility control (Sets the value as well) + ctrl->setControlVariable(LLUI::sSettingGroups["floater"]->getControl(vis_control_name)); +} + +// callback args may use "floatername.key" format +static void parse_name_key(std::string& name, LLSD& key) +{ + std::string instname = name; + std::size_t dotpos = instname.find("."); + if (dotpos != std::string::npos) + { + name = instname.substr(0, dotpos); + key = LLSD(instname.substr(dotpos+1, std::string::npos)); + } +} + +//static +void LLFloaterReg::showFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + showInstance(name, key, TRUE); +} +//static +void LLFloaterReg::hideFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + hideInstance(name, key); +} +//static +void LLFloaterReg::toggleFloaterInstance(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + toggleInstance(name, key); +} + +//static +bool LLFloaterReg::floaterInstanceVisible(const LLSD& sdname) +{ + LLSD key; + std::string name = sdname.asString(); + parse_name_key(name, key); + return instanceVisible(name, key); +} + diff --git a/indra/llui/llfloaterreg.h b/indra/llui/llfloaterreg.h new file mode 100644 index 0000000000..7edac43c96 --- /dev/null +++ b/indra/llui/llfloaterreg.h @@ -0,0 +1,153 @@ +/** + * @file llfloaterreg.h + * @brief LLFloaterReg Floater Registration Class + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLFLOATERREG_H +#define LLFLOATERREG_H + +/// llcommon +#include "llboost.h" +#include "llrect.h" +#include "llstl.h" +#include "llsd.h" + +/// llui +#include "lluictrl.h" + +#include + +//******************************************************* +// +// Floater Class Registry +// + +class LLFloater; + +typedef boost::function LLFloaterBuildFunc; + +class LLFloaterReg +{ +public: + // We use a list of LLFloater's instead of a set for two reasons: + // 1) With a list we have a predictable ordering, useful for finding the last opened floater of a given type. + // 2) We can change the key of a floater without altering the list. + typedef std::list instance_list_t; + typedef const instance_list_t const_instance_list_t; + typedef std::map instance_map_t; + + struct BuildData + { + LLFloaterBuildFunc mFunc; + std::string mFile; + }; + typedef std::map build_map_t; + +private: + static instance_list_t sNullInstanceList; + static instance_map_t sInstanceMap; + static build_map_t sBuildMap; + static std::map sGroupMap; + +public: + // Registration + + // usage: LLFloaterClassRegistry::add("foo", (LLFloaterBuildFunc)&LLFloaterClassRegistry::build); + template + static LLFloater* build(const LLSD& key) + { + T* floater = new T(key); + return floater; + } + + static void add(const std::string& name, const std::string& file, const LLFloaterBuildFunc& func, + const std::string& groupname = LLStringUtil::null); + + // Helpers + static LLRect getFloaterRect(const std::string& name); + + // Find / get (create) / remove / destroy + static LLFloater* findInstance(const std::string& name, const LLSD& key = LLSD()); + static LLFloater* getInstance(const std::string& name, const LLSD& key = LLSD()); + static LLFloater* removeInstance(const std::string& name, const LLSD& key = LLSD()); + static bool destroyInstance(const std::string& name, const LLSD& key = LLSD()); + + // Iterators + static const_instance_list_t& getFloaterList(const std::string& name); + + // Visibility Management + // return NULL if instance not found or can't create instance (no builder) + static LLFloater* showInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE); + // Close a floater (may destroy or set invisible) + // return false if can't find instance + static bool hideInstance(const std::string& name, const LLSD& key = LLSD()); + // return true if instance is visible: + static bool toggleInstance(const std::string& name, const LLSD& key = LLSD()); + static bool instanceVisible(const std::string& name, const LLSD& key = LLSD()); + + static void showInitialVisibleInstances(); + static void hideVisibleInstances(const std::set& exceptions = std::set()); + static void restoreVisibleInstances(); + + // Control Variables + static std::string getRectControlName(const std::string& name); + static std::string declareRectControl(const std::string& name); + static std::string getVisibilityControlName(const std::string& name); + static std::string declareVisibilityControl(const std::string& name); + static void registerControlVariables(); + + // Callback wrappers + static void initUICtrlToFloaterVisibilityControl(LLUICtrl* ctrl, const LLSD& sdname); + static void showFloaterInstance(const LLSD& sdname); + static void hideFloaterInstance(const LLSD& sdname); + static void toggleFloaterInstance(const LLSD& sdname); + static bool floaterInstanceVisible(const LLSD& sdname); + + // Typed find / get / show + template + static T* findTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast(findInstance(name, key)); + } + + template + static T* getTypedInstance(const std::string& name, const LLSD& key = LLSD()) + { + return dynamic_cast(getInstance(name, key)); + } + + template + static T* showTypedInstance(const std::string& name, const LLSD& key = LLSD(), BOOL focus = FALSE) + { + return dynamic_cast(showInstance(name, key, focus)); + } + +}; + +#endif diff --git a/indra/llui/llflyoutbutton.cpp b/indra/llui/llflyoutbutton.cpp new file mode 100644 index 0000000000..3483bac782 --- /dev/null +++ b/indra/llui/llflyoutbutton.cpp @@ -0,0 +1,82 @@ +/** + * @file llflyoutbutton.cpp + * @brief LLFlyoutButton base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +// file includes +#include "llflyoutbutton.h" + +//static LLDefaultChildRegistry::Register r2("flyout_button"); + +const S32 FLYOUT_BUTTON_ARROW_WIDTH = 24; + +LLFlyoutButton::LLFlyoutButton(const Params& p) +: LLComboBox(p), + mToggleState(FALSE), + mActionButton(NULL) +{ + // Always use text box + // Text label button + LLButton::Params bp(p.action_button); + bp.name(p.label); + bp.rect.left(0).bottom(0).width(getRect().getWidth() - FLYOUT_BUTTON_ARROW_WIDTH).height(getRect().getHeight()); + bp.click_callback.function(boost::bind(&LLFlyoutButton::onActionButtonClick, this, _2)); + bp.follows.flags(FOLLOWS_ALL); + + mActionButton = LLUICtrlFactory::create(bp); + addChild(mActionButton); +} + +void LLFlyoutButton::onActionButtonClick(const LLSD& data) +{ + // remember last list selection? + mList->deselect(); + onCommit(); +} + +void LLFlyoutButton::draw() +{ + mActionButton->setToggleState(mToggleState); + mButton->setToggleState(mToggleState); + + //FIXME: this should be an attribute of comboboxes, whether they have a distinct label or + // the label reflects the last selected item, for now we have to manually remove the label + setLabel(LLStringUtil::null); + LLComboBox::draw(); +} + +void LLFlyoutButton::setToggleState(BOOL state) +{ + mToggleState = state; +} + + diff --git a/indra/llui/llflyoutbutton.h b/indra/llui/llflyoutbutton.h new file mode 100644 index 0000000000..d8c0f1a50d --- /dev/null +++ b/indra/llui/llflyoutbutton.h @@ -0,0 +1,74 @@ +/** + * @file llflyoutbutton.h + * @brief LLFlyoutButton base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// A control that displays the name of the chosen item, which when clicked +// shows a scrolling box of choices. + +#ifndef LL_LLFLYOUTBUTTON_H +#define LL_LLFLYOUTBUTTON_H + +#include "llcombobox.h" + +// Classes + +class LLFlyoutButton : public LLComboBox +{ +public: + struct Params : public LLInitParam::Block + { + Optional action_button; + Deprecated allow_text_entry; + + Params() + : action_button("action_button"), + allow_text_entry("allow_text_entry") + { + LLComboBox::Params::allow_text_entry = false; + } + + }; +protected: + LLFlyoutButton(const Params&); + friend class LLUICtrlFactory; +public: + virtual void draw(); + + void setToggleState(BOOL state); + + void onActionButtonClick(const LLSD& data); + +protected: + LLButton* mActionButton; + BOOL mToggleState; +}; + +#endif // LL_LLFLYOUTBUTTON_H diff --git a/indra/llui/llfocusmgr.cpp b/indra/llui/llfocusmgr.cpp index 661ffdd467..60ddbc6cb3 100644 --- a/indra/llui/llfocusmgr.cpp +++ b/indra/llui/llfocusmgr.cpp @@ -38,6 +38,77 @@ const F32 FOCUS_FADE_TIME = 0.3f; +// NOTE: the LLFocusableElement implementation has been moved here from lluictrl.cpp. + +LLFocusableElement::LLFocusableElement() +: mFocusLostCallback(NULL), + mFocusReceivedCallback(NULL), + mFocusChangedCallback(NULL), + mTopLostCallback(NULL), + mFocusCallbackUserData(NULL) +{ +} + +// virtual +BOOL LLFocusableElement::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + return FALSE; +} + +// virtual +BOOL LLFocusableElement::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) +{ + return FALSE; +} + +// virtual +LLFocusableElement::~LLFocusableElement() +{ +} + +void LLFocusableElement::onFocusReceived() +{ + if( mFocusReceivedCallback ) + { + mFocusReceivedCallback( this, mFocusCallbackUserData ); + } + if( mFocusChangedCallback ) + { + mFocusChangedCallback( this, mFocusCallbackUserData ); + } +} + +void LLFocusableElement::onFocusLost() +{ + if( mFocusLostCallback ) + { + mFocusLostCallback( this, mFocusCallbackUserData ); + } + + if( mFocusChangedCallback ) + { + mFocusChangedCallback( this, mFocusCallbackUserData ); + } +} + +void LLFocusableElement::onTopLost() +{ + if (mTopLostCallback) + { + mTopLostCallback(this, mFocusCallbackUserData); + } +} + +BOOL LLFocusableElement::hasFocus() const +{ + return gFocusMgr.getKeyboardFocus() == this; +} + +void LLFocusableElement::setFocus(BOOL b) +{ +} + + LLFocusMgr gFocusMgr; LLFocusMgr::LLFocusMgr() @@ -49,7 +120,6 @@ LLFocusMgr::LLFocusMgr() mDefaultKeyboardFocus( NULL ), mKeystrokesOnly(FALSE), mTopCtrl( NULL ), - mFocusWeight(0.f), mAppHasFocus(TRUE) // Macs don't seem to notify us that we've gotten focus, so default to true #ifdef _DEBUG , mMouseCaptorName("none") @@ -87,19 +157,25 @@ void LLFocusMgr::releaseFocusIfNeeded( const LLView* view ) } -void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystrokes_only) +void LLFocusMgr::setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock, BOOL keystrokes_only) { + // notes if keyboard focus is changed again (by onFocusLost/onFocusReceived) + // making the rest of our processing unnecessary since it will already be + // handled by the recursive call + static bool focus_dirty; + focus_dirty = false; + if (mLockedView && (new_focus == NULL || - (new_focus != mLockedView && !new_focus->hasAncestor(mLockedView)))) + (new_focus != mLockedView + && dynamic_cast(new_focus) + && !dynamic_cast(new_focus)->hasAncestor(mLockedView)))) { // don't allow focus to go to anything that is not the locked focus // or one of its descendants return; } - //llinfos << "Keyboard focus handled by " << (new_focus ? new_focus->getName() : "nothing") << llendl; - mKeystrokesOnly = keystrokes_only; if( new_focus != mKeyboardFocus ) @@ -107,21 +183,65 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke mLastKeyboardFocus = mKeyboardFocus; mKeyboardFocus = new_focus; - if( mLastKeyboardFocus ) + // list of the focus and it's ancestors + view_handle_list_t old_focus_list = mCachedKeyboardFocusList; + view_handle_list_t new_focus_list; + + // walk up the tree to root and add all views to the new_focus_list + for (LLView* ctrl = dynamic_cast(mKeyboardFocus); ctrl && ctrl != LLUI::getRootView(); ctrl = ctrl->getParent()) { - mLastKeyboardFocus->onFocusLost(); + if (ctrl) + { + new_focus_list.push_back(ctrl->getHandle()); + } } - // clear out any existing flash - if (new_focus) + // remove all common ancestors since their focus is unchanged + while (!new_focus_list.empty() && + !old_focus_list.empty() && + new_focus_list.back() == old_focus_list.back()) { - mFocusWeight = 0.f; - new_focus->onFocusReceived(); + new_focus_list.pop_back(); + old_focus_list.pop_back(); + } + + // walk up the old focus branch calling onFocusLost + // we bubble up the tree to release focus, and back down to add + for (view_handle_list_t::iterator old_focus_iter = old_focus_list.begin(); + old_focus_iter != old_focus_list.end() && !focus_dirty; + old_focus_iter++) + { + LLView* old_focus_view = old_focus_iter->get(); + if (old_focus_view) + { + mCachedKeyboardFocusList.pop_front(); + old_focus_view->onFocusLost(); + } + } + + // walk down the new focus branch calling onFocusReceived + for (view_handle_list_t::reverse_iterator new_focus_riter = new_focus_list.rbegin(); + new_focus_riter != new_focus_list.rend() && !focus_dirty; + new_focus_riter++) + { + LLView* new_focus_view = new_focus_riter->get(); + if (new_focus_view) + { + mCachedKeyboardFocusList.push_front(new_focus_view->getHandle()); + new_focus_view->onFocusReceived(); + } + } + + // if focus was changed as part of an onFocusLost or onFocusReceived call + // stop iterating on current list since it is now invalid + if (focus_dirty) + { + return; } - mFocusTimer.reset(); #ifdef _DEBUG - mKeyboardFocusName = new_focus ? new_focus->getName() : std::string("none"); + LLUICtrl* focus_ctrl = dynamic_cast(new_focus); + mKeyboardFocusName = focus_ctrl ? focus_ctrl->getName() : std::string("none"); #endif // If we've got a default keyboard focus, and the caller is @@ -131,8 +251,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke mDefaultKeyboardFocus->setFocus(TRUE); } - LLView* focus_subtree = mKeyboardFocus; - LLView* viewp = mKeyboardFocus; + LLView* focus_subtree = dynamic_cast(mKeyboardFocus); + LLView* viewp = dynamic_cast(mKeyboardFocus); // find root-most focus root while(viewp) { @@ -146,7 +266,8 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke if (focus_subtree) { - mFocusHistory[focus_subtree->getHandle()] = mKeyboardFocus ? mKeyboardFocus->getHandle() : LLHandle(); + LLView* focused_view = dynamic_cast(mKeyboardFocus); + mFocusHistory[focus_subtree->getHandle()] = focused_view ? focused_view->getHandle() : LLHandle(); } } @@ -154,13 +275,15 @@ void LLFocusMgr::setKeyboardFocus(LLUICtrl* new_focus, BOOL lock, BOOL keystroke { lockFocus(); } + + focus_dirty = true; } // Returns TRUE is parent or any descedent of parent has keyboard focus. BOOL LLFocusMgr::childHasKeyboardFocus(const LLView* parent ) const { - LLView* focus_view = mKeyboardFocus; + LLView* focus_view = dynamic_cast(mKeyboardFocus); while( focus_view ) { if( focus_view == parent ) @@ -190,7 +313,7 @@ BOOL LLFocusMgr::childHasMouseCapture( const LLView* parent ) const return FALSE; } -void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLView* focus ) +void LLFocusMgr::removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ) { // should be ok to unlock here, as you have to know the locked view // in order to unlock it @@ -220,24 +343,19 @@ void LLFocusMgr::setMouseCapture( LLMouseHandler* new_captor ) { LLMouseHandler* old_captor = mMouseCaptor; mMouseCaptor = new_captor; - /* - if (new_captor) + + if (LLView::sDebugMouseHandling) { - if ( new_captor->getName() == "Stickto") + if (new_captor) { llinfos << "New mouse captor: " << new_captor->getName() << llendl; } else { - llinfos << "New mouse captor: " << new_captor->getName() << llendl; + llinfos << "New mouse captor: NULL" << llendl; } } - else - { - llinfos << "New mouse captor: NULL" << llendl; - } - */ - + if( old_captor ) { old_captor->onMouseCaptureLost(); @@ -295,7 +413,7 @@ void LLFocusMgr::setTopCtrl( LLUICtrl* new_top ) if (old_top) { - old_top->onLostTop(); + old_top->onTopLost(); } } } @@ -313,7 +431,7 @@ void LLFocusMgr::removeTopCtrlWithoutCallback( const LLUICtrl* top_view ) void LLFocusMgr::lockFocus() { - mLockedView = mKeyboardFocus; + mLockedView = dynamic_cast(mKeyboardFocus); } void LLFocusMgr::unlockFocus() @@ -323,12 +441,13 @@ void LLFocusMgr::unlockFocus() F32 LLFocusMgr::getFocusFlashAmt() const { - return clamp_rescale(getFocusTime(), 0.f, FOCUS_FADE_TIME, mFocusWeight, 0.f); + return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f); } LLColor4 LLFocusMgr::getFocusColor() const { - LLColor4 focus_color = lerp(LLUI::sColorsGroup->getColor( "FocusColor" ), LLColor4::white, getFocusFlashAmt()); + static LLUIColor focus_color_cached = LLUIColorTable::instance().getColor("FocusColor"); + LLColor4 focus_color = lerp(focus_color_cached, LLColor4::white, getFocusFlashAmt()); // de-emphasize keyboard focus when app has lost focus (to avoid typing into wrong window problem) if (!mAppHasFocus) { @@ -339,8 +458,7 @@ LLColor4 LLFocusMgr::getFocusColor() const void LLFocusMgr::triggerFocusFlash() { - mFocusTimer.reset(); - mFocusWeight = 1.f; + mFocusFlashTimer.reset(); } void LLFocusMgr::setAppHasFocus(BOOL focus) diff --git a/indra/llui/llfocusmgr.h b/indra/llui/llfocusmgr.h index aaeb25a870..d0adadd6d3 100644 --- a/indra/llui/llfocusmgr.h +++ b/indra/llui/llfocusmgr.h @@ -37,10 +37,44 @@ #include "llstring.h" #include "llframetimer.h" -#include "llview.h" +#include "llui.h" class LLUICtrl; class LLMouseHandler; +class LLView; + +// NOTE: the LLFocusableElement class declaration has been moved here from lluictrl.h. +class LLFocusableElement +{ + friend class LLFocusMgr; // allow access to focus change handlers +public: + LLFocusableElement(); + virtual ~LLFocusableElement(); + + virtual void setFocus( BOOL b ); + virtual BOOL hasFocus() const; + + typedef boost::function focus_callback_t; + void setFocusLostCallback(focus_callback_t cb, void* user_data = NULL) { mFocusLostCallback = cb; mFocusCallbackUserData = user_data; } + void setFocusReceivedCallback(focus_callback_t cb, void* user_data = NULL) { mFocusReceivedCallback = cb; mFocusCallbackUserData = user_data; } + void setFocusChangedCallback(focus_callback_t cb, void* user_data = NULL ) { mFocusChangedCallback = cb; mFocusCallbackUserData = user_data; } + void setTopLostCallback(focus_callback_t cb, void* user_data = NULL ) { mTopLostCallback = cb; mFocusCallbackUserData = user_data; } + + // These were brought up the hierarchy from LLView so that we don't have to use dynamic_cast when dealing with keyboard focus. + virtual BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + virtual BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + +protected: + virtual void onFocusReceived(); + virtual void onFocusLost(); + virtual void onTopLost(); // called when registered as top ctrl and user clicks elsewhere + focus_callback_t mFocusLostCallback; + focus_callback_t mFocusReceivedCallback; + focus_callback_t mFocusChangedCallback; + focus_callback_t mTopLostCallback; + void* mFocusCallbackUserData; +}; + class LLFocusMgr { @@ -55,15 +89,14 @@ public: BOOL childHasMouseCapture( const LLView* parent ) const; // Keyboard Focus - void setKeyboardFocus(LLUICtrl* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. - LLUICtrl* getKeyboardFocus() const { return mKeyboardFocus; } - LLUICtrl* getLastKeyboardFocus() const { return mLastKeyboardFocus; } + void setKeyboardFocus(LLFocusableElement* new_focus, BOOL lock = FALSE, BOOL keystrokes_only = FALSE); // new_focus = NULL to release the focus. + LLFocusableElement* getKeyboardFocus() const { return mKeyboardFocus; } + LLFocusableElement* getLastKeyboardFocus() const { return mLastKeyboardFocus; } BOOL childHasKeyboardFocus( const LLView* parent ) const; - void removeKeyboardFocusWithoutCallback( const LLView* focus ); + void removeKeyboardFocusWithoutCallback( const LLFocusableElement* focus ); BOOL getKeystrokesOnly() { return mKeystrokesOnly; } void setKeystrokesOnly(BOOL keystrokes_only) { mKeystrokesOnly = keystrokes_only; } - F32 getFocusTime() const { return mFocusTimer.getElapsedTimeF32(); } F32 getFocusFlashAmt() const; S32 getFocusFlashWidth() const { return llround(lerp(1.f, 3.f, getFocusFlashAmt())); } LLColor4 getFocusColor() const; @@ -75,8 +108,8 @@ public: // If setKeyboardFocus(NULL) is called, and there is a non-NULL default // keyboard focus view, focus goes there. JC - void setDefaultKeyboardFocus(LLUICtrl* default_focus) { mDefaultKeyboardFocus = default_focus; } - LLUICtrl* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } + void setDefaultKeyboardFocus(LLFocusableElement* default_focus) { mDefaultKeyboardFocus = default_focus; } + LLFocusableElement* getDefaultKeyboardFocus() const { return mDefaultKeyboardFocus; } // Top View @@ -98,16 +131,19 @@ private: LLMouseHandler* mMouseCaptor; // Mouse events are premptively routed to this object // Keyboard Focus - LLUICtrl* mKeyboardFocus; // Keyboard events are preemptively routed to this object - LLUICtrl* mLastKeyboardFocus; // who last had focus - LLUICtrl* mDefaultKeyboardFocus; + LLFocusableElement* mKeyboardFocus; // Keyboard events are preemptively routed to this object + LLFocusableElement* mLastKeyboardFocus; // who last had focus + LLFocusableElement* mDefaultKeyboardFocus; BOOL mKeystrokesOnly; + + // caching list of keyboard focus ancestors for calling onFocusReceived and onFocusLost + typedef std::list > view_handle_list_t; + view_handle_list_t mCachedKeyboardFocusList; // Top View LLUICtrl* mTopCtrl; - LLFrameTimer mFocusTimer; - F32 mFocusWeight; + LLFrameTimer mFocusFlashTimer; BOOL mAppHasFocus; diff --git a/indra/llui/llfunctorregistry.h b/indra/llui/llfunctorregistry.h index 8864f7af15..2c0bcc6012 100644 --- a/indra/llui/llfunctorregistry.h +++ b/indra/llui/llfunctorregistry.h @@ -40,7 +40,7 @@ #include #include "llsd.h" -#include "llmemory.h" +#include "llsingleton.h" /** * @class LLFunctorRegistry diff --git a/indra/llui/llhandle.h b/indra/llui/llhandle.h new file mode 100644 index 0000000000..10a7fd4544 --- /dev/null +++ b/indra/llui/llhandle.h @@ -0,0 +1,171 @@ +/** +* @file llhandle.h +* @brief "Handle" to an object (usually a floater) whose lifetime you don't +* control. +* +* $LicenseInfo:firstyear=2001&license=viewergpl$ +* +* Copyright (c) 2001-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#ifndef LLHANDLE_H +#define LLHANDLE_H + +#include "llpointer.h" + +template +class LLTombStone : public LLRefCount +{ +public: + LLTombStone(T* target = NULL) : mTarget(target) {} + + void setTarget(T* target) { mTarget = target; } + T* getTarget() const { return mTarget; } +private: + T* mTarget; +}; + +// LLHandles are used to refer to objects whose lifetime you do not control or influence. +// Calling get() on a handle will return a pointer to the referenced object or NULL, +// if the object no longer exists. Note that during the lifetime of the returned pointer, +// you are assuming that the object will not be deleted by any action you perform, +// or any other thread, as normal when using pointers, so avoid using that pointer outside of +// the local code block. +// +// https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 + +template +class LLHandle +{ +public: + LLHandle() : mTombStone(sDefaultTombStone) {} + const LLHandle& operator =(const LLHandle& other) + { + mTombStone = other.mTombStone; + return *this; + } + + bool isDead() const + { + return mTombStone->getTarget() == NULL; + } + + void markDead() + { + mTombStone = sDefaultTombStone; + } + + T* get() const + { + return mTombStone->getTarget(); + } + + friend bool operator== (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone == rhs.mTombStone; + } + friend bool operator!= (const LLHandle& lhs, const LLHandle& rhs) + { + return !(lhs == rhs); + } + friend bool operator< (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone < rhs.mTombStone; + } + friend bool operator> (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone > rhs.mTombStone; + } +protected: + +protected: + LLPointer > mTombStone; + +private: + static LLPointer > sDefaultTombStone; +}; + +// initialize static "empty" tombstone pointer +template LLPointer > LLHandle::sDefaultTombStone = new LLTombStone(); + + +template +class LLRootHandle : public LLHandle +{ +public: + LLRootHandle(T* object) { bind(object); } + LLRootHandle() {}; + ~LLRootHandle() { unbind(); } + + // this is redundant, since a LLRootHandle *is* an LLHandle + LLHandle getHandle() { return LLHandle(*this); } + + void bind(T* object) + { + // unbind existing tombstone + if (LLHandle::mTombStone.notNull()) + { + if (LLHandle::mTombStone->getTarget() == object) return; + LLHandle::mTombStone->setTarget(NULL); + } + // tombstone reference counted, so no paired delete + LLHandle::mTombStone = new LLTombStone(object); + } + + void unbind() + { + LLHandle::mTombStone->setTarget(NULL); + } + + //don't allow copying of root handles, since there should only be one +private: + LLRootHandle(const LLRootHandle& other) {}; +}; + +// Use this as a mixin for simple classes that need handles and when you don't +// want handles at multiple points of the inheritance hierarchy +template +class LLHandleProvider +{ +protected: + typedef LLHandle handle_type_t; + LLHandleProvider() + { + // provided here to enforce T deriving from LLHandleProvider + } + + LLHandle getHandle() + { + // perform lazy binding to avoid small tombstone allocations for handle + // providers whose handles are never referenced + mHandle.bind(static_cast(this)); + return mHandle; + } + +private: + LLRootHandle mHandle; +}; + +#endif diff --git a/indra/llui/lliconctrl.cpp b/indra/llui/lliconctrl.cpp index cb3b2a3a62..673c742e7a 100644 --- a/indra/llui/lliconctrl.cpp +++ b/indra/llui/lliconctrl.cpp @@ -40,135 +40,79 @@ #include "llcontrol.h" #include "llui.h" #include "lluictrlfactory.h" +#include "lluiimage.h" -const F32 RESOLUTION_BUMP = 1.f; +static LLDefaultChildRegistry::Register r("icon"); -static LLRegisterWidget r("icon"); - -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ) +LLIconCtrl::Params::Params() +: image("image_name"), + color("color"), + scale_image("scale_image") { - setImage( image_id ); - setTabStop(FALSE); + tab_stop = false; + mouse_opaque = false; } -LLIconCtrl::LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name) -: LLUICtrl(name, - rect, - FALSE, // mouse opaque - NULL, NULL, - FOLLOWS_LEFT | FOLLOWS_TOP), - mColor( LLColor4::white ), - mImageName(image_name) +LLIconCtrl::LLIconCtrl(const LLIconCtrl::Params& p) +: LLUICtrl(p), + mColor(p.color()), + mImagep(p.image) { - setImage( image_name ); - setTabStop(FALSE); + if (mImagep.notNull()) + { + LLUICtrl::setValue(mImagep->getName()); + } } - LLIconCtrl::~LLIconCtrl() { mImagep = NULL; } -void LLIconCtrl::setImage(const std::string& image_name) -{ - //RN: support UUIDs masquerading as strings - if (LLUUID::validate(image_name)) - { - mImageID = LLUUID(image_name); - - setImage(mImageID); - } - else - { - mImageName = image_name; - mImagep = LLUI::sImageProvider->getUIImage(image_name); - mImageID.setNull(); - } -} - -void LLIconCtrl::setImage(const LLUUID& image_id) -{ - mImageName.clear(); - mImagep = LLUI::sImageProvider->getUIImageByID(image_id); - mImageID = image_id; -} - - void LLIconCtrl::draw() { if( mImagep.notNull() ) { - mImagep->draw(getLocalRect(), mColor ); + mImagep->draw(getLocalRect(), mColor.get() ); } LLUICtrl::draw(); } +// virtual +void LLIconCtrl::setAlpha(F32 alpha) +{ + LLColor4 temp = mColor.get(); + temp.setAlpha(alpha); + mColor.set(temp); +} + // virtual +// value might be a string or a UUID void LLIconCtrl::setValue(const LLSD& value ) { - if (value.isUUID()) + LLSD tvalue(value); + if (value.isString() && LLUUID::validate(value.asString())) { - setImage(value.asUUID()); + //RN: support UUIDs masquerading as strings + tvalue = LLSD(LLUUID(value.asString())); + } + LLUICtrl::setValue(tvalue); + if (tvalue.isUUID()) + { + mImagep = LLUI::getUIImageByID(tvalue.asUUID()); } else { - setImage(value.asString()); + mImagep = LLUI::getUIImage(tvalue.asString()); } } -// virtual -LLSD LLIconCtrl::getValue() const +std::string LLIconCtrl::getImageName() const { - LLSD ret = getImage(); - return ret; -} - -// virtual -LLXMLNodePtr LLIconCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - if (mImageName != "") - { - node->createChild("image_name", TRUE)->setStringValue(mImageName); - } - - node->createChild("color", TRUE)->setFloatValue(4, mColor.mV); - - return node; -} - -LLView* LLIconCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("icon"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - std::string image_name; - if (node->hasAttribute("image_name")) - { - node->getAttributeString("image_name", image_name); - } - - LLColor4 color(LLColor4::white); - LLUICtrlFactory::getAttributeColor(node,"color", color); - - LLIconCtrl* icon = new LLIconCtrl(name, rect, image_name); - - icon->setColor(color); - - icon->initFromXML(node, parent); - - return icon; + if (getValue().isString()) + return getValue().asString(); + else + return std::string(); } diff --git a/indra/llui/lliconctrl.h b/indra/llui/lliconctrl.h index 50778cf226..aceb70b9d5 100644 --- a/indra/llui/lliconctrl.h +++ b/indra/llui/lliconctrl.h @@ -37,7 +37,6 @@ #include "v4color.h" #include "lluictrl.h" #include "stdenums.h" -#include "llimagegl.h" class LLTextBox; class LLUICtrlFactory; @@ -45,35 +44,39 @@ class LLUICtrlFactory; // // Classes // + +// class LLIconCtrl : public LLUICtrl { public: - LLIconCtrl(const std::string& name, const LLRect &rect, const LLUUID &image_id); - LLIconCtrl(const std::string& name, const LLRect &rect, const std::string &image_name); + struct Params : public LLInitParam::Block + { + Optional image; + Optional color; + Ignored scale_image; + Params(); + }; +protected: + LLIconCtrl(const Params&); + friend class LLUICtrlFactory; +public: virtual ~LLIconCtrl(); // llview overrides virtual void draw(); - void setImage(const std::string& image_name); - void setImage(const LLUUID& image_name); - const LLUUID &getImage() const { return mImageID; } - std::string getImageName() const { return mImageName; } - - // Takes a UUID, wraps get/setImage + // lluictrl overrides virtual void setValue(const LLSD& value ); - virtual LLSD getValue() const; + + std::string getImageName() const; + + /*virtual*/ void setAlpha(F32 alpha); void setColor(const LLColor4& color) { mColor = color; } - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - private: - LLColor4 mColor; - std::string mImageName; - LLUUID mImageID; + LLUIColor mColor; LLPointer mImagep; }; diff --git a/indra/llui/llkeywords.cpp b/indra/llui/llkeywords.cpp index 51ef3dbacf..ede32084d0 100644 --- a/indra/llui/llkeywords.cpp +++ b/indra/llui/llkeywords.cpp @@ -223,19 +223,21 @@ LLColor3 LLKeywords::readColor( const std::string& s ) { F32 r, g, b; r = g = b = 0.0f; - S32 read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b ); - if( read != 3 ) /* Flawfinder: ignore */ + S32 values_read = sscanf(s.c_str(), "%f, %f, %f]", &r, &g, &b ); + if( values_read != 3 ) { llinfos << " poorly formed color in keyword file" << llendl; } return LLColor3( r, g, b ); } +LLFastTimer::DeclareTimer FTM_SYNTAX_COLORING("Syntax Coloring"); + // Walk through a string, applying the rules specified by the keyword token list and // create a list of color segments. -void LLKeywords::findSegments(std::vector* seg_list, const LLWString& wtext, const LLColor4 &defaultColor) +void LLKeywords::findSegments(std::vector* seg_list, const LLWString& wtext, const LLColor4 &defaultColor, LLTextEditor& editor) { - std::for_each(seg_list->begin(), seg_list->end(), DeletePointer()); + LLFastTimer ft(FTM_SYNTAX_COLORING); seg_list->clear(); if( wtext.empty() ) @@ -243,9 +245,9 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLWS return; } - S32 text_len = wtext.size(); + S32 text_len = wtext.size() + 1; - seg_list->push_back( new LLTextSegment( LLColor3(defaultColor), 0, text_len ) ); + seg_list->push_back( new LLNormalTextSegment( defaultColor, 0, text_len, editor ) ); const llwchar* base = wtext.c_str(); const llwchar* cur = base; @@ -296,9 +298,9 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLWS } S32 seg_end = cur - base; - LLTextSegment* text_segment = new LLTextSegment( cur_token->getColor(), seg_start, seg_end ); + LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor ); text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, defaultColor); + insertSegment( seg_list, text_segment, text_len, defaultColor, editor); line_done = TRUE; // to break out of second loop. break; } @@ -405,9 +407,9 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLWS } - LLTextSegment* text_segment = new LLTextSegment( cur_delimiter->getColor(), seg_start, seg_end ); + LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_delimiter->getColor(), seg_start, seg_end, editor ); text_segment->setToken( cur_delimiter ); - insertSegment( seg_list, text_segment, text_len, defaultColor); + insertSegment( seg_list, text_segment, text_len, defaultColor, editor); // Note: we don't increment cur, since the end of one delimited seg may be immediately // followed by the start of another one. @@ -438,9 +440,9 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLWS // llinfos << "Seg: [" << word.c_str() << "]" << llendl; - LLTextSegment* text_segment = new LLTextSegment( cur_token->getColor(), seg_start, seg_end ); + LLTextSegmentPtr text_segment = new LLNormalTextSegment( cur_token->getColor(), seg_start, seg_end, editor ); text_segment->setToken( cur_token ); - insertSegment( seg_list, text_segment, text_len, defaultColor); + insertSegment( seg_list, text_segment, text_len, defaultColor, editor); } cur += seg_len; continue; @@ -455,25 +457,24 @@ void LLKeywords::findSegments(std::vector* seg_list, const LLWS } } -void LLKeywords::insertSegment(std::vector* seg_list, LLTextSegment* new_segment, S32 text_len, const LLColor4 &defaultColor ) +void LLKeywords::insertSegment(std::vector* seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, LLTextEditor& editor ) { - LLTextSegment* last = seg_list->back(); + LLTextSegmentPtr last = seg_list->back(); S32 new_seg_end = new_segment->getEnd(); if( new_segment->getStart() == last->getStart() ) { - *last = *new_segment; - delete new_segment; + seg_list->pop_back(); } else { last->setEnd( new_segment->getStart() ); - seg_list->push_back( new_segment ); } + seg_list->push_back( new_segment ); if( new_seg_end < text_len ) { - seg_list->push_back( new LLTextSegment( defaultColor, new_seg_end, text_len ) ); + seg_list->push_back( new LLNormalTextSegment( defaultColor, new_seg_end, text_len, editor ) ); } } diff --git a/indra/llui/llkeywords.h b/indra/llui/llkeywords.h index 38f5e993c2..53377869ca 100644 --- a/indra/llui/llkeywords.h +++ b/indra/llui/llkeywords.h @@ -39,9 +39,10 @@ #include #include #include +#include "llpointer.h" class LLTextSegment; - +typedef LLPointer LLTextSegmentPtr; class LLKeywordToken { @@ -84,7 +85,7 @@ public: BOOL loadFromFile(const std::string& filename); BOOL isLoaded() const { return mLoaded; } - void findSegments(std::vector *seg_list, const LLWString& text, const LLColor4 &defaultColor ); + void findSegments(std::vector *seg_list, const LLWString& text, const LLColor4 &defaultColor, class LLTextEditor& editor ); // Add the token as described void addToken(LLKeywordToken::TOKEN_TYPE type, @@ -103,7 +104,7 @@ public: private: LLColor3 readColor(const std::string& s); - void insertSegment(std::vector *seg_list, LLTextSegment* new_segment, S32 text_len, const LLColor4 &defaultColor); + void insertSegment(std::vector *seg_list, LLTextSegmentPtr new_segment, S32 text_len, const LLColor4 &defaultColor, class LLTextEditor& editor); BOOL mLoaded; word_token_map_t mWordTokenMap; diff --git a/indra/llui/lllayoutstack.cpp b/indra/llui/lllayoutstack.cpp new file mode 100644 index 0000000000..f98edec1f3 --- /dev/null +++ b/indra/llui/lllayoutstack.cpp @@ -0,0 +1,742 @@ +/** + * @file lllayoutstack.cpp + * @brief LLLayout class - dynamic stacking of UI elements + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Opaque view with a background and a border. Can contain LLUICtrls. + +#include "linden_common.h" + +#include "lllayoutstack.h" +#include "llresizebar.h" +#include "llcriticaldamp.h" + +static LLDefaultChildRegistry::Register register_layout_stack("layout_stack", &LLLayoutStack::fromXML); + + +// +// LLLayoutStack +// +struct LLLayoutStack::LayoutPanel +{ + LayoutPanel(LLPanel* panelp, ELayoutOrientation orientation, S32 min_width, S32 min_height, BOOL auto_resize, BOOL user_resize) : mPanel(panelp), + mMinWidth(min_width), + mMinHeight(min_height), + mAutoResize(auto_resize), + mUserResize(user_resize), + mOrientation(orientation), + mCollapsed(FALSE), + mCollapseAmt(0.f), + mVisibleAmt(1.f), // default to fully visible + mResizeBar(NULL) + { + LLResizeBar::Side side = (orientation == HORIZONTAL) ? LLResizeBar::RIGHT : LLResizeBar::BOTTOM; + LLRect resize_bar_rect = panelp->getRect(); + + S32 min_dim; + if (orientation == HORIZONTAL) + { + min_dim = mMinHeight; + } + else + { + min_dim = mMinWidth; + } + LLResizeBar::Params p; + p.name("resize"); + p.resizing_view(mPanel); + p.min_size(min_dim); + p.side(side); + p.snapping_enabled(false); + mResizeBar = LLUICtrlFactory::create(p); + // panels initialized as hidden should not start out partially visible + if (!mPanel->getVisible()) + { + mVisibleAmt = 0.f; + } + } + + ~LayoutPanel() + { + // probably not necessary, but... + delete mResizeBar; + mResizeBar = NULL; + } + + F32 getCollapseFactor() + { + if (mOrientation == HORIZONTAL) + { + F32 collapse_amt = + clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth())); + return mVisibleAmt * collapse_amt; + } + else + { + F32 collapse_amt = + clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight()))); + return mVisibleAmt * collapse_amt; + } + } + + LLPanel* mPanel; + S32 mMinWidth; + S32 mMinHeight; + BOOL mAutoResize; + BOOL mUserResize; + BOOL mCollapsed; + LLResizeBar* mResizeBar; + ELayoutOrientation mOrientation; + F32 mVisibleAmt; + F32 mCollapseAmt; +}; + +LLLayoutStack::Params::Params() +: orientation("orientation", std::string("vertical")), + animate("animate", true), + clip("clip", true), + border_size("border_size", LLCachedControl(*LLUI::sSettingGroups["config"], "UIResizeBarHeight", 0)) +{ + name="stack"; +} + +LLLayoutStack::LLLayoutStack(const LLLayoutStack::Params& p) +: LLView(p), + mMinWidth(0), + mMinHeight(0), + mPanelSpacing(p.border_size), + mOrientation((p.orientation() == "vertical") ? VERTICAL : HORIZONTAL), + mAnimate(p.animate), + mClip(p.clip) +{} + +LLLayoutStack::~LLLayoutStack() +{ + e_panel_list_t panels = mPanels; // copy list of panel pointers + mPanels.clear(); // clear so that removeChild() calls don't cause trouble + std::for_each(panels.begin(), panels.end(), DeletePointer()); +} + +void LLLayoutStack::draw() +{ + updateLayout(); + + e_panel_list_t::iterator panel_it; + for (panel_it = mPanels.begin(); panel_it != mPanels.end(); ++panel_it) + { + // clip to layout rectangle, not bounding rectangle + LLRect clip_rect = (*panel_it)->mPanel->getRect(); + // scale clipping rectangle by visible amount + if (mOrientation == HORIZONTAL) + { + clip_rect.mRight = clip_rect.mLeft + llround((F32)clip_rect.getWidth() * (*panel_it)->getCollapseFactor()); + } + else + { + clip_rect.mBottom = clip_rect.mTop - llround((F32)clip_rect.getHeight() * (*panel_it)->getCollapseFactor()); + } + + LLPanel* panelp = (*panel_it)->mPanel; + + LLLocalClipRect clip(clip_rect, mClip); + // only force drawing invisible children if visible amount is non-zero + drawChild(panelp, 0, 0, !clip_rect.isEmpty()); + } +} + +void LLLayoutStack::removeChild(LLView* view) +{ + LayoutPanel* embedded_panelp = findEmbeddedPanel(dynamic_cast(view)); + + if (embedded_panelp) + { + mPanels.erase(std::find(mPanels.begin(), mPanels.end(), embedded_panelp)); + delete embedded_panelp; + } + + // need to update resizebars + + calcMinExtents(); + + LLView::removeChild(view); +} + +BOOL LLLayoutStack::postBuild() +{ + updateLayout(); + return TRUE; +} + +static void get_attribute_s32_and_write(LLXMLNodePtr node, + const char* name, + S32 *value, + S32 default_value, + LLXMLNodePtr output_child) +{ + BOOL has_attr = node->getAttributeS32(name, *value); + if (has_attr && *value != default_value && output_child) + { + // create an attribute child node + LLXMLNodePtr child_attr = output_child->createChild(name, TRUE); + child_attr->setIntValue(*value); + } +} + +static void get_attribute_bool_and_write(LLXMLNodePtr node, + const char* name, + BOOL *value, + BOOL default_value, + LLXMLNodePtr output_child) +{ + BOOL has_attr = node->getAttributeBOOL(name, *value); + if (has_attr && *value != default_value && output_child) + { + LLXMLNodePtr child_attr = output_child->createChild(name, TRUE); + child_attr->setBoolValue(*value); + } +} +//static +LLView* LLLayoutStack::fromXML(LLXMLNodePtr node, LLView *parent, LLXMLNodePtr output_node) +{ + LLLayoutStack::Params p(LLUICtrlFactory::getDefaultParams()); + LLXUIParser::instance().readXUI(node, p); + + // Export must happen before setupParams() mungles rectangles and before + // this item gets added to parent (otherwise screws up last_child_rect + // logic). JC + if (output_node) + { + Params output_params(p); + setupParamsForExport(output_params, parent); + LLLayoutStack::Params default_params(LLUICtrlFactory::getDefaultParams()); + output_node->setName(node->getName()->mString); + LLXUIParser::instance().writeXUI( + output_node, output_params, &default_params); + } + + setupParams(p, parent); + LLLayoutStack* layout_stackp = LLUICtrlFactory::create(p); + + if (parent && layout_stackp) + { + S32 tab_group = p.tab_group.isProvided() ? p.tab_group() : parent->getLastTabGroup(); + + parent->addChild(layout_stackp, tab_group); + } + + for (LLXMLNodePtr child_node = node->getFirstChild(); child_node.notNull(); child_node = child_node->getNextSibling()) + { + const S32 DEFAULT_MIN_WIDTH = 0; + const S32 DEFAULT_MIN_HEIGHT = 0; + const BOOL DEFAULT_AUTO_RESIZE = TRUE; + + S32 min_width = DEFAULT_MIN_WIDTH; + S32 min_height = DEFAULT_MIN_HEIGHT; + BOOL auto_resize = DEFAULT_AUTO_RESIZE; + + LLXMLNodePtr output_child; + if (output_node) + { + output_child = output_node->createChild("", FALSE); + } + + // Layout stack allows child nodes to acquire additional attributes, + // such as "min_width" in: " + // which equates to the following nesting: + // button + // param + // nested_param1 + // nested_param2 + // nested_param3 + mCurReadDepth++; + for(LLXMLNodePtr childp = nodep->getFirstChild(); childp.notNull();) + { + std::string child_name(childp->getName()->mString); + S32 num_tokens_pushed = 0; + + // for non "dotted" child nodes check to see if child node maps to another widget type + // and if not, treat as a child element of the current node + // e.g. will interpret as "button.rect" + // since there is no widget named "rect" + if (child_name.find(".") == std::string::npos) + { + mNameStack.push_back(std::make_pair(child_name, newParseGeneration())); + num_tokens_pushed++; + } + else + { + // parse out "dotted" name into individual tokens + tokenizer name_tokens(child_name, sep); + + tokenizer::iterator name_token_it = name_tokens.begin(); + if(name_token_it == name_tokens.end()) + { + childp = childp->getNextSibling(); + continue; + } + + // check for proper nesting + if(!scope.empty() && *name_token_it != scope) + { + childp = childp->getNextSibling(); + continue; + } + + // now ignore first token + ++name_token_it; + + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_token_it; token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; + } + } + + // recurse and visit children XML nodes + if(readXUIImpl(childp, mNameStack.empty() ? scope : mNameStack.back().first, block)) + { + // child node successfully parsed, remove from DOM + + values_parsed = true; + LLXMLNodePtr node_to_remove = childp; + childp = childp->getNextSibling(); + + nodep->deleteChild(node_to_remove); + } + else + { + childp = childp->getNextSibling(); + } + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + mCurReadDepth--; + return values_parsed; +} + +bool LLXUIParser::readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block) +{ + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + + bool any_parsed = false; + + for(LLXMLAttribList::const_iterator attribute_it = nodep->mAttributes.begin(); + attribute_it != nodep->mAttributes.end(); + ++attribute_it) + { + S32 num_tokens_pushed = 0; + std::string attribute_name(attribute_it->first->mString); + mCurReadNode = attribute_it->second; + + tokenizer name_tokens(attribute_name, sep); + // copy remaining tokens on to our running token list + for(tokenizer::iterator token_to_push = name_tokens.begin(); token_to_push != name_tokens.end(); ++token_to_push) + { + mNameStack.push_back(std::make_pair(*token_to_push, newParseGeneration())); + num_tokens_pushed++; + } + + // child nodes are not necessarily valid attributes, so don't complain once we've recursed + bool silent = mCurReadDepth > 0; + any_parsed |= block.submitValue(mNameStack, *this, silent); + + while(num_tokens_pushed-- > 0) + { + mNameStack.pop_back(); + } + } + + return any_parsed; +} + +void LLXUIParser::writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock &block, const LLInitParam::BaseBlock* diff_block) +{ + mWriteRootNode = node; + block.serializeBlock(*this, Parser::name_stack_t(), diff_block); + mOutNodes.clear(); +} + +// go from a stack of names to a specific XML node +LLXMLNodePtr LLXUIParser::getNode(const name_stack_t& stack) +{ + name_stack_t name_stack; + for (name_stack_t::const_iterator it = stack.begin(); + it != stack.end(); + ++it) + { + if (!it->first.empty()) + { + name_stack.push_back(*it); + } + } + + LLXMLNodePtr out_node = mWriteRootNode; + + name_stack_t::const_iterator next_it = name_stack.begin(); + for (name_stack_t::const_iterator it = name_stack.begin(); + it != name_stack.end(); + it = next_it) + { + ++next_it; + if (it->first.empty()) + { + continue; + } + + out_nodes_t::iterator found_it = mOutNodes.lower_bound(it->second); + + // node with this name not yet written + if (found_it == mOutNodes.end() || mOutNodes.key_comp()(found_it->first, it->second)) + { + // make an attribute if we are the last element on the name stack + bool is_attribute = next_it == name_stack.end(); + LLXMLNodePtr new_node = new LLXMLNode(it->first.c_str(), is_attribute); + out_node->addChild(new_node); + mOutNodes.insert(found_it, std::make_pair(it->second, new_node)); + out_node = new_node; + } + else + { + out_node = found_it->second; + } + } + + return (out_node == mWriteRootNode ? LLXMLNodePtr(NULL) : out_node); +} + + +bool LLXUIParser::readBoolValue(void* val_ptr) +{ + S32 value; + bool success = mCurReadNode->getBoolValue(1, &value); + *((bool*)val_ptr) = (value != FALSE); + return success; +} + +bool LLXUIParser::writeBoolValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setBoolValue(*((bool*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readStringValue(void* val_ptr) +{ + *((std::string*)val_ptr) = mCurReadNode->getSanitizedValue(); + return true; +} + +bool LLXUIParser::writeStringValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + const std::string* string_val = reinterpret_cast(val_ptr); + if (string_val->find('\n') != std::string::npos + || string_val->size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + // create a child that is not an attribute, but with same name + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + node->setStringValue(*string_val); + return true; + } + return false; +} + +bool LLXUIParser::readU8Value(void* val_ptr) +{ + return mCurReadNode->getByteValue(1, (U8*)val_ptr); +} + +bool LLXUIParser::writeU8Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS8Value(void* val_ptr) +{ + S32 value; + if(mCurReadNode->getIntValue(1, &value)) + { + *((S8*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS8Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S8*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU16Value(void* val_ptr) +{ + U32 value; + if(mCurReadNode->getUnsignedValue(1, &value)) + { + *((U16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeU16Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS16Value(void* val_ptr) +{ + S32 value; + if(mCurReadNode->getIntValue(1, &value)) + { + *((S16*)val_ptr) = value; + return true; + } + return false; +} + +bool LLXUIParser::writeS16Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S16*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readU32Value(void* val_ptr) +{ + return mCurReadNode->getUnsignedValue(1, (U32*)val_ptr); +} + +bool LLXUIParser::writeU32Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setUnsignedValue(*((U32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readS32Value(void* val_ptr) +{ + return mCurReadNode->getIntValue(1, (S32*)val_ptr); +} + +bool LLXUIParser::writeS32Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setIntValue(*((S32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF32Value(void* val_ptr) +{ + return mCurReadNode->getFloatValue(1, (F32*)val_ptr); +} + +bool LLXUIParser::writeF32Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setFloatValue(*((F32*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readF64Value(void* val_ptr) +{ + return mCurReadNode->getDoubleValue(1, (F64*)val_ptr); +} + +bool LLXUIParser::writeF64Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setDoubleValue(*((F64*)val_ptr)); + return true; + } + return false; +} + +bool LLXUIParser::readColor4Value(void* val_ptr) +{ + LLColor4* colorp = (LLColor4*)val_ptr; + if(mCurReadNode->getFloatValue(4, colorp->mV) >= 3) + { + return true; + } + + return false; +} + +bool LLXUIParser::writeColor4Value(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + LLColor4 color = *((LLColor4*)val_ptr); + node->setFloatValue(4, color.mV); + return true; + } + return false; +} + +bool LLXUIParser::readUIColorValue(void* val_ptr) +{ + LLUIColor* param = (LLUIColor*)val_ptr; + LLColor4 color; + bool success = mCurReadNode->getFloatValue(4, color.mV) >= 3; + if (success) + { + param->set(color); + return true; + } + return false; +} + +bool LLXUIParser::writeUIColorValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + LLUIColor color = *((LLUIColor*)val_ptr); + //RN: don't write out the color that is represented by a function + // rely on param block exporting to get the reference to the color settings + if (color.isReference()) return false; + node->setFloatValue(4, color.get().mV); + return true; + } + return false; +} + +bool LLXUIParser::readUUIDValue(void* val_ptr) +{ + LLUUID temp_id; + // LLUUID::set is destructive, so use temporary value + if (temp_id.set(mCurReadNode->getSanitizedValue())) + { + *(LLUUID*)(val_ptr) = temp_id; + return true; + } + return false; +} + +bool LLXUIParser::writeUUIDValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + node->setStringValue(((LLUUID*)val_ptr)->asString()); + return true; + } + return false; +} + +bool LLXUIParser::readSDValue(void* val_ptr) +{ + *((LLSD*)val_ptr) = LLSD(mCurReadNode->getSanitizedValue()); + return true; +} + +bool LLXUIParser::writeSDValue(const void* val_ptr, const name_stack_t& stack) +{ + LLXMLNodePtr node = getNode(stack); + if (node.notNull()) + { + std::string string_val = ((LLSD*)val_ptr)->asString(); + if (string_val.find('\n') != std::string::npos || string_val.size() > MAX_STRING_ATTRIBUTE_SIZE) + { + // don't write strings with newlines into attributes + std::string attribute_name = node->getName()->mString; + LLXMLNodePtr parent_node = node->mParent; + parent_node->deleteChild(node); + // write results in text contents of node + if (attribute_name == "value") + { + // "value" is implicit, just write to parent + node = parent_node; + } + else + { + node = parent_node->createChild(attribute_name.c_str(), false); + } + } + + node->setStringValue(string_val); + return true; + } + return false; +} + +/*virtual*/ std::string LLXUIParser::getCurrentElementName() +{ + std::string full_name; + for (name_stack_t::iterator it = mNameStack.begin(); + it != mNameStack.end(); + ++it) + { + full_name += it->first + "."; // build up dotted names: "button.param.nestedparam." + } + + return full_name; +} + +void LLXUIParser::parserWarning(const std::string& message) +{ +#if 0 //#ifdef LL_WINDOWS + // use Visual Studo friendly formatting of output message for easy access to originating xml + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserWarning(message); +#endif +} + +void LLXUIParser::parserError(const std::string& message) +{ +#if 0 //#ifdef LL_WINDOWS + llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", LLUICtrlFactory::getInstance()->getCurFileName().c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str()); + utf16str += '\n'; + OutputDebugString(utf16str.c_str()); +#else + Parser::parserError(message); +#endif +} diff --git a/indra/llxuixml/llxuiparser.h b/indra/llxuixml/llxuiparser.h new file mode 100644 index 0000000000..6f000f2422 --- /dev/null +++ b/indra/llxuixml/llxuiparser.h @@ -0,0 +1,174 @@ +/** + * @file llxuiparser.h + * @brief Utility functions for handling XUI structures in XML + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLXUIPARSER_H +#define LLXUIPARSER_H + +#include "llinitparam.h" +#include "llxmlnode.h" +#include "llfasttimer.h" +#include "llregistry.h" + +#include +#include +#include +#include + + + +class LLView; + + + +// lookup widget type by name +class LLWidgetTypeRegistry +: public LLRegistrySingleton +{}; + + +// global static instance for registering all widget types +typedef boost::function LLWidgetCreatorFunc; + +typedef LLRegistry widget_registry_t; + +class LLChildRegistryRegistry +: public LLRegistrySingleton +{}; + + + +class LLXSDWriter : public LLInitParam::Parser +{ + LOG_CLASS(LLXSDWriter); +public: + void writeXSD(const std::string& name, LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const std::string& xml_namespace); + + /*virtual*/ std::string getCurrentElementName() { return LLStringUtil::null; } + + LLXSDWriter(); + +protected: + void writeAttribute(const std::string& type, const Parser::name_stack_t&, S32 min_count, S32 max_count, const std::vector* possible_values); + void addAttributeToSchema(LLXMLNodePtr nodep, const std::string& attribute_name, const std::string& type, bool mandatory, const std::vector* possible_values); + LLXMLNodePtr mAttributeNode; + LLXMLNodePtr mElementNode; + LLXMLNodePtr mSchemaNode; + + typedef std::set string_set_t; + typedef std::map attributes_map_t; + attributes_map_t mAttributesWritten; +}; + + + +// NOTE: DOES NOT WORK YET +// should support child widgets for XUI +class LLXUIXSDWriter : public LLXSDWriter +{ +public: + void writeXSD(const std::string& name, const std::string& path, const LLInitParam::BaseBlock& block); +}; + + + +class LLXUIParser : public LLInitParam::Parser, public LLSingleton +{ +LOG_CLASS(LLXUIParser); + +protected: + LLXUIParser(); + friend class LLSingleton; +public: + typedef LLInitParam::Parser::name_stack_t name_stack_t; + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ void parserWarning(const std::string& message); + /*virtual*/ void parserError(const std::string& message); + + void readXUI(LLXMLNodePtr node, LLInitParam::BaseBlock& block, bool silent=false); + void writeXUI(LLXMLNodePtr node, const LLInitParam::BaseBlock& block, const LLInitParam::BaseBlock* diff_block = NULL); + +private: + typedef std::list > token_list_t; + + bool readXUIImpl(LLXMLNodePtr node, const std::string& scope, LLInitParam::BaseBlock& block); + bool readAttributes(LLXMLNodePtr nodep, LLInitParam::BaseBlock& block); + + //reader helper functions + bool readBoolValue(void* val_ptr); + bool readStringValue(void* val_ptr); + bool readU8Value(void* val_ptr); + bool readS8Value(void* val_ptr); + bool readU16Value(void* val_ptr); + bool readS16Value(void* val_ptr); + bool readU32Value(void* val_ptr); + bool readS32Value(void* val_ptr); + bool readF32Value(void* val_ptr); + bool readF64Value(void* val_ptr); + bool readColor4Value(void* val_ptr); + bool readUIColorValue(void* val_ptr); + bool readUUIDValue(void* val_ptr); + bool readSDValue(void* val_ptr); + + //writer helper functions + bool writeBoolValue(const void* val_ptr, const name_stack_t&); + bool writeStringValue(const void* val_ptr, const name_stack_t&); + bool writeU8Value(const void* val_ptr, const name_stack_t&); + bool writeS8Value(const void* val_ptr, const name_stack_t&); + bool writeU16Value(const void* val_ptr, const name_stack_t&); + bool writeS16Value(const void* val_ptr, const name_stack_t&); + bool writeU32Value(const void* val_ptr, const name_stack_t&); + bool writeS32Value(const void* val_ptr, const name_stack_t&); + bool writeF32Value(const void* val_ptr, const name_stack_t&); + bool writeF64Value(const void* val_ptr, const name_stack_t&); + bool writeColor4Value(const void* val_ptr, const name_stack_t&); + bool writeUIColorValue(const void* val_ptr, const name_stack_t&); + bool writeUUIDValue(const void* val_ptr, const name_stack_t&); + bool writeSDValue(const void* val_ptr, const name_stack_t&); + + LLXMLNodePtr getNode(const name_stack_t& stack); + +private: + Parser::name_stack_t mNameStack; + LLXMLNodePtr mCurReadNode; + // Root of the widget XML sub-tree, for example, "line_editor" + LLXMLNodePtr mWriteRootNode; + + typedef std::map out_nodes_t; + out_nodes_t mOutNodes; + S32 mLastWriteGeneration; + LLXMLNodePtr mLastWrittenChild; + S32 mCurReadDepth; +}; + + +#endif //LLXUIPARSER_H diff --git a/indra/lscript/lscript_compile/lscript_tree.cpp b/indra/lscript/lscript_compile/lscript_tree.cpp index 7fa115bb20..3b8bbbe805 100644 --- a/indra/lscript/lscript_compile/lscript_tree.cpp +++ b/indra/lscript/lscript_compile/lscript_tree.cpp @@ -10679,20 +10679,21 @@ void LLScriptScript::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa { mGlobalScope = new LLScriptScope(gScopeStringTable); // zeroth, add library functions to global scope - S32 i; + U16 function_index = 0; const char *arg; LLScriptScopeEntry *sentry; - for (i = 0; i < gScriptLibrary.mNextNumber; i++) + for (std::vector::const_iterator i = gScriptLibrary.mFunctions.begin(); + i != gScriptLibrary.mFunctions.end(); ++i) { // First, check to make sure this isn't a god only function, or that the viewer's agent is a god. - if (!gScriptLibrary.mFunctions[i]->mGodOnly || mGodLike) + if (!i->mGodOnly || mGodLike) { - if (gScriptLibrary.mFunctions[i]->mReturnType) - sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName, LIT_LIBRARY_FUNCTION, char2type(*gScriptLibrary.mFunctions[i]->mReturnType)); + if (i->mReturnType) + sentry = mGlobalScope->addEntry(i->mName, LIT_LIBRARY_FUNCTION, char2type(*i->mReturnType)); else - sentry = mGlobalScope->addEntry(gScriptLibrary.mFunctions[i]->mName, LIT_LIBRARY_FUNCTION, LST_NULL); - sentry->mLibraryNumber = i; - arg = gScriptLibrary.mFunctions[i]->mArgs; + sentry = mGlobalScope->addEntry(i->mName, LIT_LIBRARY_FUNCTION, LST_NULL); + sentry->mLibraryNumber = function_index; + arg = i->mArgs; if (arg) { while (*arg) @@ -10704,6 +10705,7 @@ void LLScriptScript::recurse(LLFILE *fp, S32 tabs, S32 tabsize, LSCRIPTCompilePa } } } + function_index++; } // first go and collect all the global variables if (mGlobals) diff --git a/indra/lscript/lscript_execute.h b/indra/lscript/lscript_execute.h index 8549482299..96855abea0 100644 --- a/indra/lscript/lscript_execute.h +++ b/indra/lscript/lscript_execute.h @@ -37,6 +37,8 @@ #include "linked_lists.h" #include "lscript_library.h" +class LLTimer; + // Return values for run() methods const U32 NO_DELETE_FLAG = 0x0000; const U32 DELETE_FLAG = 0x0001; diff --git a/indra/lscript/lscript_execute/lscript_readlso.cpp b/indra/lscript/lscript_execute/lscript_readlso.cpp index faf4fba0e0..2948ebca63 100644 --- a/indra/lscript/lscript_execute/lscript_readlso.cpp +++ b/indra/lscript/lscript_execute/lscript_readlso.cpp @@ -1579,7 +1579,7 @@ void print_calllib(LLFILE *fp, U8 *buffer, S32 &offset, S32 tabs) lso_print_tabs(fp, tabs); fprintf(fp, "[0x%X]\tCALLLIB ", offset++); arg = *(buffer + offset++); - fprintf(fp, "%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName); + fprintf(fp, "%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName); } @@ -1589,6 +1589,6 @@ void print_calllib_two_byte(LLFILE *fp, U8 *buffer, S32 &offset, S32 tabs) lso_print_tabs(fp, tabs); fprintf(fp, "[0x%X]\tCALLLIB_TWO_BYTE ", offset++); arg = bytestream2u16(buffer, offset); - fprintf(fp, "%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg]->mName); + fprintf(fp, "%d (%s)\n", (U32)arg, gScriptLibrary.mFunctions[arg].mName); } diff --git a/indra/lscript/lscript_library.h b/indra/lscript/lscript_library.h index fa3b06b7d9..6728d70d0a 100644 --- a/indra/lscript/lscript_library.h +++ b/indra/lscript/lscript_library.h @@ -44,7 +44,7 @@ class LLScriptLibData; class LLScriptLibraryFunction { public: - LLScriptLibraryFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, const char *desc, BOOL god_only = FALSE); + LLScriptLibraryFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, BOOL god_only = FALSE); ~LLScriptLibraryFunction(); F32 mEnergyUse; @@ -53,7 +53,6 @@ public: const char *mName; const char *mReturnType; const char *mArgs; - const char *mDesc; BOOL mGodOnly; }; @@ -65,11 +64,10 @@ public: void init(); - void addFunction(LLScriptLibraryFunction *func); + void addFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, BOOL god_only = FALSE); void assignExec(const char *name, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &)); - S32 mNextNumber; - LLScriptLibraryFunction **mFunctions; + std::vector mFunctions; }; extern LLScriptLibrary gScriptLibrary; diff --git a/indra/lscript/lscript_library/lscript_library.cpp b/indra/lscript/lscript_library/lscript_library.cpp index 0342c97429..0d51c27c92 100644 --- a/indra/lscript/lscript_library/lscript_library.cpp +++ b/indra/lscript/lscript_library/lscript_library.cpp @@ -49,20 +49,12 @@ #include "lscript_library.h" LLScriptLibrary::LLScriptLibrary() -: mNextNumber(0), mFunctions(NULL) { init(); } LLScriptLibrary::~LLScriptLibrary() { - S32 i; - for (i = 0; i < mNextNumber; i++) - { - delete mFunctions[i]; - mFunctions[i] = NULL; - } - delete [] mFunctions; } void dummy_func(LLScriptLibData *retval, LLScriptLibData *args, const LLUUID &id) @@ -75,448 +67,424 @@ void LLScriptLibrary::init() // Otherwise the bytecode numbers for each call will be wrong, and all // existing scripts will crash. - // energy, sleep, dummy_func, name, return type, parameters, help text, gods-only - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSin", "f", "f", "float llSin(float theta)\ntheta in radians")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCos", "f", "f", "float llCos(float theta)\ntheta in radians")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTan", "f", "f", "float llTan(float theta)\ntheta radians")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAtan2", "f", "ff", "float llAtan2(float y, float x)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSqrt", "f", "f", "float llSqrt(float val)\nreturns 0 and triggers a Math Error for imaginary results")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPow", "f", "ff", "float llPow(float base, float exponent)\nreturns 0 and triggers Math Error for imaginary results")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAbs", "i", "i", "integer llAbs(integer val)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llFabs", "f", "f", "float llFabs(float val)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llFrand", "f", "f", "float llFrand(float mag)\nreturns random number in range [0,mag)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llFloor", "i", "f", "integer llFloor(float val)\nreturns largest integer value <= val")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCeil", "i", "f", "integer llCeil(float val)\nreturns smallest integer value >= val")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRound", "i", "f", "integer llRound(float val)\nreturns val rounded to the nearest integer")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llVecMag", "f", "v", "float llVecMag(vector v)\nreturns the magnitude of v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llVecNorm", "v", "v", "vector llVecNorm(vector v)\nreturns the v normalized")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llVecDist", "f", "vv", "float llVecDist(vector v1, vector v2)\nreturns the 3D distance between v1 and v2")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Euler", "v", "q", "vector llRot2Euler(rotation q)\nreturns the Euler representation (roll, pitch, yaw) of q")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llEuler2Rot", "q", "v", "rotation llEuler2Rot(vector v)\nreturns the rotation representation of Euler Angles v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAxes2Rot", "q", "vvv", "rotation llAxes2Rot(vector fwd, vector left, vector up)\nreturns the rotation defined by the coordinate axes")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Fwd", "v", "q", "vector llRot2Fwd(rotation q)\nreturns the forward vector defined by q")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Left", "v", "q", "vector llRot2Left(rotation q)\nreturns the left vector defined by q")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Up", "v", "q", "vector llRot2Up(rotation q)\nreturns the up vector defined by q")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRotBetween", "q", "vv", "rotation llRotBetween(vector v1, vector v2)\nreturns the rotation to rotate v1 to v2")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llWhisper", NULL, "is", "llWhisper(integer channel, string msg)\nwhispers msg on channel")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSay", NULL, "is", "llSay(integer channel, string msg)\nsays msg on channel")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llShout", NULL, "is", "llShout(integer channel, string msg)\nshouts msg on channel")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListen", "i", "isks", "integer llListen(integer channel, string name, key id, string msg)\nsets a callback for msg on channel from name and id (name, id, and/or msg can be empty) and returns an identifier that can be used to deactivate or remove the listen")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListenControl", NULL, "ii", "llListenControl(integer number, integer active)\nmakes a listen event callback active or inactive")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListenRemove", NULL, "i", "llListenRemove(integer number)\nremoves listen event callback number")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSensor", NULL, "skiff", "llSensor(string name, key id, integer type, float range, float arc)\nPerforms a single scan for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSensorRepeat", NULL, "skifff", "llSensorRepeat(string name, key id, integer type, float range, float arc, float rate)\nsets a callback for name and id with type (AGENT, ACTIVE, PASSIVE, and/or SCRIPTED) within range meters and arc radians of forward vector (name, id, and/or keytype can be empty or 0) and repeats every rate seconds")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSensorRemove", NULL, NULL, "llSensorRemove()\nremoves sensor")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedName", "s", "i", "string llDetectedName(integer number)\nreturns the name of detected object number (returns empty string if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedKey", "k", "i", "key llDetectedKey(integer number)\nreturns the key of detected object number (returns empty key if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedOwner", "k", "i", "key llDetectedOwner(integer number)\nreturns the key of detected object's owner (returns empty key if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedType", "i", "i", "integer llDetectedType(integer number)\nreturns the type (AGENT, ACTIVE, PASSIVE, SCRIPTED) of detected object (returns 0 if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedPos", "v", "i", "vector llDetectedPos(integer number)\nreturns the position of detected object number (returns <0,0,0> if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedVel", "v", "i", "vector llDetectedVel(integer number)\nreturns the velocity of detected object number (returns <0,0,0> if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedGrab", "v", "i", "vector llDetectedGrab(integer number)\nreturns the grab offset of the user touching object (returns <0,0,0> if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedRot", "q", "i", "rotation llDetectedRot(integer number)\nreturns the rotation of detected object number (returns <0,0,0,1> if number is not valid sensed object)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedGroup", "i", "i", "integer llDetectedGroup(integer number)\nReturns TRUE if detected object is part of same group as owner")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedLinkNumber", "i", "i", "integer llDetectedLinkNumber(integer number)\nreturns the link position of the triggered event for touches and collisions only")); - addFunction(new LLScriptLibraryFunction(0.f, 0.f, dummy_func, "llDie", NULL, NULL, "llDie()\ndeletes the object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGround", "f", "v", "float llGround(vector v)\nreturns the ground height below the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCloud", "f", "v", "float llCloud(vector v)\nreturns the cloud density at the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llWind", "v", "v", "vector llWind(vector v)\nreturns the wind velocity at the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetStatus", NULL, "ii", "llSetStatus(integer status, integer value)\nsets status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB,\nSTATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z) to value")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetStatus", "i", "i", "integer llGetStatus(integer status)\ngets value of status (STATUS_PHYSICS, STATUS_PHANTOM, STATUS_BLOCK_GRAB,\nSTATUS_ROTATE_X, STATUS_ROTATE_Y, and/or STATUS_ROTATE_Z)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetScale", NULL, "v", "llSetScale(vector scale)\nsets the scale")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetScale", "v", NULL, "vector llGetScale()\ngets the scale")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetColor", NULL, "vi", "llSetColor(vector color, integer face)\nsets the color")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAlpha", "f", "i", "float llGetAlpha(integer face)\ngets the alpha")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetAlpha", NULL, "fi", "llSetAlpha(float alpha, integer face)\nsets the alpha")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetColor", "v", "i", "vector llGetColor(integer face)\ngets the color")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetTexture", NULL, "si", "llSetTexture(string texture, integer face)\nsets the texture of face")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llScaleTexture", NULL, "ffi", "llScaleTexture(float scales, float scalet, integer face)\nsets the texture s, t scales for the chosen face")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llOffsetTexture", NULL, "ffi", "llOffsetTexture(float offsets, float offsett, integer face)\nsets the texture s, t offsets for the chosen face")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llRotateTexture", NULL, "fi", "llRotateTexture(float rotation, integer face)\nsets the texture rotation for the chosen face")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTexture", "s", "i", "string llGetTexture(integer face)\ngets the texture of face (if it's a texture in the object inventory, otherwise the key in a string)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetPos", NULL, "v", "llSetPos(vector pos)\nsets the position (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetPos", "v", NULL, "vector llGetPos()\ngets the position (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLocalPos", "v", NULL, "vector llGetLocalPos()\ngets the position relative to the root (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetRot", NULL, "q", "llSetRot(rotation rot)\nsets the rotation (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRot", "q", NULL, "rotation llGetRot()\ngets the rotation (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLocalRot", "q", NULL, "rotation llGetLocalRot()\ngets the rotation local to the root (if the script isn't physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetForce", NULL, "vi", "llSetForce(vector force, integer local)\nsets force on object, in local coords if local == TRUE (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetForce", "v", NULL, "vector llGetForce()\ngets the force (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTarget", "i", "vf", "integer llTarget(vector position, float range)\nset positions within range of position as a target and return an ID for the target")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTargetRemove", NULL, "i", "llTargetRemove(integer number)\nremoves target number")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRotTarget", "i", "qf", "integer llRotTarget(rotation rot, float error)\nset rotations with error of rot as a rotational target and return an ID for the rotational target")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRotTargetRemove", NULL, "i", "llRotTargetRemove(integer number)\nremoves rotational target number")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llMoveToTarget", NULL, "vf", "llMoveToTarget(vector target, float tau)\ncritically damp to target in tau seconds (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopMoveToTarget", NULL, NULL, "llStopMoveToTarget()\nStops critically damped motion")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llApplyImpulse", NULL, "vi", "llApplyImpulse(vector force, integer local)\napplies impulse to object, in local coords if local == TRUE (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llApplyRotationalImpulse", NULL, "vi", "llApplyRotationalImpulse(vector force, integer local)\napplies rotational impulse to object, in local coords if local == TRUE (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetTorque", NULL, "vi", "llSetTorque(vector torque, integer local)\nsets the torque of object, in local coords if local == TRUE (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTorque", "v", NULL, "vector llGetTorque()\ngets the torque (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetForceAndTorque", NULL, "vvi", "llSetForceAndTorque(vector force, vector torque, integer local)\nsets the force and torque of object, in local coords if local == TRUE (if the script is physical)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetVel", "v", NULL, "vector llGetVel()\ngets the velocity")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAccel", "v", NULL, "vector llGetAccel()\ngets the acceleration")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetOmega", "v", NULL, "vector llGetOmega()\ngets the omega")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTimeOfDay", "f", "", "float llGetTimeOfDay()\ngets the time in seconds since Second Life server midnight (or since server up-time; whichever is smaller)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetWallclock", "f", "", "float llGetWallclock()\ngets the time in seconds since midnight")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTime", "f", NULL, "float llGetTime()\ngets the time in seconds since creation")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llResetTime", NULL, NULL, "llResetTime()\nsets the time to zero")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAndResetTime", "f", NULL, "float llGetAndResetTime()\ngets the time in seconds since creation and sets the time to zero")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSound", NULL, "sfii", "llSound(string sound, float volume, integer queue, integer loop)\nplays sound at volume and whether it should loop or not")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPlaySound", NULL, "sf", "llPlaySound(string sound, float volume)\nplays attached sound once at volume (0.0 - 1.0)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLoopSound", NULL, "sf", "llLoopSound(string sound, float volume)\nplays attached sound looping indefinitely at volume (0.0 - 1.0)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLoopSoundMaster", NULL, "sf", "llLoopSoundMaster(string sound, float volume)\nplays attached sound looping at volume (0.0 - 1.0), declares it a sync master")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLoopSoundSlave", NULL, "sf", "llLoopSoundSlave(string sound, float volume)\nplays attached sound looping at volume (0.0 - 1.0), synced to most audible sync master")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPlaySoundSlave", NULL, "sf", "llPlaySoundSlave(string sound, float volume)\nplays attached sound once at volume (0.0 - 1.0), synced to next loop of most audible sync master")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTriggerSound", NULL, "sf", "llTriggerSound(string sound, float volume)\nplays sound at volume (0.0 - 1.0), centered at but not attached to object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopSound", NULL, "", "llStopSound()\nStops currently attached sound")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llPreloadSound", NULL, "s", "llPreloadSound(string sound)\npreloads a sound on viewers within range")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetSubString", "s", "sii", "string llGetSubString(string src, integer start, integer end)\nreturns the indicated substring")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDeleteSubString", "s", "sii", "string llDeleteSubString(string src, integer start, integer end)\nremoves the indicated substring and returns the result")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llInsertString", "s", "sis", "string llInsertString(string dst, integer position, string src)\ninserts src into dst at position and returns the result")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llToUpper", "s", "s", "string llToUpper(string src)\nconvert src to all upper case and returns the result")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llToLower", "s", "s", "string llToLower(string src)\nconvert src to all lower case and returns the result")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGiveMoney", "i", "ki", "llGiveMoney(key destination, integer amount)\ntransfer amount of money from script owner to destination")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llMakeExplosion", NULL, "iffffsv", "llMakeExplosion(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake a round explosion of particles")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llMakeFountain", NULL, "iffffisvf", "llMakeFountain(integer particles, float scale, float vel, float lifetime, float arc, integer bounce, string texture, vector offset, float bounce_offset)\nMake a fountain of particles")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llMakeSmoke", NULL, "iffffsv", "llMakeSmoke(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake smoke like particles")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llMakeFire", NULL, "iffffsv", "llMakeFire(integer particles, float scale, float vel, float lifetime, float arc, string texture, vector offset)\nMake fire like particles")); - addFunction(new LLScriptLibraryFunction(200.f, 0.1f, dummy_func, "llRezObject", NULL, "svvqi", "llRezObject(string inventory, vector pos, vector vel, rotation rot, integer param)\nInstanciate owners inventory object at pos with velocity vel and rotation rot with start parameter param")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLookAt", NULL, "vff", "llLookAt(vector target, F32 strength, F32 damping)\nCause object name to point it's forward axis towards target")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopLookAt", NULL, NULL, "llStopLookAt()\nStop causing object name to point at a target")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetTimerEvent", NULL, "f", "llSetTimerEvent(float sec)\nCause the timer event to be triggered every sec seconds")); - addFunction(new LLScriptLibraryFunction(0.f, 0.f, dummy_func, "llSleep", NULL, "f", "llSleep(float sec)\nPut script to sleep for sec seconds")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetMass", "f", NULL, "float llGetMass()\nGet the mass of task name that script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCollisionFilter", NULL, "ski", "llCollisionFilter(string name, key id, integer accept)\nif accept == TRUE, only accept collisions with objects name and id (either is optional), otherwise with objects not name or id")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTakeControls", NULL, "iii", "llTakeControls(integer controls, integer accept, integer pass_on)\nTake controls from agent task has permissions for. If (accept == (controls & input)), send input to task. If pass_on send to agent also.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llReleaseControls", NULL, NULL, "llReleaseControls()\nStop taking inputs")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAttachToAvatar", NULL, "i", "llAttachToAvatar(integer attachment)\nAttach to avatar task has permissions for at point attachment")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetachFromAvatar", NULL, NULL, "llDetachFromAvatar()\nDrop off of avatar")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTakeCamera", NULL, "k", "llTakeCamera(key avatar)\nMove avatar's viewpoint to task")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llReleaseCamera", NULL, "k", "llReleaseCamera(key avatar)\nReturn camera to agent")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetOwner", "k", NULL, "key llGetOwner()\nReturns the owner of the task")); - addFunction(new LLScriptLibraryFunction(10.f, 2.f, dummy_func, "llInstantMessage", NULL, "ks", "llInstantMessage(key user, string message)\nIMs message to the user")); - addFunction(new LLScriptLibraryFunction(10.f, 20.f, dummy_func, "llEmail", NULL, "sss", "llEmail(string address, string subject, string message)\nSends email to address with subject and message")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetNextEmail", NULL, "ss", "llGetNextEmail(string address, string subject)\nGet the next waiting email with appropriate address and/or subject (if blank they are ignored)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetKey", "k", NULL, "key llGetKey()\nGet the key for the task the script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetBuoyancy", NULL, "f", "llSetBuoyancy(float buoyancy)\nSet the tasks buoyancy (0 is none, < 1.0 sinks, 1.0 floats, > 1.0 rises)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetHoverHeight", NULL, "fif", "llSetHoverHeight(float height, integer water, float tau)\nCritically damps to a height (either above ground level or above the higher of land and water if water == TRUE)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopHover", NULL, NULL, "llStopHover()\nStop hovering to a height")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llMinEventDelay", NULL, "f", "llMinEventDelay(float delay)\nSet the minimum time between events being handled")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSoundPreload", NULL, "s", "llSoundPreload(string sound)\npreloads a sound on viewers within range")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRotLookAt", NULL, "qff", "llRotLookAt(rotation target, F32 strength, F32 damping)\nCause object name to point it's forward axis towards target")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStringLength", "i", "s", "integer llStringLength(string str)\nReturns the length of string")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStartAnimation", NULL, "s", "llStartAnimation(string anim)\nStart animation anim for agent that owns object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopAnimation", NULL, "s", "llStopAnimation(string anim)\nStop animation anim for agent that owns object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPointAt", NULL, "v", "llPointAt(vector pos)\nMake agent that owns object point at pos")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStopPointAt", NULL, NULL, "llStopPointAt()\nStop agent that owns object pointing")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTargetOmega", NULL, "vff", "llTargetOmega(vector axis, float spinrate, float gain)\nAttempt to spin at spinrate with strength gain")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetStartParameter", "i", NULL, "integer llGetStartParameter()\nGet's the start paramter passed to llRezObject")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGodLikeRezObject", NULL, "kv", "llGodLikeRezObject(key inventory, vector pos)\nrez directly off of a UUID if owner has dog-bit set", TRUE)); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRequestPermissions", NULL, "ki", "llRequestPermissions(key agent, integer perm)\nask agent to allow the script to do perm (NB: Debit, ownership, link, joint, and permission requests can only go to the task's owner)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetPermissionsKey", "k", NULL, "key llGetPermissionsKey()\nReturn agent that permissions are enabled for. NULL_KEY if not enabled")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetPermissions", "i", NULL, "integer llGetPermissions()\nreturn what permissions have been enabled")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLinkNumber", "i", NULL, "integer llGetLinkNumber()\nReturns what number in a link set the script is attached to (0 means no link, 1 the root, 2 for first child, &c)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetLinkColor", NULL, "ivi", "llSetLinkColor(integer linknumber, vector color, integer face)\nIf a task exists in the link chain at linknumber, set face to color")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llCreateLink", NULL, "ki", "llCreateLink(key target, integer parent)\nAttempt to link task script is attached to and target (requires permission PERMISSION_CHANGE_LINKS be set). If parent == TRUE, task script is attached to is the root")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llBreakLink", NULL, "i", "llBreakLink(integer linknum)\nDelinks the task with the given link number (requires permission PERMISSION_CHANGE_LINKS be set)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llBreakAllLinks", NULL, NULL, "llBreakAllLinks()\nDelinks all tasks in the link set (requires permission PERMISSION_CHANGE_LINKS be set)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLinkKey", "k", "i", "key llGetLinkKey(integer linknum)\nGet the key of linknumber in link set")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLinkName", "s", "i", "string llGetLinkName(integer linknum)\nGet the name of linknumber in link set")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryNumber", "i", "i", "integer llGetInventoryNumber(integer type)\nGet the number of items of a given type in the task's inventory.\nValid types: INVENTORY_TEXTURE, INVENTORY_SOUND, INVENTORY_OBJECT, INVENTORY_SCRIPT, INVENTORY_CLOTHING, INVENTORY_BODYPART, INVENTORY_NOTECARD, INVENTORY_LANDMARK, INVENTORY_ALL")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryName", "s", "ii", "string llGetInventoryName(integer type, integer number)\nGet the name of the inventory item number of type")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetScriptState", NULL, "si", "llSetScriptState(string name, integer run)\nControl the state of a script name.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetEnergy", "f", NULL, "float llGetEnergy()\nReturns how much energy is in the object as a percentage of maximum")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGiveInventory", NULL, "ks", "llGiveInventory(key destination, string inventory)\nGive inventory to destination")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRemoveInventory", NULL, "s", "llRemoveInventory(string inventory)\nRemove the named inventory item")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetText", NULL, "svf", "llSetText(string text, vector color, float alpha)\nSet text floating over object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llWater", "f", "v", "float llWater(vector v)\nreturns the water height below the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPassTouches", NULL, "i", "llPassTouches(integer pass)\nif pass == TRUE, touches are passed from children on to parents (default is FALSE)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llRequestAgentData", "k", "ki", "key llRequestAgentData(key id, integer data)\nRequests data about agent id. When data is available the dataserver event will be raised")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llRequestInventoryData", "k", "s", "key llRequestInventoryData(string name)\nRequests data from object's inventory object. When data is available the dataserver event will be raised")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetDamage", NULL, "f", "llSetDamage(float damage)\nSets the amount of damage that will be done to an object that this task hits. Task will be killed.")); - addFunction(new LLScriptLibraryFunction(100.f, 5.f, dummy_func, "llTeleportAgentHome", NULL, "k", "llTeleportAgentHome(key id)\nTeleports agent on owner's land to agent's home location")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llModifyLand", NULL, "ii", "llModifyLand(integer action, integer size)\nModify land with action (LAND_LEVEL, LAND_RAISE, LAND_LOWER, LAND_SMOOTH, LAND_NOISE, LAND_REVERT)\non size (LAND_SMALL_BRUSH, LAND_MEDIUM_BRUSH, LAND_LARGE_BRUSH)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCollisionSound", NULL, "sf", "llCollisionSound(string impact_sound, float impact_volume)\nSuppress default collision sounds, replace default impact sounds with impact_sound (empty string to just suppress)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCollisionSprite", NULL, "s", "llCollisionSprite(string impact_sprite)\nSuppress default collision sprites, replace default impact sprite with impact_sprite (empty string to just suppress)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAnimation", "s", "k", "string llGetAnimation(key id)\nGet the currently playing locomotion animation for avatar id")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llResetScript", NULL, NULL, "llResetScript()\nResets the script")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llMessageLinked", NULL, "iisk", "llMessageLinked(integer linknum, integer num, string str, key id)\nSends num, str, and id to members of the link set (LINK_ROOT sends to root task in a linked set,\nLINK_SET sends to all tasks,\nLINK_ALL_OTHERS to all other tasks,\nLINK_ALL_CHILDREN to all children,\nLINK_THIS to the task the script it is in)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPushObject", NULL, "kvvi", "llPushObject(key id, vector impulse, vector ang_impulse, integer local)\nApplies impulse and ang_impulse to object id")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llPassCollisions", NULL, "i", "llPassCollisions(integer pass)\nif pass == TRUE, collisions are passed from children on to parents (default is FALSE)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetScriptName", "s", NULL, "llGetScriptName()\nReturns the script name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetNumberOfSides", "i", NULL, "integer llGetNumberOfSides()\nReturns the number of sides")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAxisAngle2Rot", "q", "vf", "rotation llAxisAngle2Rot(vector axis, float angle)\nReturns the rotation generated angle about axis")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Axis", "v", "q", "vector llRot2Axis(rotation rot)\nReturns the rotation axis represented by rot")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRot2Angle", "f", "q", "float llRot2Angle(rotation rot)\nReturns the rotation angle represented by rot")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAcos", "f", "f", "float llAcos(float val)\nReturns the arccosine in radians of val")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAsin", "f", "f", "float llAsin(float val)\nReturns the arcsine in radians of val")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAngleBetween", "f", "qq", "float llAngleBetween(rotation a, rotation b)\nReturns angle between rotation a and b")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryKey", "k", "s", "key llGetInventoryKey(string name)\nReturns the key of the inventory name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAllowInventoryDrop", NULL, "i", "llAllowInventoryDrop(integer add)\nIf add == TRUE, users without permissions can still drop inventory items onto task")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetSunDirection", "v", NULL, "vector llGetSunDirection()\nReturns the sun direction on the simulator")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTextureOffset", "v", "i", "vector llGetTextureOffset(integer side)\nReturns the texture offset of side in the x and y components of a vector")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTextureScale", "v", "i", "vector llGetTextureScale(integer side)\nReturns the texture scale of side in the x and y components of a vector")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTextureRot", "f", "i", "float llGetTextureRot(integer side)\nReturns the texture rotation of side")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSubStringIndex", "i", "ss", "integer llSubStringIndex(string source, string pattern)\nFinds index in source where pattern first appears (returns -1 if not found)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetOwnerKey", "k", "k", "key llGetOwnerKey(key id)\nFind the owner of id")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCenterOfMass", "v", NULL, "vector llGetCenterOfMass()\nGet the object's center of mass")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListSort", "l", "lii", "list llListSort(list src, integer stride, integer ascending)\nSort the list into blocks of stride in ascending order if ascending == TRUE. Note that sort only works between same types.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetListLength", "i", "l", "integer llGetListLength(list src)\nGet the number of elements in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2Integer", "i", "li", "integer llList2Integer(list src, integer index)\nCopy the integer at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2Float", "f", "li", "float llList2Float(list src, integer index)\nCopy the float at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2String", "s", "li", "string llList2String(list src, integer index)\nCopy the string at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2Key", "k", "li", "key llList2Key(list src, integer index)\nCopy the key at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2Vector", "v", "li", "vector llList2Vector(list src, integer index)\nCopy the vector at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2Rot", "q", "li", "rotation llList2Rot(list src, integer index)\nCopy the rotation at index in the list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2List", "l", "lii", "list llList2List(list src, integer start, integer end)\nCopy the slice of the list from start to end")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDeleteSubList", "l", "lii", "list llDeleteSubList(list src, integer start, integer end)\nRemove the slice from the list and return the remainder")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetListEntryType", "i", "li", "integer llGetListEntryType(list src, integer index)\nReturns the type of the index entry in the list\n(TYPE_INTEGER, TYPE_FLOAT, TYPE_STRING, TYPE_KEY, TYPE_VECTOR, TYPE_ROTATION, or TYPE_INVALID if index is off list)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2CSV", "s", "l", "string llList2CSV(list src)\nCreate a string of comma separated values from list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llCSV2List", "l", "s", "list llCSV2List(string src)\nCreate a list from a string of comma separated values")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListRandomize", "l", "li", "list llListRandomize(list src, integer stride)\nReturns a randomized list of blocks of size stride")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llList2ListStrided", "l", "liii", "list llList2ListStrided(list src, integer start, integer end, integer stride)\nCopy the strided slice of the list from start to end")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionCorner", "v", NULL, "vector llGetRegionCorner()\nReturns a vector with the south west corner x,y position of the region the object is in")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListInsertList", "l", "lli", "list llListInsertList(list dest, list src, integer start)\nInserts src into dest at position start")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListFindList", "i", "ll", "integer llListFindList(list src, list test)\nReturns the start of the first instance of test in src, -1 if not found")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectName", "s", NULL, "string llGetObjectName()\nReturns the name of the object script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetObjectName", NULL, "s", "llSetObjectName(string name)\nSets the objects name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetDate", "s", NULL, "string llGetDate()\nGets the date as YYYY-MM-DD")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llEdgeOfWorld", "i", "vv", "integer llEdgeOfWorld(vector pos, vector dir)\nChecks to see whether the border hit by dir from pos is the edge of the world (has no neighboring simulator)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAgentInfo", "i", "k", "integer llGetAgentInfo(key id)\nGets information about agent ID.\nReturns AGENT_FLYING, AGENT_ATTACHMENTS, AGENT_SCRIPTED, AGENT_SITTING, AGENT_ON_OBJECT, AGENT_MOUSELOOK, AGENT_AWAY, AGENT_BUSY, AGENT_TYPING, AGENT_CROUCHING, AGENT_ALWAYS_RUN, AGENT_WALKING and/or AGENT_IN_AIR.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llAdjustSoundVolume", NULL, "f", "llAdjustSoundVolume(float volume)\nadjusts volume of attached sound (0.0 - 1.0)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetSoundQueueing", NULL, "i", "llSetSoundQueueing(integer queue)\ndetermines whether attached sound calls wait for the current sound to finish (0 = no [default], nonzero = yes)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetSoundRadius", NULL, "f", "llSetSoundRadius(float radius)\nestablishes a hard cut-off radius for audibility of scripted sounds (both attached and triggered)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llKey2Name", "s", "k", "string llKey2Name(key id)\nReturns the name of the object key, iff the object is in the current simulator, otherwise the empty string")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetTextureAnim", NULL, "iiiifff", "llSetTextureAnim(integer mode, integer face, integer sizex, integer sizey, float start, float length, float rate)\nAnimate the texture on the specified face/faces")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llTriggerSoundLimited", NULL, "sfvv", "llTriggerSoundLimited(string sound, float volume, vector tne, vector bsw)\nplays sound at volume (0.0 - 1.0), centered at but not attached to object, limited to AABB defined by vectors top-north-east and bottom-south-west")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llEjectFromLand", NULL, "k", "llEjectFromLand(key pest)\nEjects pest from land that you own")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llParseString2List", "l", "sll", "list llParseString2List(string src, list separators, list spacers)\nBreaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llOverMyLand", "i", "k", "integer llOverMyLand(key id)\nReturns TRUE if id is over land owner of object owns, FALSE otherwise")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetLandOwnerAt", "k", "v", "key llGetLandOwnerAt(vector pos)\nReturns the key of the land owner, NULL_KEY if public")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llGetNotecardLine", "k", "si", "key llGetNotecardLine(string name, integer line)\nReturns line line of notecard name via the dataserver event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAgentSize", "v", "k", "vector llGetAgentSize(key id)\nIf the agent is in the same sim as the object, returns the size of the avatar")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSameGroup", "i", "k", "integer llSameGroup(key id)\nReturns TRUE if ID is in the same sim and has the same active group, otherwise FALSE")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llUnSit", NULL, "k", "key llUnSit(key id)\nIf agent identified by id is sitting on the object the script is attached to or is over land owned by the objects owner, the agent is forced to stand up")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGroundSlope", "v", "v", "vector llGroundSlope(vector v)\nreturns the ground slope below the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGroundNormal", "v", "v", "vector llGroundNormal(vector v)\nreturns the ground normal below the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGroundContour", "v", "v", "vector llGroundCountour(vector v)\nreturns the ground contour below the object position + v")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAttached", "i", NULL, "integer llGetAttached()\nreturns the object attachment point or 0 if not attached")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetFreeMemory", "i", NULL, "integer llGetFreeMemory()\nreturns the available heap space for the current script")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionName", "s", NULL, "string llGetRegionName()\nreturns the current region name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionTimeDilation", "f", NULL, "float llGetRegionTimeDilation()\nreturns the current time dilation as a float between 0 and 1")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionFPS", "f", NULL, "float llGetRegionFPS()\nreturns the mean region frames per second")); + // energy, sleep, dummy_func, name, return type, parameters, gods-only + addFunction(10.f, 0.f, dummy_func, "llSin", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llCos", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llTan", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llAtan2", "f", "ff"); + addFunction(10.f, 0.f, dummy_func, "llSqrt", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llPow", "f", "ff"); + addFunction(10.f, 0.f, dummy_func, "llAbs", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llFabs", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llFrand", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llFloor", "i", "f"); + addFunction(10.f, 0.f, dummy_func, "llCeil", "i", "f"); + addFunction(10.f, 0.f, dummy_func, "llRound", "i", "f"); + addFunction(10.f, 0.f, dummy_func, "llVecMag", "f", "v"); + addFunction(10.f, 0.f, dummy_func, "llVecNorm", "v", "v"); + addFunction(10.f, 0.f, dummy_func, "llVecDist", "f", "vv"); + addFunction(10.f, 0.f, dummy_func, "llRot2Euler", "v", "q"); + addFunction(10.f, 0.f, dummy_func, "llEuler2Rot", "q", "v"); + addFunction(10.f, 0.f, dummy_func, "llAxes2Rot", "q", "vvv"); + addFunction(10.f, 0.f, dummy_func, "llRot2Fwd", "v", "q"); + addFunction(10.f, 0.f, dummy_func, "llRot2Left", "v", "q"); + addFunction(10.f, 0.f, dummy_func, "llRot2Up", "v", "q"); + addFunction(10.f, 0.f, dummy_func, "llRotBetween", "q", "vv"); + addFunction(10.f, 0.f, dummy_func, "llWhisper", NULL, "is"); + addFunction(10.f, 0.f, dummy_func, "llSay", NULL, "is"); + addFunction(10.f, 0.f, dummy_func, "llShout", NULL, "is"); + addFunction(10.f, 0.f, dummy_func, "llListen", "i", "isks"); + addFunction(10.f, 0.f, dummy_func, "llListenControl", NULL, "ii"); + addFunction(10.f, 0.f, dummy_func, "llListenRemove", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llSensor", NULL, "skiff"); + addFunction(10.f, 0.f, dummy_func, "llSensorRepeat", NULL, "skifff"); + addFunction(10.f, 0.f, dummy_func, "llSensorRemove", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llDetectedName", "s", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedKey", "k", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedOwner", "k", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedType", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedPos", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedVel", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedGrab", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedRot", "q", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedGroup", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedLinkNumber", "i", "i"); + addFunction(0.f, 0.f, dummy_func, "llDie", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llGround", "f", "v"); + addFunction(10.f, 0.f, dummy_func, "llCloud", "f", "v"); + addFunction(10.f, 0.f, dummy_func, "llWind", "v", "v"); + addFunction(10.f, 0.f, dummy_func, "llSetStatus", NULL, "ii"); + addFunction(10.f, 0.f, dummy_func, "llGetStatus", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llSetScale", NULL, "v"); + addFunction(10.f, 0.f, dummy_func, "llGetScale", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetColor", NULL, "vi"); + addFunction(10.f, 0.f, dummy_func, "llGetAlpha", "f", "i"); + addFunction(10.f, 0.f, dummy_func, "llSetAlpha", NULL, "fi"); + addFunction(10.f, 0.f, dummy_func, "llGetColor", "v", "i"); + addFunction(10.f, 0.2f, dummy_func, "llSetTexture", NULL, "si"); + addFunction(10.f, 0.2f, dummy_func, "llScaleTexture", NULL, "ffi"); + addFunction(10.f, 0.2f, dummy_func, "llOffsetTexture", NULL, "ffi"); + addFunction(10.f, 0.2f, dummy_func, "llRotateTexture", NULL, "fi"); + addFunction(10.f, 0.f, dummy_func, "llGetTexture", "s", "i"); + addFunction(10.f, 0.2f, dummy_func, "llSetPos", NULL, "v"); + addFunction(10.f, 0.f, dummy_func, "llGetPos", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetLocalPos", "v", NULL); + addFunction(10.f, 0.2f, dummy_func, "llSetRot", NULL, "q"); + addFunction(10.f, 0.f, dummy_func, "llGetRot", "q", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetLocalRot", "q", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetForce", NULL, "vi"); + addFunction(10.f, 0.f, dummy_func, "llGetForce", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llTarget", "i", "vf"); + addFunction(10.f, 0.f, dummy_func, "llTargetRemove", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llRotTarget", "i", "qf"); + addFunction(10.f, 0.f, dummy_func, "llRotTargetRemove", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llMoveToTarget", NULL, "vf"); + addFunction(10.f, 0.f, dummy_func, "llStopMoveToTarget", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llApplyImpulse", NULL, "vi"); + addFunction(10.f, 0.f, dummy_func, "llApplyRotationalImpulse", NULL, "vi"); + addFunction(10.f, 0.f, dummy_func, "llSetTorque", NULL, "vi"); + addFunction(10.f, 0.f, dummy_func, "llGetTorque", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetForceAndTorque", NULL, "vvi"); + addFunction(10.f, 0.f, dummy_func, "llGetVel", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetAccel", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetOmega", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetTimeOfDay", "f", ""); + addFunction(10.f, 0.f, dummy_func, "llGetWallclock", "f", ""); + addFunction(10.f, 0.f, dummy_func, "llGetTime", "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llResetTime", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llGetAndResetTime", "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llSound", NULL, "sfii"); + addFunction(10.f, 0.f, dummy_func, "llPlaySound", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llLoopSound", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llLoopSoundMaster", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llLoopSoundSlave", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llPlaySoundSlave", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llTriggerSound", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llStopSound", NULL, ""); + addFunction(10.f, 1.f, dummy_func, "llPreloadSound", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llGetSubString", "s", "sii"); + addFunction(10.f, 0.f, dummy_func, "llDeleteSubString", "s", "sii"); + addFunction(10.f, 0.f, dummy_func, "llInsertString", "s", "sis"); + addFunction(10.f, 0.f, dummy_func, "llToUpper", "s", "s"); + addFunction(10.f, 0.f, dummy_func, "llToLower", "s", "s"); + addFunction(10.f, 0.f, dummy_func, "llGiveMoney", "i", "ki"); + addFunction(10.f, 0.1f, dummy_func, "llMakeExplosion", NULL, "iffffsv"); + addFunction(10.f, 0.1f, dummy_func, "llMakeFountain", NULL, "iffffisvf"); + addFunction(10.f, 0.1f, dummy_func, "llMakeSmoke", NULL, "iffffsv"); + addFunction(10.f, 0.1f, dummy_func, "llMakeFire", NULL, "iffffsv"); + addFunction(200.f, 0.1f, dummy_func, "llRezObject", NULL, "svvqi"); + addFunction(10.f, 0.f, dummy_func, "llLookAt", NULL, "vff"); + addFunction(10.f, 0.f, dummy_func, "llStopLookAt", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llSetTimerEvent", NULL, "f"); + addFunction(0.f, 0.f, dummy_func, "llSleep", NULL, "f"); + addFunction(10.f, 0.f, dummy_func, "llGetMass", "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llCollisionFilter", NULL, "ski"); + addFunction(10.f, 0.f, dummy_func, "llTakeControls", NULL, "iii"); + addFunction(10.f, 0.f, dummy_func, "llReleaseControls", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llAttachToAvatar", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llDetachFromAvatar", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llTakeCamera", NULL, "k"); + addFunction(10.f, 0.f, dummy_func, "llReleaseCamera", NULL, "k"); + addFunction(10.f, 0.f, dummy_func, "llGetOwner", "k", NULL); + addFunction(10.f, 2.f, dummy_func, "llInstantMessage", NULL, "ks"); + addFunction(10.f, 20.f, dummy_func, "llEmail", NULL, "sss"); + addFunction(10.f, 0.f, dummy_func, "llGetNextEmail", NULL, "ss"); + addFunction(10.f, 0.f, dummy_func, "llGetKey", "k", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetBuoyancy", NULL, "f"); + addFunction(10.f, 0.f, dummy_func, "llSetHoverHeight", NULL, "fif"); + addFunction(10.f, 0.f, dummy_func, "llStopHover", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llMinEventDelay", NULL, "f"); + addFunction(10.f, 0.f, dummy_func, "llSoundPreload", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llRotLookAt", NULL, "qff"); + addFunction(10.f, 0.f, dummy_func, "llStringLength", "i", "s"); + addFunction(10.f, 0.f, dummy_func, "llStartAnimation", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llStopAnimation", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llPointAt", NULL, "v"); + addFunction(10.f, 0.f, dummy_func, "llStopPointAt", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llTargetOmega", NULL, "vff"); + addFunction(10.f, 0.f, dummy_func, "llGetStartParameter", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llGodLikeRezObject", NULL, "kv", TRUE); + addFunction(10.f, 0.f, dummy_func, "llRequestPermissions", NULL, "ki"); + addFunction(10.f, 0.f, dummy_func, "llGetPermissionsKey", "k", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetPermissions", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetLinkNumber", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetLinkColor", NULL, "ivi"); + addFunction(10.f, 1.f, dummy_func, "llCreateLink", NULL, "ki"); + addFunction(10.f, 0.f, dummy_func, "llBreakLink", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llBreakAllLinks", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llGetLinkKey", "k", "i"); + addFunction(10.f, 0.f, dummy_func, "llGetLinkName", "s", "i"); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryNumber", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryName", "s", "ii"); + addFunction(10.f, 0.f, dummy_func, "llSetScriptState", NULL, "si"); + addFunction(10.f, 0.f, dummy_func, "llGetEnergy", "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llGiveInventory", NULL, "ks"); + addFunction(10.f, 0.f, dummy_func, "llRemoveInventory", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llSetText", NULL, "svf"); + addFunction(10.f, 0.f, dummy_func, "llWater", "f", "v"); + addFunction(10.f, 0.f, dummy_func, "llPassTouches", NULL, "i"); + addFunction(10.f, 0.1f, dummy_func, "llRequestAgentData", "k", "ki"); + addFunction(10.f, 1.f, dummy_func, "llRequestInventoryData", "k", "s"); + addFunction(10.f, 0.f, dummy_func, "llSetDamage", NULL, "f"); + addFunction(100.f, 5.f, dummy_func, "llTeleportAgentHome", NULL, "k"); + addFunction(10.f, 0.f, dummy_func, "llModifyLand", NULL, "ii"); + addFunction(10.f, 0.f, dummy_func, "llCollisionSound", NULL, "sf"); + addFunction(10.f, 0.f, dummy_func, "llCollisionSprite", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llGetAnimation", "s", "k"); + addFunction(10.f, 0.f, dummy_func, "llResetScript", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llMessageLinked", NULL, "iisk"); + addFunction(10.f, 0.f, dummy_func, "llPushObject", NULL, "kvvi"); + addFunction(10.f, 0.f, dummy_func, "llPassCollisions", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llGetScriptName", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetNumberOfSides", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llAxisAngle2Rot", "q", "vf"); + addFunction(10.f, 0.f, dummy_func, "llRot2Axis", "v", "q"); + addFunction(10.f, 0.f, dummy_func, "llRot2Angle", "f", "q"); + addFunction(10.f, 0.f, dummy_func, "llAcos", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llAsin", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llAngleBetween", "f", "qq"); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryKey", "k", "s"); + addFunction(10.f, 0.f, dummy_func, "llAllowInventoryDrop", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llGetSunDirection", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetTextureOffset", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llGetTextureScale", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llGetTextureRot", "f", "i"); + addFunction(10.f, 0.f, dummy_func, "llSubStringIndex", "i", "ss"); + addFunction(10.f, 0.f, dummy_func, "llGetOwnerKey", "k", "k"); + addFunction(10.f, 0.f, dummy_func, "llGetCenterOfMass", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llListSort", "l", "lii"); + addFunction(10.f, 0.f, dummy_func, "llGetListLength", "i", "l"); + addFunction(10.f, 0.f, dummy_func, "llList2Integer", "i", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2Float", "f", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2String", "s", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2Key", "k", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2Vector", "v", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2Rot", "q", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2List", "l", "lii"); + addFunction(10.f, 0.f, dummy_func, "llDeleteSubList", "l", "lii"); + addFunction(10.f, 0.f, dummy_func, "llGetListEntryType", "i", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2CSV", "s", "l"); + addFunction(10.f, 0.f, dummy_func, "llCSV2List", "l", "s"); + addFunction(10.f, 0.f, dummy_func, "llListRandomize", "l", "li"); + addFunction(10.f, 0.f, dummy_func, "llList2ListStrided", "l", "liii"); + addFunction(10.f, 0.f, dummy_func, "llGetRegionCorner", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llListInsertList", "l", "lli"); + addFunction(10.f, 0.f, dummy_func, "llListFindList", "i", "ll"); + addFunction(10.f, 0.f, dummy_func, "llGetObjectName", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetObjectName", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llGetDate", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llEdgeOfWorld", "i", "vv"); + addFunction(10.f, 0.f, dummy_func, "llGetAgentInfo", "i", "k"); + addFunction(10.f, 0.1f, dummy_func, "llAdjustSoundVolume", NULL, "f"); + addFunction(10.f, 0.f, dummy_func, "llSetSoundQueueing", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llSetSoundRadius", NULL, "f"); + addFunction(10.f, 0.f, dummy_func, "llKey2Name", "s", "k"); + addFunction(10.f, 0.f, dummy_func, "llSetTextureAnim", NULL, "iiiifff"); + addFunction(10.f, 0.f, dummy_func, "llTriggerSoundLimited", NULL, "sfvv"); + addFunction(10.f, 0.f, dummy_func, "llEjectFromLand", NULL, "k"); + addFunction(10.f, 0.f, dummy_func, "llParseString2List", "l", "sll"); + addFunction(10.f, 0.f, dummy_func, "llOverMyLand", "i", "k"); + addFunction(10.f, 0.f, dummy_func, "llGetLandOwnerAt", "k", "v"); + addFunction(10.f, 0.1f, dummy_func, "llGetNotecardLine", "k", "si"); + addFunction(10.f, 0.f, dummy_func, "llGetAgentSize", "v", "k"); + addFunction(10.f, 0.f, dummy_func, "llSameGroup", "i", "k"); + addFunction(10.f, 0.f, dummy_func, "llUnSit", NULL, "k"); + addFunction(10.f, 0.f, dummy_func, "llGroundSlope", "v", "v"); + addFunction(10.f, 0.f, dummy_func, "llGroundNormal", "v", "v"); + addFunction(10.f, 0.f, dummy_func, "llGroundContour", "v", "v"); + addFunction(10.f, 0.f, dummy_func, "llGetAttached", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetFreeMemory", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetRegionName", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetRegionTimeDilation", "f", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetRegionFPS", "f", NULL); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llParticleSystem", NULL, "l", "llParticleSystem(list rules)\nCreates a particle system based on rules. Empty list removes particle system from object.\nList format is [ rule1, data1, rule2, data2 . . . rulen, datan ]")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGroundRepel", NULL, "fif", "llGroundRepel(float height, integer water, float tau)\nCritically damps to height if within height*0.5 of level (either above ground level or above the higher of land and water if water == TRUE)")); - addFunction(new LLScriptLibraryFunction(10.f, 3.f, dummy_func, "llGiveInventoryList", NULL, "ksl", "llGiveInventoryList(key destination, string category, list inventory)\nGive inventory to destination in a new category")); + addFunction(10.f, 0.f, dummy_func, "llParticleSystem", NULL, "l"); + addFunction(10.f, 0.f, dummy_func, "llGroundRepel", NULL, "fif"); + addFunction(10.f, 3.f, dummy_func, "llGiveInventoryList", NULL, "ksl"); // script calls for vehicle action - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetVehicleType", NULL, "i", "llSetVehicleType(integer type)\nsets vehicle to one of the default types")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetVehicleFloatParam", NULL, "if", "llSetVehicleFloatParam(integer param, float value)\nsets the specified vehicle float parameter")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetVehicleVectorParam", NULL, "iv", "llSetVehicleVectorParam(integer param, vector vec)\nsets the specified vehicle vector parameter")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetVehicleRotationParam", NULL, "iq", "llSetVehicleVectorParam(integer param, rotation rot)\nsets the specified vehicle rotation parameter")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetVehicleFlags", NULL, "i", "llSetVehicleFlags(integer flags)\nsets the enabled bits in 'flags'")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRemoveVehicleFlags", NULL, "i", "llRemoveVehicleFlags(integer flags)\nremoves the enabled bits in 'flags'")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSitTarget", NULL, "vq", "llSitTarget(vector offset, rotation rot)\nSet the sit location for this object (if offset == <0,0,0> clear it)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llAvatarOnSitTarget", "k", NULL, "key llAvatarOnSitTarget()\nIf an avatar is sitting on the sit target, return the avatar's key, NULL_KEY otherwise")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llAddToLandPassList", NULL, "kf", "llAddToLandPassList(key avatar, float hours)\nAdd avatar to the land pass list for hours")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetTouchText", NULL, "s", "llSetTouchText(string text)\nDisplays text in pie menu that acts as a touch")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetSitText", NULL, "s", "llSetSitText(string text)\nDisplays text rather than sit in pie menu")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCameraEyeOffset", NULL, "v", "llSetCameraEyeOffset(vector offset)\nSets the camera eye offset used in this object if an avatar sits on it")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCameraAtOffset", NULL, "v", "llSetCameraAtOffset(vector offset)\nSets the camera at offset used in this object if an avatar sits on it")); + addFunction(10.f, 0.f, dummy_func, "llSetVehicleType", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llSetVehicleFloatParam", NULL, "if"); + addFunction(10.f, 0.f, dummy_func, "llSetVehicleVectorParam", NULL, "iv"); + addFunction(10.f, 0.f, dummy_func, "llSetVehicleRotationParam", NULL, "iq"); + addFunction(10.f, 0.f, dummy_func, "llSetVehicleFlags", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llRemoveVehicleFlags", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llSitTarget", NULL, "vq"); + addFunction(10.f, 0.f, dummy_func, "llAvatarOnSitTarget", "k", NULL); + addFunction(10.f, 0.1f, dummy_func, "llAddToLandPassList", NULL, "kf"); + addFunction(10.f, 0.f, dummy_func, "llSetTouchText", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llSetSitText", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llSetCameraEyeOffset", NULL, "v"); + addFunction(10.f, 0.f, dummy_func, "llSetCameraAtOffset", NULL, "v"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDumpList2String", "s", "ls", "string llDumpList2String(list src, string separator)\nWrite the list out in a single string using separator between values")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llScriptDanger", "i", "v", "integer llScriptDanger(vector pos)\nReturns true if pos is over public land, sandbox land, land that doesn't allow everyone to edit and build, or land that doesn't allow outside scripts")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llDialog", NULL, "ksli", "llDialog(key avatar, string message, list buttons, integer chat_channel\nShows a dialog box on the avatar's screen with the message.\nUp to 12 strings in the list form buttons.\nIf a button is clicked, the name is chatted on chat_channel.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llVolumeDetect", NULL, "i", "llVolumeDetect(integer detect)\nIf detect = TRUE, object becomes phantom but triggers collision_start and collision_end events\nwhen other objects start and stop interpenetrating.\nMust be applied to the root object.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llResetOtherScript", NULL, "s", "llResetOtherScript(string name)\nResets script name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetScriptState", "i", "s", "integer llGetScriptState(string name)\nResets TRUE if script name is running")); - addFunction(new LLScriptLibraryFunction(10.f, 3.f, dummy_func, "llRemoteLoadScript", NULL, "ksii", "Deprecated. Please use llRemoteLoadScriptPin instead.")); + addFunction(10.f, 0.f, dummy_func, "llDumpList2String", "s", "ls"); + addFunction(10.f, 0.f, dummy_func, "llScriptDanger", "i", "v"); + addFunction(10.f, 1.f, dummy_func, "llDialog", NULL, "ksli"); + addFunction(10.f, 0.f, dummy_func, "llVolumeDetect", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llResetOtherScript", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llGetScriptState", "i", "s"); + addFunction(10.f, 3.f, dummy_func, "llRemoteLoadScript", NULL, "ksii"); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetRemoteScriptAccessPin", NULL, "i", "llSetRemoteScriptAccessPin(integer pin)\nIf pin is set to a non-zero number, the task will accept remote script\nloads via llRemoteLoadScriptPin if it passes in the correct pin.\nOthersise, llRemoteLoadScriptPin is ignored.")); - addFunction(new LLScriptLibraryFunction(10.f, 3.f, dummy_func, "llRemoteLoadScriptPin", NULL, "ksiii", "llRemoteLoadScriptPin(key target, string name, integer pin, integer running, integer start_param)\nIf the owner of the object this script is attached can modify target,\nthey are in the same region,\nand the matching pin is used,\ncopy script name onto target,\nif running == TRUE, start the script with param.")); + addFunction(10.f, 0.2f, dummy_func, "llSetRemoteScriptAccessPin", NULL, "i"); + addFunction(10.f, 3.f, dummy_func, "llRemoteLoadScriptPin", NULL, "ksiii"); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llOpenRemoteDataChannel", NULL, NULL, "llOpenRemoteDataChannel()\nCreates a channel to listen for XML-RPC calls. Will trigger a remote_data event with channel id once it is available.")); - addFunction(new LLScriptLibraryFunction(10.f, 3.f, dummy_func, "llSendRemoteData", "k", "ksis", "key llSendRemoteData(key channel, string dest, integer idata, string sdata)\nSend an XML-RPC request to dest through channel with payload of channel (in a string), integer idata and string sdata.\nA message identifier key is returned.\nAn XML-RPC reply will trigger a remote_data event and reference the message id.\nThe message_id is returned.")); - addFunction(new LLScriptLibraryFunction(10.f, 3.f, dummy_func, "llRemoteDataReply", NULL, "kksi", "llRemoteDataReply(key channel, key message_id, string sdata, integer idata)\nSend an XML-RPC reply to message_id on channel with payload of string sdata and integer idata")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llCloseRemoteDataChannel", NULL, "k", "llCloseRemoteDataChannel(key channel)\nCloses XML-RPC channel.")); + addFunction(10.f, 1.f, dummy_func, "llOpenRemoteDataChannel", NULL, NULL); + addFunction(10.f, 3.f, dummy_func, "llSendRemoteData", "k", "ksis"); + addFunction(10.f, 3.f, dummy_func, "llRemoteDataReply", NULL, "kksi"); + addFunction(10.f, 1.f, dummy_func, "llCloseRemoteDataChannel", NULL, "k"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llMD5String", "s", "si", "string llMD5String(string src, integer nonce)\nPerforms a RSA Data Security, Inc. MD5 Message-Digest Algorithm on string with nonce. Returns a 32 character hex string.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetPrimitiveParams", NULL, "l", "llSetPrimitiveParams(list rules)\nSet primitive parameters based on rules.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStringToBase64", "s", "s", "string llStringToBase64(string str)\nConverts a string to the Base 64 representation of the string.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llBase64ToString", "s", "s", "string llBase64ToString(string str)\nConverts a Base 64 string to a conventional string. If the conversion creates any unprintable characters, they are converted to spaces.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.3f, dummy_func, "llXorBase64Strings", "s", "ss", "string llXorBase64Strings(string s1, string s2)\nDEPRECATED! Please use llXorBase64StringsCorrect instead!! Incorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1. Retained for backwards compatability.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRemoteDataSetRegion", NULL, NULL, "llRemoteDataSetRegion()\nIf an object using remote data channels changes regions, you must call this function to reregister the remote data channels.\nYou do not need to make this call if you don't change regions.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLog10", "f", "f", "float llLog10(float val)\nReturns the base 10 log of val if val > 0, otherwise returns 0.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llLog", "f", "f", "float llLog(float val)\nReturns the base e log of val if val > 0, otherwise returns 0.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAnimationList", "l", "k", "list llGetAnimationList(key id)\nGets a list of all playing animations for avatar id")); - addFunction(new LLScriptLibraryFunction(10.f, 2.f, dummy_func, "llSetParcelMusicURL", NULL, "s", "llSetParcelMusicURL(string url)\nSets the streaming audio URL for the parcel object is on")); + addFunction(10.f, 0.f, dummy_func, "llMD5String", "s", "si"); + addFunction(10.f, 0.2f, dummy_func, "llSetPrimitiveParams", NULL, "l"); + addFunction(10.f, 0.f, dummy_func, "llStringToBase64", "s", "s"); + addFunction(10.f, 0.f, dummy_func, "llBase64ToString", "s", "s"); + addFunction(10.f, 0.3f, dummy_func, "llXorBase64Strings", "s", "ss"); + addFunction(10.f, 0.f, dummy_func, "llRemoteDataSetRegion", NULL, NULL); + addFunction(10.f, 0.f, dummy_func, "llLog10", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llLog", "f", "f"); + addFunction(10.f, 0.f, dummy_func, "llGetAnimationList", "l", "k"); + addFunction(10.f, 2.f, dummy_func, "llSetParcelMusicURL", NULL, "s"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRootPosition", "v", NULL, "vector llGetRootPosition()\nGets the global position of the root object of the object script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRootRotation", "q", NULL, "rotation llGetRootRotation()\nGets the global rotation of the root object of the object script is attached to")); + addFunction(10.f, 0.f, dummy_func, "llGetRootPosition", "v", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetRootRotation", "q", NULL); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectDesc", "s", NULL, "string llGetObjectDesc()\nReturns the description of the object the script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetObjectDesc", NULL, "s", "llSetObjectDesc(string name)\nSets the object's description")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCreator", "k", NULL, "key llGetCreator()\nReturns the creator of the object")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetTimestamp", "s", NULL, "string llGetTimestamp()\nGets the timestamp in the format: YYYY-MM-DDThh:mm:ss.ff..fZ")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetLinkAlpha", NULL, "ifi", "llSetLinkAlpha(integer linknumber, float alpha, integer face)\nIf a prim exists in the link chain at linknumber, set face to alpha")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetNumberOfPrims", "i", NULL, "integer llGetNumberOfPrims()\nReturns the number of prims in a link set the script is attached to")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llGetNumberOfNotecardLines", "k", "s", "key llGetNumberOfNotecardLines(string name)\nReturns number of lines in notecard 'name' via the dataserver event (cast return value to integer)")); + addFunction(10.f, 0.f, dummy_func, "llGetObjectDesc", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetObjectDesc", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llGetCreator", "k", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetTimestamp", "s", NULL); + addFunction(10.f, 0.f, dummy_func, "llSetLinkAlpha", NULL, "ifi"); + addFunction(10.f, 0.f, dummy_func, "llGetNumberOfPrims", "i", NULL); + addFunction(10.f, 0.1f, dummy_func, "llGetNumberOfNotecardLines", "k", "s"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetBoundingBox", "l", "k", "list llGetBoundingBox(key object)\nReturns the bounding box around an object (including any linked prims) relative to the root prim, in a list: [ (vector) min_corner, (vector) max_corner ]")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetGeometricCenter", "v", NULL, "vector llGetGeometricCenter()\nReturns the geometric center of the linked set the script is attached to.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llGetPrimitiveParams", "l", "l", "list llGetPrimitiveParams(list params)\nGets primitive parameters specified in the params list.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.0f, dummy_func, "llIntegerToBase64", "s", "i", "string llIntegerToBase64(integer number)\nBig endian encode of of integer as a Base64 string.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.0f, dummy_func, "llBase64ToInteger", "i", "s", "integer llBase64ToInteger(string str)\nBig endian decode of a Base64 string into an integer.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetGMTclock", "f", "", "float llGetGMTclock()\nGets the time in seconds since midnight in GMT")); - addFunction(new LLScriptLibraryFunction(10.f, 10.f, dummy_func, "llGetSimulatorHostname", "s", "", "string llGetSimulatorHostname()\nGets the hostname of the machine script is running on (same as string in viewer Help dialog)")); + addFunction(10.f, 0.f, dummy_func, "llGetBoundingBox", "l", "k"); + addFunction(10.f, 0.f, dummy_func, "llGetGeometricCenter", "v", NULL); + addFunction(10.f, 0.2f, dummy_func, "llGetPrimitiveParams", "l", "l"); + addFunction(10.f, 0.0f, dummy_func, "llIntegerToBase64", "s", "i"); + addFunction(10.f, 0.0f, dummy_func, "llBase64ToInteger", "i", "s"); + addFunction(10.f, 0.f, dummy_func, "llGetGMTclock", "f", ""); + addFunction(10.f, 10.f, dummy_func, "llGetSimulatorHostname", "s", ""); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetLocalRot", NULL, "q", "llSetLocalRot(rotation rot)\nsets the rotation of a child prim relative to the root prim")); + addFunction(10.f, 0.2f, dummy_func, "llSetLocalRot", NULL, "q"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llParseStringKeepNulls", "l", "sll", "list llParseStringKeepNulls(string src, list separators, list spacers)\nBreaks src into a list, discarding separators, keeping spacers (separators and spacers must be lists of strings, maximum of 8 each), keeping any null values generated.")); - addFunction(new LLScriptLibraryFunction(200.f, 0.1f, dummy_func, "llRezAtRoot", NULL, "svvqi", "llRezAtRoot(string inventory, vector pos, vector vel, rotation rot, integer param)\nInstantiate owner's inventory object at pos with velocity vel and rotation rot with start parameter param.\nThe last selected root object's location will be set to pos")); + addFunction(10.f, 0.f, dummy_func, "llParseStringKeepNulls", "l", "sll"); + addFunction(200.f, 0.1f, dummy_func, "llRezAtRoot", NULL, "svvqi"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectPermMask", "i", "i", "integer llGetObjectPermMask(integer mask)\nReturns the requested permission mask for the root object the task is attached to.", FALSE)); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetObjectPermMask", NULL, "ii", "llSetObjectPermMask(integer mask, integer value)\nSets the given permission mask to the new value on the root object the task is attached to.", TRUE)); + addFunction(10.f, 0.f, dummy_func, "llGetObjectPermMask", "i", "i", FALSE); + addFunction(10.f, 0.f, dummy_func, "llSetObjectPermMask", NULL, "ii", TRUE); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryPermMask", "i", "si", "integer llGetInventoryPermMask(string item, integer mask)\nReturns the requested permission mask for the inventory item.", FALSE)); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetInventoryPermMask", NULL, "sii", "llSetInventoryPermMask(string item, integer mask, integer value)\nSets the given permission mask to the new value on the inventory item.", TRUE)); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryCreator", "k", "s", "key llGetInventoryCreator(string item)\nReturns the key for the creator of the inventory item.", FALSE)); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llOwnerSay", NULL, "s", "llOwnerSay(string msg)\nsays msg to owner only (if owner in sim)")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llRequestSimulatorData", "k", "si", "key llRequestSimulatorData(string simulator, integer data)\nRequests data about simulator. When data is available the dataserver event will be raised")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llForceMouselook", NULL, "i", "llForceMouselook(integer mouselook)\nIf mouselook is TRUE any avatar that sits on this object is forced into mouselook mode")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectMass", "f", "k", "float llGetObjectMass(key id)\nGet the mass of the object with key id")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListReplaceList", "l", "llii", "list llListReplaceList(list dest, list src, integer start, integer end)\nReplaces start through end of dest with src.")); - addFunction(new LLScriptLibraryFunction(10.f, 10.f, dummy_func, "llLoadURL", NULL, "kss", "llLoadURL(key avatar_id, string message, string url)\nShows dialog to avatar avatar_id offering to load web page at URL. If user clicks yes, launches their web browser.")); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryPermMask", "i", "si", FALSE); + addFunction(10.f, 0.f, dummy_func, "llSetInventoryPermMask", NULL, "sii", TRUE); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryCreator", "k", "s", FALSE); + addFunction(10.f, 0.f, dummy_func, "llOwnerSay", NULL, "s"); + addFunction(10.f, 1.f, dummy_func, "llRequestSimulatorData", "k", "si"); + addFunction(10.f, 0.f, dummy_func, "llForceMouselook", NULL, "i"); + addFunction(10.f, 0.f, dummy_func, "llGetObjectMass", "f", "k"); + addFunction(10.f, 0.f, dummy_func, "llListReplaceList", "l", "llii"); + addFunction(10.f, 10.f, dummy_func, "llLoadURL", NULL, "kss"); - addFunction(new LLScriptLibraryFunction(10.f, 2.f, dummy_func, "llParcelMediaCommandList", NULL, "l", "llParcelMediaCommandList(list command)\nSends a list of commands, some with arguments, to a parcel.")); - addFunction(new LLScriptLibraryFunction(10.f, 2.f, dummy_func, "llParcelMediaQuery", "l", "l", "list llParcelMediaQuery(list query)\nSends a list of queries, returns a list of results.")); + addFunction(10.f, 2.f, dummy_func, "llParcelMediaCommandList", NULL, "l"); + addFunction(10.f, 2.f, dummy_func, "llParcelMediaQuery", "l", "l"); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llModPow", "i", "iii", "integer llModPow(integer a, integer b, integer c)\nReturns a raised to the b power, mod c. ( (a**b)%c ). b is capped at 0xFFFF (16 bits).")); + addFunction(10.f, 1.f, dummy_func, "llModPow", "i", "iii"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetInventoryType", "i", "s", "integer llGetInventoryType(string name)\nReturns the type of the inventory name")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetPayPrice", NULL, "il", "llSetPayPrice(integer price, list quick_pay_buttons)\nSets the default amount when someone chooses to pay this object.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCameraPos", "v", "", "vector llGetCameraPos()\nGets current camera position for agent task has permissions for.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetCameraRot", "q", "", "rotation llGetCameraRot()\nGets current camera orientation for agent task has permissions for.")); + addFunction(10.f, 0.f, dummy_func, "llGetInventoryType", "i", "s"); + addFunction(10.f, 0.f, dummy_func, "llSetPayPrice", NULL, "il"); + addFunction(10.f, 0.f, dummy_func, "llGetCameraPos", "v", ""); + addFunction(10.f, 0.f, dummy_func, "llGetCameraRot", "q", ""); - addFunction(new LLScriptLibraryFunction(10.f, 20.f, dummy_func, "llSetPrimURL", NULL, "s", "llSetPrimURL(string url)\nUpdates the URL for the web page shown on the sides of the object.")); - addFunction(new LLScriptLibraryFunction(10.f, 20.f, dummy_func, "llRefreshPrimURL", NULL, "", "llRefreshPrimURL()\nReloads the web page shown on the sides of the object.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llEscapeURL", "s", "s", "string llEscapeURL(string url)\nReturns and escaped/encoded version of url, replacing spaces with %20 etc.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llUnescapeURL", "s", "s", "string llUnescapeURL(string url)\nReturns and unescaped/unencoded version of url, replacing %20 with spaces etc.")); + addFunction(10.f, 20.f, dummy_func, "llSetPrimURL", NULL, "s"); + addFunction(10.f, 20.f, dummy_func, "llRefreshPrimURL", NULL, ""); + addFunction(10.f, 0.f, dummy_func, "llEscapeURL", "s", "s"); + addFunction(10.f, 0.f, dummy_func, "llUnescapeURL", "s", "s"); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llMapDestination", NULL, "svv", "llMapDestination(string simname, vector pos, vector look_at)\nOpens world map centered on region with pos highlighted.\nOnly works for scripts attached to avatar, or during touch events.\n(NOTE: look_at currently does nothing)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llAddToLandBanList", NULL, "kf", "llAddToLandBanList(key avatar, float hours)\nAdd avatar to the land ban list for hours")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llRemoveFromLandPassList", NULL, "k", "llRemoveFromLandPassList(key avatar)\nRemove avatar from the land pass list")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llRemoveFromLandBanList", NULL, "k", "llRemoveFromLandBanList(key avatar)\nRemove avatar from the land ban list")); + addFunction(10.f, 1.f, dummy_func, "llMapDestination", NULL, "svv"); + addFunction(10.f, 0.1f, dummy_func, "llAddToLandBanList", NULL, "kf"); + addFunction(10.f, 0.1f, dummy_func, "llRemoveFromLandPassList", NULL, "k"); + addFunction(10.f, 0.1f, dummy_func, "llRemoveFromLandBanList", NULL, "k"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetCameraParams", NULL, "l", "llSetCameraParams(list rules)\nSets multiple camera parameters at once.\nList format is [ rule1, data1, rule2, data2 . . . rulen, datan ]")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llClearCameraParams", NULL, NULL, "llClearCameraParams()\nResets all camera parameters to default values and turns off scripted camera control.")); + addFunction(10.f, 0.f, dummy_func, "llSetCameraParams", NULL, "l"); + addFunction(10.f, 0.f, dummy_func, "llClearCameraParams", NULL, NULL); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llListStatistics", "f", "il", "float llListStatistics(integer operation, list l)\nPerform statistical aggregate functions on list l using LIST_STAT_* operations.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetUnixTime", "i", NULL, "integer llGetUnixTime()\nGet the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC from the system clock.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetParcelFlags", "i", "v", "integer llGetParcelFlags(vector pos)\nGet the parcel flags (PARCEL_FLAG_*) for the parcel including the point pos.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionFlags", "i", NULL, "integer llGetRegionFlags()\nGet the region flags (REGION_FLAG_*) for the region the object is in.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llXorBase64StringsCorrect", "s", "ss", "string llXorBase64StringsCorrect(string s1, string s2)\nCorrectly performs an exclusive or on two Base 64 strings and returns a Base 64 string. s2 repeats if it is shorter than s1.")); + addFunction(10.f, 0.f, dummy_func, "llListStatistics", "f", "il"); + addFunction(10.f, 0.f, dummy_func, "llGetUnixTime", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llGetParcelFlags", "i", "v"); + addFunction(10.f, 0.f, dummy_func, "llGetRegionFlags", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llXorBase64StringsCorrect", "s", "ss"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llHTTPRequest", "k", "sls", "llHTTPRequest(string url, list parameters, string body)\nSend an HTTP request.")); + addFunction(10.f, 0.f, dummy_func, "llHTTPRequest", "k", "sls"); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llResetLandBanList", NULL, NULL, "llResetLandBanList()\nRemoves all residents from the land ban list.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.1f, dummy_func, "llResetLandPassList", NULL, NULL, "llResetLandPassList()\nRemoves all residents from the land access/pass list.")); + addFunction(10.f, 0.1f, dummy_func, "llResetLandBanList", NULL, NULL); + addFunction(10.f, 0.1f, dummy_func, "llResetLandPassList", NULL, NULL); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectPrimCount", "i", "k", "integer llGetObjectPrimCount(key object_id)\nReturns the total number of prims for an object.")); - addFunction(new LLScriptLibraryFunction(10.f, 2.0f, dummy_func, "llGetParcelPrimOwners", "l", "v", "list llGetParcelPrimOwners(vector pos)\nReturns a list of all residents who own objects on the parcel and the number of objects they own.\nRequires owner-like permissions for the parcel.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetParcelPrimCount", "i", "vii","integer llGetParcelPrimCount(vector pos, integer category, integer sim_wide)\nGets the number of prims on the parcel of the given category.\nCategories: PARCEL_COUNT_TOTAL, _OWNER, _GROUP, _OTHER, _SELECTED, _TEMP.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetParcelMaxPrims", "i", "vi","integer llGetParcelMaxPrims(vector pos, integer sim_wide)\nGets the maximum number of prims allowed on the parcel at pos.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetParcelDetails", "l", "vl","list llGetParcelDetails(vector pos, list params)\nGets the parcel details specified in params for the parcel at pos.\nParams is one or more of: PARCEL_DETAILS_NAME, _DESC, _OWNER, _GROUP, _AREA")); + addFunction(10.f, 0.f, dummy_func, "llGetObjectPrimCount", "i", "k"); + addFunction(10.f, 2.0f, dummy_func, "llGetParcelPrimOwners", "l", "v"); + addFunction(10.f, 0.f, dummy_func, "llGetParcelPrimCount", "i", "vii"); + addFunction(10.f, 0.f, dummy_func, "llGetParcelMaxPrims", "i", "vi"); + addFunction(10.f, 0.f, dummy_func, "llGetParcelDetails", "l", "vl"); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetLinkPrimitiveParams", NULL, "il", "llSetLinkPrimitiveParams(integer linknumber, list rules)\nSet primitive parameters for linknumber based on rules.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.2f, dummy_func, "llSetLinkTexture", NULL, "isi", "llSetLinkTexture(integer link_pos, string texture, integer face)\nSets the texture of face for link_pos")); + addFunction(10.f, 0.2f, dummy_func, "llSetLinkPrimitiveParams", NULL, "il"); + addFunction(10.f, 0.2f, dummy_func, "llSetLinkTexture", NULL, "isi"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llStringTrim", "s", "si", "string llStringTrim(string src, integer trim_type)\nTrim leading and/or trailing spaces from a string.\nUses trim_type of STRING_TRIM, STRING_TRIM_HEAD or STRING_TRIM_TAIL.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRegionSay", NULL, "is", "llRegionSay(integer channel, string msg)\nbroadcasts msg to entire region on channel (not 0.)")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetObjectDetails", "l", "kl", "list llGetObjectDetails(key id, list params)\nGets the object details specified in params for the object with key id.\nDetails are OBJECT_NAME, _DESC, _POS, _ROT, _VELOCITY, _OWNER, _GROUP, _CREATOR.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSetClickAction", NULL, "i", "llSetClickAction(integer action)\nSets the action performed when a prim is clicked upon.")); + addFunction(10.f, 0.f, dummy_func, "llStringTrim", "s", "si"); + addFunction(10.f, 0.f, dummy_func, "llRegionSay", NULL, "is"); + addFunction(10.f, 0.f, dummy_func, "llGetObjectDetails", "l", "kl"); + addFunction(10.f, 0.f, dummy_func, "llSetClickAction", NULL, "i"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetRegionAgentCount", "i", NULL, "int llGetRegionAgentCount()\nreturns the number of agents in a region")); - addFunction(new LLScriptLibraryFunction(10.f, 1.f, dummy_func, "llTextBox", NULL, "ksi", "llTextBox(key avatar, string message, integer chat_channel\nShows a dialog box on the avatar's screen with the message.\nA text box asks for input, and if entered the text is chatted on chat_channel.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetAgentLanguage", "s", "k", "string llGetAgentLanguage(key id)\nGets the agents preferred language..")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchUV", "v", "i", "vector llDetectedTouchUV(integer number)\nreturns the u and v coordinates in the first two components of a vector, for a triggered touch event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchFace", "i", "i", "integer llDetectedTouchFace(integer number)\nreturns the index of the face on the object for a triggered touch event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchPos", "v", "i", "vector llDetectedTouchPos(integer number)\nreturns the position touched for a triggered touch event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchNormal", "v", "i", "vector llDetectedTouchNormal(integer number)\nreturns the surface normal for a triggered touch event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchBinormal", "v", "i", "vector llDetectedTouchBinormal(integer number)\nreturns the surface binormal for a triggered touch event")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llDetectedTouchST", "v", "i", "vector llDetectedTouchST(integer number)\nreturns the s and t coordinates in the first two components of a vector, for a triggered touch event")); + addFunction(10.f, 0.f, dummy_func, "llGetRegionAgentCount", "i", NULL); + addFunction(10.f, 1.f, dummy_func, "llTextBox", NULL, "ksi"); + addFunction(10.f, 0.f, dummy_func, "llGetAgentLanguage", "s", "k"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchUV", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchFace", "i", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchPos", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchNormal", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchBinormal", "v", "i"); + addFunction(10.f, 0.f, dummy_func, "llDetectedTouchST", "v", "i"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llSHA1String", "s", "s", "string llSHA1String(string sr)\nPerforms a SHA1 security Hash. Returns a 40 character hex string.")); + addFunction(10.f, 0.f, dummy_func, "llSHA1String", "s", "s"); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetFreeURLs", "i", NULL, "integer llGetFreeURLs()\nreturns the available urls for the current script")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRequestURL", "k", NULL, "key llRequestURL()\nRequests one HTTP:// url for use by this object\nTriggers an http_server event with results.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llRequestSecureURL", "k", NULL, "key llRequestSecureURL()\nRequests one HTTPS:// (SSL) url for use by this object\nTriggers an http_server event with results.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llReleaseURL", NULL, "s", "llReleaseURL(string url)\nReleases the specified URL, it will no longer be usable.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llHTTPResponse", NULL, "kis", "llHTTPResponse(key id, integer status, string body)\nResponds to request id with status and body.")); - addFunction(new LLScriptLibraryFunction(10.f, 0.f, dummy_func, "llGetHTTPHeader", "s", "ks", "string llGetHTTPHeader(key id, string header)\nGet the value for header for request id.")); + addFunction(10.f, 0.f, dummy_func, "llGetFreeURLs", "i", NULL); + addFunction(10.f, 0.f, dummy_func, "llRequestURL", "k", NULL); + addFunction(10.f, 0.f, dummy_func, "llRequestSecureURL", "k", NULL); + addFunction(10.f, 0.f, dummy_func, "llReleaseURL", NULL, "s"); + addFunction(10.f, 0.f, dummy_func, "llHTTPResponse", NULL, "kis"); + addFunction(10.f, 0.f, dummy_func, "llGetHTTPHeader", "s", "ks"); - // energy, sleep, dummy_func, name, return type, parameters, help text, gods-only + // energy, sleep, dummy_func, name, return type, parameters, gods-only // IF YOU ADD NEW SCRIPT CALLS, YOU MUST PUT THEM AT THE END OF THIS LIST. // Otherwise the bytecode numbers for each call will be wrong, and all // existing scripts will crash. } -LLScriptLibraryFunction::LLScriptLibraryFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, const char *desc, BOOL god_only) +LLScriptLibraryFunction::LLScriptLibraryFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, BOOL god_only) : mEnergyUse(eu), mSleepTime(st), mExecFunc(exec_func), mName(name), mReturnType(ret_type), mArgs(args), mGodOnly(god_only) { - char *mDesc_ = new char[512]; - if (mSleepTime) - { - snprintf( /* Flawfinder: ignore */ - mDesc_, - 512, - "%s\nSleeps script for %.1f seconds.", - desc, - mSleepTime); - } - else - { - strncpy(mDesc_, desc, 512); /* Flawfinder: ignore */ - mDesc_[511] = '\0'; // just in case. - } - mDesc = mDesc_; } LLScriptLibraryFunction::~LLScriptLibraryFunction() { - delete [] mDesc; } -void LLScriptLibrary::addFunction(LLScriptLibraryFunction *func) +void LLScriptLibrary::addFunction(F32 eu, F32 st, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &), const char *name, const char *ret_type, const char *args, BOOL god_only) { - LLScriptLibraryFunction **temp = new LLScriptLibraryFunction*[mNextNumber + 1]; - if (mNextNumber) - { - memcpy( /* Flawfinder: ignore */ - temp, - mFunctions, - sizeof(LLScriptLibraryFunction*)*mNextNumber); - delete [] mFunctions; - } - mFunctions = temp; - mFunctions[mNextNumber] = func; - mNextNumber++; + LLScriptLibraryFunction func(eu, st, exec_func, name, ret_type, args, god_only); + mFunctions.push_back(func); } void LLScriptLibrary::assignExec(const char *name, void (*exec_func)(LLScriptLibData *, LLScriptLibData *, const LLUUID &)) { - S32 i; - for (i = 0; i < mNextNumber; i++) + for (std::vector::iterator i = mFunctions.begin(); + i != mFunctions.end(); ++i) { - if (!strcmp(name, mFunctions[i]->mName)) + if (!strcmp(name, i->mName)) { - mFunctions[i]->mExecFunc = exec_func; + i->mExecFunc = exec_func; + return; } } + + llerrs << "Unknown LSL function in assignExec: " << name << llendl; } void LLScriptLibData::print(std::ostream &s, BOOL b_prepend_comma) diff --git a/indra/media_plugins/CMakeLists.txt b/indra/media_plugins/CMakeLists.txt new file mode 100644 index 0000000000..d35afd8cbd --- /dev/null +++ b/indra/media_plugins/CMakeLists.txt @@ -0,0 +1,11 @@ +# -*- cmake -*- + +add_subdirectory(base) + +add_subdirectory(webkit) + +add_subdirectory(gstreamer010) + +if (WINDOWS OR DARWIN) + add_subdirectory(quicktime) +endif (WINDOWS OR DARWIN) diff --git a/indra/media_plugins/base/CMakeLists.txt b/indra/media_plugins/base/CMakeLists.txt new file mode 100644 index 0000000000..f8d2dabc6c --- /dev/null +++ b/indra/media_plugins/base/CMakeLists.txt @@ -0,0 +1,41 @@ +# -*- cmake -*- + +project(media_plugin_base) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(FindOpenGL) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + + +### media_plugin_base + +set(media_plugin_base_SOURCE_FILES + media_plugin_base.cpp +) + +set(media_plugin_base_HEADER_FILES + CMakeLists.txt + + media_plugin_base.h +) + +add_library(media_plugin_base + ${media_plugin_base_SOURCE_FILES} +) + diff --git a/indra/media_plugins/base/media_plugin_base.cpp b/indra/media_plugins/base/media_plugin_base.cpp new file mode 100644 index 0000000000..0b7092fad6 --- /dev/null +++ b/indra/media_plugins/base/media_plugin_base.cpp @@ -0,0 +1,154 @@ +/** + * @file media_plugin_base.cpp + * @brief Media plugin base class for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "media_plugin_base.h" + + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +//////////////////////////////////////////////////////////////////////////////// +// + +MediaPluginBase::MediaPluginBase( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) +{ + mHostSendFunction = host_send_func; + mHostUserData = host_user_data; + mDeleteMe = false; + mPixels = 0; + mWidth = 0; + mHeight = 0; + mTextureWidth = 0; + mTextureHeight = 0; + mDepth = 0; + mStatus = STATUS_NONE; +} + +std::string MediaPluginBase::statusString() +{ + std::string result; + + switch(mStatus) + { + case STATUS_LOADING: result = "loading"; break; + case STATUS_LOADED: result = "loaded"; break; + case STATUS_ERROR: result = "error"; break; + case STATUS_PLAYING: result = "playing"; break; + case STATUS_PAUSED: result = "paused"; break; + default: + // keep the empty string + break; + } + + return result; +} + +void MediaPluginBase::setStatus(EStatus status) +{ + if(mStatus != status) + { + mStatus = status; + sendStatus(); + } +} + + +void MediaPluginBase::staticReceiveMessage(const char *message_string, void **user_data) +{ + MediaPluginBase *self = (MediaPluginBase*)*user_data; + + if(self != NULL) + { + self->receiveMessage(message_string); + + // If the plugin has processed the delete message, delete it. + if(self->mDeleteMe) + { + delete self; + *user_data = NULL; + } + } +} + +void MediaPluginBase::sendMessage(const LLPluginMessage &message) +{ + std::string output = message.generate(); + mHostSendFunction(output.c_str(), &mHostUserData); +} + +void MediaPluginBase::setDirty(int left, int top, int right, int bottom) +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + sendMessage(message); +} + +void MediaPluginBase::sendStatus() +{ + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "media_status"); + + message.setValue("status", statusString()); + + sendMessage(message); +} + + +#if LL_WINDOWS +# define LLSYMEXPORT __declspec(dllexport) +#elif LL_LINUX +# define LLSYMEXPORT __attribute__ ((visibility("default"))) +#else +# define LLSYMEXPORT /**/ +#endif + +extern "C" +{ + LLSYMEXPORT int LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data); +} + +LLSYMEXPORT int +LLPluginInitEntryPoint(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return init_media_plugin(host_send_func, host_user_data, plugin_send_func, plugin_user_data); +} + +#ifdef WIN32 +int WINAPI DllEntryPoint( HINSTANCE hInstance, unsigned long reason, void* params ) +{ + return 1; +} +#endif diff --git a/indra/media_plugins/base/media_plugin_base.exp b/indra/media_plugins/base/media_plugin_base.exp new file mode 100644 index 0000000000..d7a945a1c5 --- /dev/null +++ b/indra/media_plugins/base/media_plugin_base.exp @@ -0,0 +1 @@ +_LLPluginInitEntryPoint \ No newline at end of file diff --git a/indra/media_plugins/base/media_plugin_base.h b/indra/media_plugins/base/media_plugin_base.h new file mode 100644 index 0000000000..8f600cb8d6 --- /dev/null +++ b/indra/media_plugins/base/media_plugin_base.h @@ -0,0 +1,111 @@ +/** + * @file media_plugin_base.h + * @brief Media plugin base class for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" + + +class MediaPluginBase +{ +public: + MediaPluginBase(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + virtual ~MediaPluginBase() {} + + virtual void receiveMessage(const char *message_string) = 0; + + static void staticReceiveMessage(const char *message_string, void **user_data); + +protected: + + typedef enum + { + STATUS_NONE, + STATUS_LOADING, + STATUS_LOADED, + STATUS_ERROR, + STATUS_PLAYING, + STATUS_PAUSED, + } EStatus; + + class SharedSegmentInfo + { + public: + void *mAddress; + size_t mSize; + }; + + void sendMessage(const LLPluginMessage &message); + void sendStatus(); + std::string statusString(); + void setStatus(EStatus status); + + // The quicktime plugin overrides this to add current time and duration to the message... + virtual void setDirty(int left, int top, int right, int bottom); + + typedef std::map SharedSegmentMap; + + + LLPluginInstance::sendMessageFunction mHostSendFunction; + void *mHostUserData; + bool mDeleteMe; + unsigned char* mPixels; + std::string mTextureSegmentName; + int mWidth; + int mHeight; + int mTextureWidth; + int mTextureHeight; + int mDepth; + EStatus mStatus; + SharedSegmentMap mSharedSegments; + +}; + +// The plugin must define this function to create its instance. +int init_media_plugin( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data, + LLPluginInstance::sendMessageFunction *plugin_send_func, + void **plugin_user_data); + +// It should look something like this: +/* +{ + MediaPluginFoo *self = new MediaPluginFoo(host_send_func, host_user_data); + *plugin_send_func = MediaPluginFoo::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} +*/ + diff --git a/indra/media_plugins/gstreamer010/CMakeLists.txt b/indra/media_plugins/gstreamer010/CMakeLists.txt new file mode 100644 index 0000000000..5c0ce3ee17 --- /dev/null +++ b/indra/media_plugins/gstreamer010/CMakeLists.txt @@ -0,0 +1,71 @@ +# -*- cmake -*- + +project(media_plugin_gstreamer010) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) + +include(GStreamer010Plugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} + ${GSTREAMER010_INCLUDE_DIRS} + ${GSTREAMER010_PLUGINS_BASE_INCLUDE_DIRS} +) + +### media_plugin_gstreamer010 + +set(media_plugin_gstreamer010_SOURCE_FILES + media_plugin_gstreamer010.cpp + llmediaimplgstreamer_syms.cpp + llmediaimplgstreamervidplug.cpp + ) + +set(media_plugin_gstreamer010_HEADER_FILES + llmediaimplgstreamervidplug.h + llmediaimplgstreamer_syms.h + llmediaimplgstreamertriviallogging.h + ) + +if (${CXX_VERSION} MATCHES "4.[23]") + # Work around a bad interaction between broken gstreamer headers and + # g++ 4.3's increased strictness. + set_source_files_properties(llmediaimplgstreamervidplug.cpp PROPERTIES + COMPILE_FLAGS -Wno-error=write-strings) +endif (${CXX_VERSION} MATCHES "4.[23]") + +add_library(media_plugin_gstreamer010 + SHARED + ${media_plugin_gstreamer010_SOURCE_FILES} +) + +target_link_libraries(media_plugin_gstreamer010 + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} + ${GSTREAMER010_LIBRARIES} +) + +add_dependencies(media_plugin_gstreamer010 + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + + diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h new file mode 100644 index 0000000000..ef41736c18 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer.h @@ -0,0 +1,57 @@ +/** + * @file llmediaimplgstreamer.h + * @author Tofu Linden + * @brief implementation that supports media playback via GStreamer. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// header guard +#ifndef llmediaimplgstreamer_h +#define llmediaimplgstreamer_h + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + + +extern "C" { +gboolean llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data); +} + +#endif // LL_GSTREAMER010_ENABLED + +#endif // llmediaimplgstreamer_h diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp new file mode 100644 index 0000000000..cc52232496 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.cpp @@ -0,0 +1,171 @@ +/** + * @file llmediaimplgstreamer_syms.cpp + * @brief dynamic GStreamer symbol-grabbing code + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if LL_GSTREAMER010_ENABLED + +#include + +extern "C" { +#include + +#include "apr_pools.h" +#include "apr_dso.h" +} + +#include "llmediaimplgstreamertriviallogging.h" + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL +#include "llmediaimplgstreamer_syms_raw.inc" +#include "llmediaimplgstreamer_syms_rawv.inc" +#undef LL_GST_SYM + +// a couple of stubs for disgusting reasons +GstDebugCategory* +ll_gst_debug_category_new(gchar *name, guint color, gchar *description) +{ + static GstDebugCategory dummy; + return &dummy; +} +void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname) +{ +} + +static bool sSymsGrabbed = false; +static apr_pool_t *sSymGSTDSOMemoryPool = NULL; +static apr_dso_handle_t *sSymGSTDSOHandleG = NULL; +static apr_dso_handle_t *sSymGSTDSOHandleV = NULL; + + +bool grab_gst_syms(std::string gst_dso_name, + std::string gst_dso_name_vid) +{ + if (sSymsGrabbed) + { + // already have grabbed good syms + return TRUE; + } + + bool sym_error = false; + bool rtn = false; + apr_status_t rv; + apr_dso_handle_t *sSymGSTDSOHandle = NULL; + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll##GSTSYM, sSymGSTDSOHandle, #GSTSYM); if (rv != APR_SUCCESS) {INFOMSG("Failed to grab symbol: %s", #GSTSYM); if (REQ) sym_error = true;} else DEBUGMSG("grabbed symbol: %s from %p", #GSTSYM, (void*)ll##GSTSYM);}while(0) + + //attempt to load the shared libraries + apr_pool_create(&sSymGSTDSOMemoryPool, NULL); + + if ( APR_SUCCESS == (rv = apr_dso_load(&sSymGSTDSOHandle, + gst_dso_name.c_str(), + sSymGSTDSOMemoryPool) )) + { + INFOMSG("Found DSO: %s", gst_dso_name.c_str()); +#include "llmediaimplgstreamer_syms_raw.inc" + + if ( sSymGSTDSOHandle ) + { + sSymGSTDSOHandleG = sSymGSTDSOHandle; + sSymGSTDSOHandle = NULL; + } + + if ( APR_SUCCESS == + (rv = apr_dso_load(&sSymGSTDSOHandle, + gst_dso_name_vid.c_str(), + sSymGSTDSOMemoryPool) )) + { + INFOMSG("Found DSO: %s", gst_dso_name_vid.c_str()); +#include "llmediaimplgstreamer_syms_rawv.inc" + rtn = !sym_error; + } + else + { + INFOMSG("Couldn't load DSO: %s", gst_dso_name_vid.c_str()); + rtn = false; // failure + } + } + else + { + INFOMSG("Couldn't load DSO: %s", gst_dso_name.c_str()); + rtn = false; // failure + } + + if (sym_error) + { + WARNMSG("Failed to find necessary symbols in GStreamer libraries."); + } + + if ( sSymGSTDSOHandle ) + { + sSymGSTDSOHandleV = sSymGSTDSOHandle; + sSymGSTDSOHandle = NULL; + } +#undef LL_GST_SYM + + sSymsGrabbed = !!rtn; + return rtn; +} + + +void ungrab_gst_syms() +{ + // should be safe to call regardless of whether we've + // actually grabbed syms. + + if ( sSymGSTDSOHandleG ) + { + apr_dso_unload(sSymGSTDSOHandleG); + sSymGSTDSOHandleG = NULL; + } + + if ( sSymGSTDSOHandleV ) + { + apr_dso_unload(sSymGSTDSOHandleV); + sSymGSTDSOHandleV = NULL; + } + + if ( sSymGSTDSOMemoryPool ) + { + apr_pool_destroy(sSymGSTDSOMemoryPool); + sSymGSTDSOMemoryPool = NULL; + } + + // NULL-out all of the symbols we'd grabbed +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) do{ll##GSTSYM = NULL;}while(0) +#include "llmediaimplgstreamer_syms_raw.inc" +#include "llmediaimplgstreamer_syms_rawv.inc" +#undef LL_GST_SYM + + sSymsGrabbed = false; +} + + +#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h new file mode 100644 index 0000000000..ee7473d6d1 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms.h @@ -0,0 +1,78 @@ +/** + * @file llmediaimplgstreamer_syms.h + * @brief dynamic GStreamer symbol-grabbing code + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +} + +bool grab_gst_syms(std::string gst_dso_name, + std::string gst_dso_name_vid); +void ungrab_gst_syms(); + +#define LL_GST_SYM(REQ, GSTSYM, RTN, ...) extern RTN (*ll##GSTSYM)(__VA_ARGS__) +#include "llmediaimplgstreamer_syms_raw.inc" +#include "llmediaimplgstreamer_syms_rawv.inc" +#undef LL_GST_SYM + +// regrettable hacks to give us better runtime compatibility with older systems +#define llg_return_if_fail(COND) do{if (!(COND)) return;}while(0) +#define llg_return_val_if_fail(COND,V) do{if (!(COND)) return V;}while(0) + +// regrettable hacks because GStreamer was not designed for runtime loading +#undef GST_TYPE_MESSAGE +#define GST_TYPE_MESSAGE (llgst_message_get_type()) +#undef GST_TYPE_OBJECT +#define GST_TYPE_OBJECT (llgst_object_get_type()) +#undef GST_TYPE_PIPELINE +#define GST_TYPE_PIPELINE (llgst_pipeline_get_type()) +#undef GST_TYPE_ELEMENT +#define GST_TYPE_ELEMENT (llgst_element_get_type()) +#undef GST_TYPE_VIDEO_SINK +#define GST_TYPE_VIDEO_SINK (llgst_video_sink_get_type()) +// more regrettable hacks to stub-out these .h-exposed GStreamer internals +void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname); +#undef _gst_debug_register_funcptr +#define _gst_debug_register_funcptr ll_gst_debug_register_funcptr +GstDebugCategory* ll_gst_debug_category_new(gchar *name, guint color, gchar *description); +#undef _gst_debug_category_new +#define _gst_debug_category_new ll_gst_debug_category_new +#undef __gst_debug_enabled +#define __gst_debug_enabled (0) + +// more hacks +#define LLGST_MESSAGE_TYPE_NAME(M) (llgst_message_type_get_name(GST_MESSAGE_TYPE(M))) + +#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc new file mode 100644 index 0000000000..b33e59363d --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_raw.inc @@ -0,0 +1,51 @@ + +// required symbols to grab +LL_GST_SYM(true, gst_pad_peer_accept_caps, gboolean, GstPad *pad, GstCaps *caps); +LL_GST_SYM(true, gst_buffer_new, GstBuffer*, void); +LL_GST_SYM(true, gst_buffer_set_caps, void, GstBuffer*, GstCaps *); +LL_GST_SYM(true, gst_structure_set_value, void, GstStructure *, const gchar *, const GValue*); +LL_GST_SYM(true, gst_init_check, gboolean, int *argc, char **argv[], GError ** err); +LL_GST_SYM(true, gst_message_get_type, GType, void); +LL_GST_SYM(true, gst_message_type_get_name, const gchar*, GstMessageType type); +LL_GST_SYM(true, gst_message_parse_error, void, GstMessage *message, GError **gerror, gchar **debug); +LL_GST_SYM(true, gst_message_parse_warning, void, GstMessage *message, GError **gerror, gchar **debug); +LL_GST_SYM(true, gst_message_parse_state_changed, void, GstMessage *message, GstState *oldstate, GstState *newstate, GstState *pending); +LL_GST_SYM(true, gst_element_set_state, GstStateChangeReturn, GstElement *element, GstState state); +LL_GST_SYM(true, gst_object_unref, void, gpointer object); +LL_GST_SYM(true, gst_object_get_type, GType, void); +LL_GST_SYM(true, gst_pipeline_get_type, GType, void); +LL_GST_SYM(true, gst_pipeline_get_bus, GstBus*, GstPipeline *pipeline); +LL_GST_SYM(true, gst_bus_add_watch, guint, GstBus * bus, GstBusFunc func, gpointer user_data); +LL_GST_SYM(true, gst_element_factory_make, GstElement*, const gchar *factoryname, const gchar *name); +LL_GST_SYM(true, gst_element_get_type, GType, void); +LL_GST_SYM(true, gst_static_pad_template_get, GstPadTemplate*, GstStaticPadTemplate *pad_template); +LL_GST_SYM(true, gst_element_class_add_pad_template, void, GstElementClass *klass, GstPadTemplate *temp); +LL_GST_SYM(true, gst_element_class_set_details, void, GstElementClass *klass, const GstElementDetails *details); +LL_GST_SYM(true, gst_caps_unref, void, GstCaps* caps); +LL_GST_SYM(true, gst_caps_ref, GstCaps *, GstCaps* caps); +//LL_GST_SYM(true, gst_caps_is_empty, gboolean, const GstCaps *caps); +LL_GST_SYM(true, gst_caps_from_string, GstCaps *, const gchar *string); +LL_GST_SYM(true, gst_caps_replace, void, GstCaps **caps, GstCaps *newcaps); +LL_GST_SYM(true, gst_caps_get_structure, GstStructure *, const GstCaps *caps, guint index); +LL_GST_SYM(true, gst_caps_copy, GstCaps *, const GstCaps * caps); +//LL_GST_SYM(true, gst_caps_intersect, GstCaps *, const GstCaps *caps1, const GstCaps *caps2); +LL_GST_SYM(true, gst_element_register, gboolean, GstPlugin *plugin, const gchar *name, guint rank, GType type); +LL_GST_SYM(true, _gst_plugin_register_static, void, GstPluginDesc *desc); +LL_GST_SYM(true, gst_structure_get_int, gboolean, const GstStructure *structure, const gchar *fieldname, gint *value); +LL_GST_SYM(true, gst_structure_get_value, G_CONST_RETURN GValue *, const GstStructure *structure, const gchar *fieldname); +LL_GST_SYM(true, gst_value_get_fraction_numerator, gint, const GValue *value); +LL_GST_SYM(true, gst_value_get_fraction_denominator, gint, const GValue *value); +LL_GST_SYM(true, gst_structure_get_name, G_CONST_RETURN gchar *, const GstStructure *structure); +LL_GST_SYM(true, gst_element_seek, bool, GstElement *, gdouble, GstFormat, GstSeekFlags, GstSeekType, gint64, GstSeekType, gint64); + +// optional symbols to grab +LL_GST_SYM(false, gst_registry_fork_set_enabled, void, gboolean enabled); +LL_GST_SYM(false, gst_segtrap_set_enabled, void, gboolean enabled); +LL_GST_SYM(false, gst_message_parse_buffering, void, GstMessage *message, gint *percent); +LL_GST_SYM(false, gst_message_parse_info, void, GstMessage *message, GError **gerror, gchar **debug); +LL_GST_SYM(false, gst_element_query_position, gboolean, GstElement *element, GstFormat *format, gint64 *cur); +LL_GST_SYM(false, gst_version, void, guint *major, guint *minor, guint *micro, guint *nano); + +// GStreamer 'internal' symbols which may not be visible in some runtimes but are still used in expanded GStreamer header macros - yuck! We'll substitute our own stubs for these. +//LL_GST_SYM(true, _gst_debug_register_funcptr, void, GstDebugFuncPtr func, gchar* ptrname); +//LL_GST_SYM(true, _gst_debug_category_new, GstDebugCategory *, gchar *name, guint color, gchar *description); diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc new file mode 100644 index 0000000000..14fbcb48b9 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamer_syms_rawv.inc @@ -0,0 +1,5 @@ + +// required symbols to grab +LL_GST_SYM(true, gst_video_sink_get_type, GType, void); + +// optional symbols to grab diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h new file mode 100644 index 0000000000..e31d4a3282 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamertriviallogging.h @@ -0,0 +1,53 @@ +/** + * @file llmediaimplgstreamertriviallogging.h + * @brief minimal logging utilities. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ +#define __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ + +#include + +///////////////////////////////////////////////////////////////////////// +// Debug/Info/Warning macros. +#define MSGMODULEFOO "(media plugin)" +#define STDERRMSG(...) do{\ + fprintf(stderr, MSGMODULEFOO " %s:%d: ", __FUNCTION__, __LINE__);\ + fprintf(stderr, __VA_ARGS__);\ + fputc('\n',stderr);\ + }while(0) +#define NULLMSG(...) do{}while(0) + +#define DEBUGMSG NULLMSG +#define INFOMSG STDERRMSG +#define WARNMSG STDERRMSG +///////////////////////////////////////////////////////////////////////// + +#endif /* __LLMEDIAIMPLGSTREAMERTRIVIALLOGGING_H__ */ diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp new file mode 100644 index 0000000000..d8ccfaa702 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.cpp @@ -0,0 +1,532 @@ +/** + * @file llmediaimplgstreamervidplug.h + * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#if LL_GSTREAMER010_ENABLED + +#include "linden_common.h" + +#include +#include +#include + +#include "llmediaimplgstreamer_syms.h" +#include "llmediaimplgstreamertriviallogging.h" + +#include "llmediaimplgstreamervidplug.h" + + +GST_DEBUG_CATEGORY_STATIC (gst_slvideo_debug); +#define GST_CAT_DEFAULT gst_slvideo_debug + + +#define SLV_SIZECAPS ", width=(int)[1,2048], height=(int)[1,2048] " +#define SLV_ALLCAPS GST_VIDEO_CAPS_RGBx SLV_SIZECAPS + +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (SLV_ALLCAPS) + ); + +GST_BOILERPLATE (GstSLVideo, gst_slvideo, GstVideoSink, + GST_TYPE_VIDEO_SINK); + +static void gst_slvideo_set_property (GObject * object, guint prop_id, + const GValue * value, + GParamSpec * pspec); +static void gst_slvideo_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_slvideo_base_init (gpointer gclass) +{ + static GstElementDetails element_details = { + (gchar*)"PluginTemplate", + (gchar*)"Generic/PluginTemplate", + (gchar*)"Generic Template Element", + (gchar*)"Linden Lab" + }; + GstElementClass *element_class = GST_ELEMENT_CLASS (gclass); + + llgst_element_class_add_pad_template (element_class, + llgst_static_pad_template_get (&sink_factory)); + llgst_element_class_set_details (element_class, &element_details); +} + + +static void +gst_slvideo_finalize (GObject * object) +{ + GstSLVideo *slvideo; + slvideo = GST_SLVIDEO (object); + if (slvideo->caps) + { + llgst_caps_unref(slvideo->caps); + } + + G_OBJECT_CLASS(parent_class)->finalize (object); +} + + +static GstFlowReturn +gst_slvideo_show_frame (GstBaseSink * bsink, GstBuffer * buf) +{ + GstSLVideo *slvideo; + llg_return_val_if_fail (buf != NULL, GST_FLOW_ERROR); + + slvideo = GST_SLVIDEO(bsink); + +#if 0 + fprintf(stderr, "\n\ntransferring a frame of %dx%d <- %p (%d)\n\n", + slvideo->width, slvideo->height, GST_BUFFER_DATA(buf), + slvideo->format); +#endif + if (GST_BUFFER_DATA(buf)) + { + // copy frame and frame info into neutral territory + GST_OBJECT_LOCK(slvideo); + slvideo->retained_frame_ready = TRUE; + slvideo->retained_frame_width = slvideo->width; + slvideo->retained_frame_height = slvideo->height; + slvideo->retained_frame_format = slvideo->format; + int rowbytes = + SLVPixelFormatBytes[slvideo->retained_frame_format] * + slvideo->retained_frame_width; + int needbytes = rowbytes * slvideo->retained_frame_width; + // resize retained frame hunk only if necessary + if (needbytes != slvideo->retained_frame_allocbytes) + { + delete[] slvideo->retained_frame_data; + slvideo->retained_frame_data = new unsigned char[needbytes]; + slvideo->retained_frame_allocbytes = needbytes; + + } + // copy the actual frame data to neutral territory - + // flipped, for GL reasons + for (int ypos=0; yposheight; ++ypos) + { + memcpy(&slvideo->retained_frame_data[(slvideo->height-1-ypos)*rowbytes], + &(((unsigned char*)GST_BUFFER_DATA(buf))[ypos*rowbytes]), + rowbytes); + } + // done with the shared data + GST_OBJECT_UNLOCK(slvideo); + } + + return GST_FLOW_OK; +} + + +static GstStateChangeReturn +gst_slvideo_change_state(GstElement * element, GstStateChange transition) +{ + GstSLVideo *slvideo; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + slvideo = GST_SLVIDEO (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + slvideo->fps_n = 0; + slvideo->fps_d = 1; + GST_VIDEO_SINK_WIDTH(slvideo) = 0; + GST_VIDEO_SINK_HEIGHT(slvideo) = 0; + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} + + +static GstCaps * +gst_slvideo_get_caps (GstBaseSink * bsink) +{ + GstSLVideo *slvideo; + slvideo = GST_SLVIDEO(bsink); + + return llgst_caps_ref (slvideo->caps); +} + + +/* this function handles the link with other elements */ +static gboolean +gst_slvideo_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstSLVideo *filter; + GstStructure *structure; + + GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps); + + filter = GST_SLVIDEO(bsink); + + int width, height; + gboolean ret; + const GValue *fps; + const GValue *par; + structure = llgst_caps_get_structure (caps, 0); + ret = llgst_structure_get_int (structure, "width", &width); + ret = ret && llgst_structure_get_int (structure, "height", &height); + fps = llgst_structure_get_value (structure, "framerate"); + ret = ret && (fps != NULL); + par = llgst_structure_get_value (structure, "pixel-aspect-ratio"); + if (!ret) + return FALSE; + + INFOMSG("** filter caps set with width=%d, height=%d", width, height); + + GST_OBJECT_LOCK(filter); + + filter->width = width; + filter->height = height; + + filter->fps_n = llgst_value_get_fraction_numerator(fps); + filter->fps_d = llgst_value_get_fraction_denominator(fps); + if (par) + { + filter->par_n = llgst_value_get_fraction_numerator(par); + filter->par_d = llgst_value_get_fraction_denominator(par); + } + else + { + filter->par_n = 1; + filter->par_d = 1; + } + GST_VIDEO_SINK_WIDTH(filter) = width; + GST_VIDEO_SINK_HEIGHT(filter) = height; + + // crufty lump - we *always* accept *only* RGBX now. + /* + filter->format = SLV_PF_UNKNOWN; + if (0 == strcmp(llgst_structure_get_name(structure), + "video/x-raw-rgb")) + { + int red_mask; + int green_mask; + int blue_mask; + llgst_structure_get_int(structure, "red_mask", &red_mask); + llgst_structure_get_int(structure, "green_mask", &green_mask); + llgst_structure_get_int(structure, "blue_mask", &blue_mask); + if ((unsigned int)red_mask == 0xFF000000 && + (unsigned int)green_mask == 0x00FF0000 && + (unsigned int)blue_mask == 0x0000FF00) + { + filter->format = SLV_PF_RGBX; + //fprintf(stderr, "\n\nPIXEL FORMAT RGB\n\n"); + } else if ((unsigned int)red_mask == 0x0000FF00 && + (unsigned int)green_mask == 0x00FF0000 && + (unsigned int)blue_mask == 0xFF000000) + { + filter->format = SLV_PF_BGRX; + //fprintf(stderr, "\n\nPIXEL FORMAT BGR\n\n"); + } + }*/ + + filter->format = SLV_PF_RGBX; + + GST_OBJECT_UNLOCK(filter); + + return TRUE; +} + + +static gboolean +gst_slvideo_start (GstBaseSink * bsink) +{ + GstSLVideo *slvideo; + gboolean ret = TRUE; + + slvideo = GST_SLVIDEO(bsink); + + return ret; +} + +static gboolean +gst_slvideo_stop (GstBaseSink * bsink) +{ + GstSLVideo *slvideo; + slvideo = GST_SLVIDEO(bsink); + + // free-up retained frame buffer + GST_OBJECT_LOCK(slvideo); + slvideo->retained_frame_ready = FALSE; + delete[] slvideo->retained_frame_data; + slvideo->retained_frame_data = NULL; + slvideo->retained_frame_allocbytes = 0; + GST_OBJECT_UNLOCK(slvideo); + + return TRUE; +} + + +static GstFlowReturn +gst_slvideo_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size, + GstCaps * caps, GstBuffer ** buf) +{ + gint width, height; + GstStructure *structure = NULL; + GstSLVideo *slvideo; + slvideo = GST_SLVIDEO(bsink); + + // caps == requested caps + // we can ignore these and reverse-negotiate our preferred dimensions with + // the peer if we like - we need to do this to obey dynamic resize requests + // flowing in from the app. + structure = llgst_caps_get_structure (caps, 0); + if (!llgst_structure_get_int(structure, "width", &width) || + !llgst_structure_get_int(structure, "height", &height)) + { + GST_WARNING_OBJECT (slvideo, "no width/height in caps %" GST_PTR_FORMAT, caps); + return GST_FLOW_NOT_NEGOTIATED; + } + + GstBuffer *newbuf = llgst_buffer_new(); + bool made_bufferdata_ptr = false; +#define MAXDEPTHHACK 4 + + GST_OBJECT_LOCK(slvideo); + if (slvideo->resize_forced) + { + gint slwantwidth, slwantheight; + slwantwidth = slvideo->resize_try_width; + slwantheight = slvideo->resize_try_height; + + if (slwantwidth != width || + slwantheight != height) + { + // don't like requested caps, we will issue our own suggestion - copy + // the requested caps but substitute our own width and height and see + // if our peer is happy with that. + + GstCaps *desired_caps; + GstStructure *desired_struct; + desired_caps = llgst_caps_copy (caps); + desired_struct = llgst_caps_get_structure (desired_caps, 0); + + GValue value = {0}; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, slwantwidth); + llgst_structure_set_value (desired_struct, "width", &value); + g_value_unset(&value); + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, slwantheight); + llgst_structure_set_value (desired_struct, "height", &value); + + if (llgst_pad_peer_accept_caps (GST_VIDEO_SINK_PAD (slvideo), + desired_caps)) + { + // todo: re-use buffers from a pool? + // todo: set MALLOCDATA to null, set DATA to point straight to shm? + + // peer likes our cap suggestion + DEBUGMSG("peer loves us :)"); + GST_BUFFER_SIZE(newbuf) = slwantwidth * slwantheight * MAXDEPTHHACK; + GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); + GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); + llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), desired_caps); + + made_bufferdata_ptr = true; + } else { + // peer hates our cap suggestion + INFOMSG("peer hates us :("); + llgst_caps_unref(desired_caps); + } + } + } + + if (!made_bufferdata_ptr) // need to fallback to malloc at original size + { + GST_BUFFER_SIZE(newbuf) = width * height * MAXDEPTHHACK; + GST_BUFFER_MALLOCDATA(newbuf) = (guint8*)g_malloc(GST_BUFFER_SIZE(newbuf)); + GST_BUFFER_DATA(newbuf) = GST_BUFFER_MALLOCDATA(newbuf); + llgst_buffer_set_caps (GST_BUFFER_CAST(newbuf), caps); + } + + GST_OBJECT_UNLOCK(slvideo); + + *buf = GST_BUFFER_CAST(newbuf); + + return GST_FLOW_OK; +} + + +/* initialize the plugin's class */ +static void +gst_slvideo_class_init (GstSLVideoClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + + gobject_class->finalize = gst_slvideo_finalize; + gobject_class->set_property = gst_slvideo_set_property; + gobject_class->get_property = gst_slvideo_get_property; + + gstelement_class->change_state = gst_slvideo_change_state; + +#define LLGST_DEBUG_FUNCPTR(p) (p) + gstbasesink_class->get_caps = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_caps); + gstbasesink_class->set_caps = LLGST_DEBUG_FUNCPTR( gst_slvideo_set_caps); + gstbasesink_class->buffer_alloc=LLGST_DEBUG_FUNCPTR(gst_slvideo_buffer_alloc); + //gstbasesink_class->get_times = LLGST_DEBUG_FUNCPTR (gst_slvideo_get_times); + gstbasesink_class->preroll = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); + gstbasesink_class->render = LLGST_DEBUG_FUNCPTR (gst_slvideo_show_frame); + + gstbasesink_class->start = LLGST_DEBUG_FUNCPTR (gst_slvideo_start); + gstbasesink_class->stop = LLGST_DEBUG_FUNCPTR (gst_slvideo_stop); + + // gstbasesink_class->unlock = LLGST_DEBUG_FUNCPTR (gst_slvideo_unlock); +#undef LLGST_DEBUG_FUNCPTR +} + + +/* initialize the new element + * instantiate pads and add them to element + * set functions + * initialize structure + */ +static void +gst_slvideo_init (GstSLVideo * filter, + GstSLVideoClass * gclass) +{ + filter->caps = NULL; + filter->width = -1; + filter->height = -1; + + // this is the info we share with the client app + GST_OBJECT_LOCK(filter); + filter->retained_frame_ready = FALSE; + filter->retained_frame_data = NULL; + filter->retained_frame_allocbytes = 0; + filter->retained_frame_width = filter->width; + filter->retained_frame_height = filter->height; + filter->retained_frame_format = SLV_PF_UNKNOWN; + GstCaps *caps = llgst_caps_from_string (SLV_ALLCAPS); + llgst_caps_replace (&filter->caps, caps); + filter->resize_forced = false; + filter->resize_try_width = -1; + filter->resize_try_height = -1; + GST_OBJECT_UNLOCK(filter); +} + +static void +gst_slvideo_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + llg_return_if_fail (GST_IS_SLVIDEO (object)); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_slvideo_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + llg_return_if_fail (GST_IS_SLVIDEO (object)); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +/* entry point to initialize the plug-in + * initialize the plug-in itself + * register the element factories and pad templates + * register the features + */ +static gboolean +plugin_init (GstPlugin * plugin) +{ + DEBUGMSG("\n\n\nPLUGIN INIT\n\n\n"); + + GST_DEBUG_CATEGORY_INIT (gst_slvideo_debug, (gchar*)"private-slvideo-plugin", + 0, (gchar*)"Second Life Video Sink"); + + return llgst_element_register (plugin, "private-slvideo", + GST_RANK_NONE, GST_TYPE_SLVIDEO); +} + +/* this is the structure that gstreamer looks for to register plugins + */ +/* NOTE: Can't rely upon GST_PLUGIN_DEFINE_STATIC to self-register, since + some g++ versions buggily avoid __attribute__((constructor)) functions - + so we provide an explicit plugin init function. + */ +void gst_slvideo_init_class (void) +{ +#define PACKAGE "packagehack" + // this macro quietly refers to PACKAGE internally + static GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "private-slvideoplugin", + "SL Video sink plugin", + plugin_init, "0.1", GST_LICENSE_UNKNOWN, + "Second Life", + "http://www.secondlife.com/"); +#undef PACKAGE + ll_gst_plugin_register_static (&gst_plugin_desc); + DEBUGMSG(stderr, "\n\n\nCLASS INIT\n\n\n"); +} + +#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h new file mode 100644 index 0000000000..f6d55b8758 --- /dev/null +++ b/indra/media_plugins/gstreamer010/llmediaimplgstreamervidplug.h @@ -0,0 +1,109 @@ +/** + * @file llmediaimplgstreamervidplug.h + * @brief Video-consuming static GStreamer plugin for gst-to-LLMediaImpl + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef __GST_SLVIDEO_H__ +#define __GST_SLVIDEO_H__ + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +#include +#include +} + +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_SLVIDEO \ + (gst_slvideo_get_type()) +#define GST_SLVIDEO(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SLVIDEO,GstSLVideo)) +#define GST_SLVIDEO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SLVIDEO,GstSLVideoClass)) +#define GST_IS_SLVIDEO(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SLVIDEO)) +#define GST_IS_SLVIDEO_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SLVIDEO)) + +typedef struct _GstSLVideo GstSLVideo; +typedef struct _GstSLVideoClass GstSLVideoClass; + +typedef enum { + SLV_PF_UNKNOWN = 0, + SLV_PF_RGBX = 1, + SLV_PF_BGRX = 2, + SLV__END = 3 +} SLVPixelFormat; +const int SLVPixelFormatBytes[SLV__END] = {1, 4, 4}; + +struct _GstSLVideo +{ + GstVideoSink video_sink; + + GstCaps *caps; + + int fps_n, fps_d; + int par_n, par_d; + int height, width; + SLVPixelFormat format; + + // SHARED WITH APPLICATION: + // Access to the following should be protected by GST_OBJECT_LOCK() on + // the GstSLVideo object, and should be totally consistent upon UNLOCK + // (i.e. all written at once to reflect the current retained frame info + // when the retained frame is updated.) + bool retained_frame_ready; // new frame ready since flag last reset. (*TODO: could get the writer to wait on a semaphore instead of having the reader poll, potentially making dropped frames somewhat cheaper.) + unsigned char* retained_frame_data; + int retained_frame_allocbytes; + int retained_frame_width, retained_frame_height; + SLVPixelFormat retained_frame_format; + // sticky resize info + bool resize_forced; + int resize_try_width; + int resize_try_height; +}; + +struct _GstSLVideoClass +{ + GstVideoSinkClass parent_class; +}; + +GType gst_slvideo_get_type (void); + +void gst_slvideo_init_class (void); + +G_END_DECLS + +#endif // LL_GSTREAMER010_ENABLED + +#endif /* __GST_SLVIDEO_H__ */ diff --git a/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp new file mode 100644 index 0000000000..647db7a5bf --- /dev/null +++ b/indra/media_plugins/gstreamer010/media_plugin_gstreamer010.cpp @@ -0,0 +1,1204 @@ +/** + * @file media_plugin_gstreamer010.cpp + * @brief GStreamer-0.10 plugin for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_GSTREAMER010_ENABLED + +extern "C" { +#include +} + +#include "llmediaimplgstreamer.h" +#include "llmediaimplgstreamertriviallogging.h" + +#include "llmediaimplgstreamervidplug.h" + +#include "llmediaimplgstreamer_syms.h" + +////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginGStreamer010 : public MediaPluginBase +{ +public: + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer010(); + + /* virtual */ void receiveMessage(const char *message_string); + + static bool startup(); + static bool closedown(); + + gboolean processGSTEvents(GstBus *bus, + GstMessage *message); + +private: + std::string getVersion(); + bool navigateTo( const std::string urlIn ); + bool seek( double time_sec ); + bool setVolume( float volume ); + + // misc + bool pause(); + bool stop(); + bool play(double rate); + bool getTimePos(double &sec_out); + + static const double MIN_LOOP_SEC = 1.0F; + + bool mIsLooping; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + +private: + bool unload(); + bool load(); + + bool update(int milliseconds); + void mouseDown( int x, int y ); + void mouseUp( int x, int y ); + void mouseMove( int x, int y ); + + bool sizeChanged(); + + static bool mDoneInit; + + guint mBusWatchID; + + float mVolume; + + int mDepth; + + // media natural size + int mNaturalWidth; + int mNaturalHeight; + int mNaturalRowbytes; + // previous media natural size so we can detect changes + int mPreviousNaturalWidth; + int mPreviousNaturalHeight; + // desired render size from host + int mWidth; + int mHeight; + // padded texture size we need to write into + int mTextureWidth; + int mTextureHeight; + + int mTextureFormatPrimary; + int mTextureFormatType; + + bool mSeekWanted; + double mSeekDestination; + + // Very GStreamer-specific + GMainLoop *mPump; // event pump for this media + GstElement *mPlaybin; + GstSLVideo *mVideoSink; +}; + +//static +bool MediaPluginGStreamer010::mDoneInit = false; + +MediaPluginGStreamer010::MediaPluginGStreamer010( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data), + mBusWatchID ( 0 ), + mNaturalRowbytes ( 4 ), + mTextureFormatPrimary ( GL_RGBA ), + mTextureFormatType ( GL_UNSIGNED_INT_8_8_8_8_REV ), + mSeekWanted(false), + mSeekDestination(0.0), + mPump ( NULL ), + mPlaybin ( NULL ), + mVideoSink ( NULL ), + mCommand ( COMMAND_NONE ) +{ + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010 constructor - my PID=%u", U32(getpid())); +} + +/////////////////////////////////////////////////////////////////////////////// +// +//#define LL_GST_REPORT_STATE_CHANGES +#ifdef LL_GST_REPORT_STATE_CHANGES +static char* get_gst_state_name(GstState state) +{ + switch (state) { + case GST_STATE_VOID_PENDING: return "VOID_PENDING"; + case GST_STATE_NULL: return "NULL"; + case GST_STATE_READY: return "READY"; + case GST_STATE_PAUSED: return "PAUSED"; + case GST_STATE_PLAYING: return "PLAYING"; + } + return "(unknown)"; +} +#endif // LL_GST_REPORT_STATE_CHANGES + +gboolean +MediaPluginGStreamer010::processGSTEvents(GstBus *bus, + GstMessage *message) +{ + if (!message) + return TRUE; // shield against GStreamer bug + + if (GST_MESSAGE_TYPE(message) != GST_MESSAGE_STATE_CHANGED && + GST_MESSAGE_TYPE(message) != GST_MESSAGE_BUFFERING) + { + DEBUGMSG("Got GST message type: %s", + LLGST_MESSAGE_TYPE_NAME (message)); + } + else + { + DEBUGMSG("Got GST message type: %s", + LLGST_MESSAGE_TYPE_NAME (message)); + } + + switch (GST_MESSAGE_TYPE (message)) { + case GST_MESSAGE_BUFFERING: { + // NEEDS GST 0.10.11+ + if (llgst_message_parse_buffering) + { + gint percent = 0; + llgst_message_parse_buffering(message, &percent); + DEBUGMSG("GST buffering: %d%%", percent); + } + break; + } + case GST_MESSAGE_STATE_CHANGED: { + GstState old_state; + GstState new_state; + GstState pending_state; + llgst_message_parse_state_changed(message, + &old_state, + &new_state, + &pending_state); +#ifdef LL_GST_REPORT_STATE_CHANGES + // not generally very useful, and rather spammy. + DEBUGMSG("state change (old,,pending): %s,<%s>,%s", + get_gst_state_name(old_state), + get_gst_state_name(new_state), + get_gst_state_name(pending_state)); +#endif // LL_GST_REPORT_STATE_CHANGES + + switch (new_state) { + case GST_STATE_VOID_PENDING: + break; + case GST_STATE_NULL: + break; + case GST_STATE_READY: + setStatus(STATUS_LOADED); + break; + case GST_STATE_PAUSED: + setStatus(STATUS_PAUSED); + break; + case GST_STATE_PLAYING: + setStatus(STATUS_PLAYING); + break; + } + break; + } + case GST_MESSAGE_ERROR: { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_error (message, &err, &debug); + WARNMSG("GST error: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + mCommand = COMMAND_STOP; + + setStatus(STATUS_ERROR); + + break; + } + case GST_MESSAGE_INFO: { + if (llgst_message_parse_info) + { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_info (message, &err, &debug); + INFOMSG("GST info: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + } + break; + } + case GST_MESSAGE_WARNING: { + GError *err = NULL; + gchar *debug = NULL; + + llgst_message_parse_warning (message, &err, &debug); + WARNMSG("GST warning: %s", err?err->message:"(unknown)"); + if (err) + g_error_free (err); + g_free (debug); + + break; + } + case GST_MESSAGE_EOS: + /* end-of-stream */ + DEBUGMSG("GST end-of-stream."); + if (mIsLooping) + { + DEBUGMSG("looping media..."); + double eos_pos_sec = 0.0F; + bool got_eos_position = getTimePos(eos_pos_sec); + + if (got_eos_position && eos_pos_sec < MIN_LOOP_SEC) + { + // if we know that the movie is really short, don't + // loop it else it can easily become a time-hog + // because of GStreamer spin-up overhead + DEBUGMSG("really short movie (%0.3fsec) - not gonna loop this, pausing instead.", eos_pos_sec); + // inject a COMMAND_PAUSE + mCommand = COMMAND_PAUSE; + } + else + { +#undef LLGST_LOOP_BY_SEEKING +// loop with a stop-start instead of a seek, because it actually seems rather +// faster than seeking on remote streams. +#ifdef LLGST_LOOP_BY_SEEKING + // first, try looping by an explicit rewind + bool seeksuccess = seek(0.0); + if (seeksuccess) + { + play(1.0); + } + else +#endif // LLGST_LOOP_BY_SEEKING + { // use clumsy stop-start to loop + DEBUGMSG("didn't loop by rewinding - stopping and starting instead..."); + stop(); + play(1.0); + } + } + } + else // not a looping media + { + // inject a COMMAND_STOP + mCommand = COMMAND_STOP; + } + break; + default: + /* unhandled message */ + break; + } + + /* we want to be notified again the next time there is a message + * on the bus, so return true (false means we want to stop watching + * for messages on the bus and our callback should not be called again) + */ + return TRUE; +} + +extern "C" { +gboolean +llmediaimplgstreamer_bus_callback (GstBus *bus, + GstMessage *message, + gpointer data) +{ + MediaPluginGStreamer010 *impl = (MediaPluginGStreamer010*)data; + return impl->processGSTEvents(bus, message); +} +} // extern "C" + + + +bool +MediaPluginGStreamer010::navigateTo ( const std::string urlIn ) +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + DEBUGMSG("Setting media URI: %s", urlIn.c_str()); + + mSeekWanted = false; + + if (NULL == mPump || + NULL == mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // set URI + g_object_set (G_OBJECT (mPlaybin), "uri", urlIn.c_str(), NULL); + //g_object_set (G_OBJECT (mPlaybin), "uri", "file:///tmp/movie", NULL); + + // navigateTo implicitly plays, too. + play(1.0); + + return true; +} + + +bool +MediaPluginGStreamer010::update(int milliseconds) +{ + if (!mDoneInit) + return false; // error + + DEBUGMSG("updating media..."); + + // sanity check + if (NULL == mPump || + NULL == mPlaybin) + { + DEBUGMSG("dead media..."); + return false; + } + + // see if there's an outstanding seek wanted + if (mSeekWanted && + // bleh, GST has to be happy that the movie is really truly playing + // or it may quietly ignore the seek (with rtsp:// at least). + (GST_STATE(mPlaybin) == GST_STATE_PLAYING)) + { + seek(mSeekDestination); + mSeekWanted = false; + } + + // *TODO: time-limit - but there isn't a lot we can do here, most + // time is spent in gstreamer's own opaque worker-threads. maybe + // we can do something sneaky like only unlock the video object + // for 'milliseconds' and otherwise hold the lock. + while (g_main_context_pending(g_main_loop_get_context(mPump))) + { + g_main_context_iteration(g_main_loop_get_context(mPump), FALSE); + } + + // check for availability of a new frame + + if (mVideoSink) + { + GST_OBJECT_LOCK(mVideoSink); + if (mVideoSink->retained_frame_ready) + { + DEBUGMSG("NEW FRAME READY"); + + if (mVideoSink->retained_frame_width != mNaturalWidth || + mVideoSink->retained_frame_height != mNaturalHeight) + // *TODO: also check for change in format + { + // just resize container, don't consume frame + int neww = mVideoSink->retained_frame_width; + int newh = mVideoSink->retained_frame_height; + + int newd = 4; + mTextureFormatPrimary = GL_RGBA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + + /* + int newd = SLVPixelFormatBytes[mVideoSink->retained_frame_format]; + if (SLV_PF_BGRX == mVideoSink->retained_frame_format) + { + mTextureFormatPrimary = GL_BGRA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + } + else + { + mTextureFormatPrimary = GL_RGBA; + mTextureFormatType = GL_UNSIGNED_INT_8_8_8_8_REV; + } + */ + + GST_OBJECT_UNLOCK(mVideoSink); + + mNaturalRowbytes = neww * newd; + DEBUGMSG("video container resized to %dx%d", + neww, newh); + + mDepth = newd; + mNaturalWidth = neww; + mNaturalHeight = newh; + sizeChanged(); + return true; + } + + if (mPixels && + mNaturalHeight <= mHeight && + mNaturalWidth <= mWidth && + !mTextureSegmentName.empty()) + { + + // we're gonna totally consume this frame - reset 'ready' flag + mVideoSink->retained_frame_ready = FALSE; + int destination_rowbytes = mWidth * mDepth; + for (int row=0; rowretained_frame_data + [mNaturalRowbytes * row], + mNaturalRowbytes); + } + + GST_OBJECT_UNLOCK(mVideoSink); + DEBUGMSG("NEW FRAME REALLY TRULY CONSUMED, TELLING HOST"); + + setDirty(0,0,mNaturalWidth,mNaturalHeight); + } + else + { + // new frame ready, but we're not ready to + // consume it. + + GST_OBJECT_UNLOCK(mVideoSink); + + DEBUGMSG("NEW FRAME not consumed, still waiting for a shm segment and/or shm resize"); + } + + return true; + } + else + { + // nothing to do yet. + GST_OBJECT_UNLOCK(mVideoSink); + return true; + } + } + + return true; +} + + +void +MediaPluginGStreamer010::mouseDown( int x, int y ) +{ + // do nothing +} + +void +MediaPluginGStreamer010::mouseUp( int x, int y ) +{ + // do nothing +} + +void +MediaPluginGStreamer010::mouseMove( int x, int y ) +{ + // do nothing +} + + +bool +MediaPluginGStreamer010::pause() +{ + DEBUGMSG("pausing media..."); + // todo: error-check this? + llgst_element_set_state(mPlaybin, GST_STATE_PAUSED); + return true; +} + +bool +MediaPluginGStreamer010::stop() +{ + DEBUGMSG("stopping media..."); + // todo: error-check this? + llgst_element_set_state(mPlaybin, GST_STATE_READY); + return true; +} + +bool +MediaPluginGStreamer010::play(double rate) +{ + // NOTE: we don't actually support non-natural rate. + + DEBUGMSG("playing media... rate=%f", rate); + // todo: error-check this? + llgst_element_set_state(mPlaybin, GST_STATE_PLAYING); + return true; +} + +bool +MediaPluginGStreamer010::setVolume( float volume ) +{ + // we try to only update volume as conservatively as + // possible, as many gst-plugins-base versions up to at least + // November 2008 have critical race-conditions in setting volume - sigh + if (mVolume == volume) + return true; // nothing to do, everything's fine + + mVolume = volume; + if (mDoneInit && mPlaybin) + { + g_object_set(mPlaybin, "volume", mVolume, NULL); + return true; + } + + return false; +} + +bool +MediaPluginGStreamer010::seek(double time_sec) +{ + bool success = false; + if (mDoneInit && mPlaybin) + { + success = llgst_element_seek(mPlaybin, 1.0F, GST_FORMAT_TIME, + GstSeekFlags(GST_SEEK_FLAG_FLUSH | + GST_SEEK_FLAG_KEY_UNIT), + GST_SEEK_TYPE_SET, gint64(time_sec*GST_SECOND), + GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE); + } + DEBUGMSG("MEDIA SEEK REQUEST to %fsec result was %d", + float(time_sec), int(success)); + return success; +} + +bool +MediaPluginGStreamer010::getTimePos(double &sec_out) +{ + bool got_position = false; + if (mPlaybin) + { + gint64 pos; + GstFormat timefmt = GST_FORMAT_TIME; + got_position = + llgst_element_query_position && + llgst_element_query_position(mPlaybin, + &timefmt, + &pos); + got_position = got_position + && (timefmt == GST_FORMAT_TIME); + // GStreamer may have other ideas, but we consider the current position + // undefined if not PLAYING or PAUSED + got_position = got_position && + (GST_STATE(mPlaybin) == GST_STATE_PLAYING || + GST_STATE(mPlaybin) == GST_STATE_PAUSED); + if (got_position && !GST_CLOCK_TIME_IS_VALID(pos)) + { + if (GST_STATE(mPlaybin) == GST_STATE_PLAYING) + { + // if we're playing then we treat an invalid clock time + // as 0, for complicated reasons (insert reason here) + pos = 0; + } + else + { + got_position = false; + } + + } + // If all the preconditions succeeded... we can trust the result. + if (got_position) + { + sec_out = double(pos) / double(GST_SECOND); // gst to sec + } + } + return got_position; +} + +bool +MediaPluginGStreamer010::load() +{ + if (!mDoneInit) + return false; // error + + setStatus(STATUS_LOADING); + + DEBUGMSG("setting up media..."); + + mIsLooping = false; + mVolume = 0.1234567; // minor hack to force an initial volume update + + // Create a pumpable main-loop for this media + mPump = g_main_loop_new (NULL, FALSE); + if (!mPump) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // instantiate a playbin element to do the hard work + mPlaybin = llgst_element_factory_make ("playbin", "play"); + if (!mPlaybin) + { + setStatus(STATUS_ERROR); + return false; // error + } + + // get playbin's bus + GstBus *bus = llgst_pipeline_get_bus (GST_PIPELINE (mPlaybin)); + if (!bus) + { + setStatus(STATUS_ERROR); + return false; // error + } + mBusWatchID = llgst_bus_add_watch (bus, + llmediaimplgstreamer_bus_callback, + this); + llgst_object_unref (bus); + + if (NULL == getenv("LL_GSTREAMER_EXTERNAL")) { + // instantiate a custom video sink + mVideoSink = + GST_SLVIDEO(llgst_element_factory_make ("private-slvideo", "slvideo")); + if (!mVideoSink) + { + WARNMSG("Could not instantiate private-slvideo element."); + // todo: cleanup. + setStatus(STATUS_ERROR); + return false; // error + } + + // connect the pieces + g_object_set(mPlaybin, "video-sink", mVideoSink, NULL); + } + + return true; +} + +bool +MediaPluginGStreamer010::unload () +{ + if (!mDoneInit) + return false; // error + + DEBUGMSG("unloading media..."); + + // stop getting callbacks for this bus + g_source_remove(mBusWatchID); + mBusWatchID = 0; + + if (mPlaybin) + { + llgst_element_set_state (mPlaybin, GST_STATE_NULL); + llgst_object_unref (GST_OBJECT (mPlaybin)); + mPlaybin = NULL; + } + + if (mPump) + { + g_main_loop_quit(mPump); + mPump = NULL; + } + + mVideoSink = NULL; + + setStatus(STATUS_NONE); + + return true; +} + + +//static +bool +MediaPluginGStreamer010::startup() +{ + // first - check if GStreamer is explicitly disabled + if (NULL != getenv("LL_DISABLE_GSTREAMER")) + return false; + + // only do global GStreamer initialization once. + if (!mDoneInit) + { + g_thread_init(NULL); + + // Init the glib type system - we need it. + g_type_init(); + + // Get symbols! +#if LL_DARWIN + if (! grab_gst_syms("libgstreamer-0.10.dylib", + "libgstvideo-0.10.dylib") ) +#elseif LL_WINDOWS + if (! grab_gst_syms("libgstreamer-0.10.dll", + "libgstvideo-0.10.dll") ) +#else // linux or other ELFy unixoid + if (! grab_gst_syms("libgstreamer-0.10.so.0", + "libgstvideo-0.10.so.0") ) +#endif + { + WARNMSG("Couldn't find suitable GStreamer 0.10 support on this system - video playback disabled."); + return false; + } + + if (llgst_segtrap_set_enabled) + { + llgst_segtrap_set_enabled(FALSE); + } + else + { + WARNMSG("gst_segtrap_set_enabled() is not available; plugin crashes won't be caught."); + } + +#if LL_LINUX + // Gstreamer tries a fork during init, waitpid-ing on it, + // which conflicts with any installed SIGCHLD handler... + struct sigaction tmpact, oldact; + if (llgst_registry_fork_set_enabled) { + // if we can disable SIGCHLD-using forking behaviour, + // do it. + llgst_registry_fork_set_enabled(false); + } + else { + // else temporarily install default SIGCHLD handler + // while GStreamer initialises + tmpact.sa_handler = SIG_DFL; + sigemptyset( &tmpact.sa_mask ); + tmpact.sa_flags = SA_SIGINFO; + sigaction(SIGCHLD, &tmpact, &oldact); + } +#endif // LL_LINUX + + // Protect against GStreamer resetting the locale, yuck. + static std::string saved_locale; + saved_locale = setlocale(LC_ALL, NULL); + + // finally, try to initialize GStreamer! + GError *err = NULL; + gboolean init_gst_success = llgst_init_check(NULL, NULL, &err); + + // restore old locale + setlocale(LC_ALL, saved_locale.c_str() ); + +#if LL_LINUX + // restore old SIGCHLD handler + if (!llgst_registry_fork_set_enabled) + sigaction(SIGCHLD, &oldact, NULL); +#endif // LL_LINUX + + if (!init_gst_success) // fail + { + if (err) + { + WARNMSG("GST init failed: %s", err->message); + g_error_free(err); + } + else + { + WARNMSG("GST init failed for unspecified reason."); + } + return false; + } + + // Init our custom plugins - only really need do this once. + gst_slvideo_init_class(); + + mDoneInit = true; + } + + return true; +} + + +bool +MediaPluginGStreamer010::sizeChanged() +{ + // the shared writing space has possibly changed size/location/whatever + + // Check to see whether the movie's natural size has updated + if (mNaturalWidth != mPreviousNaturalWidth || + mNaturalHeight != mPreviousNaturalHeight) + { + mPreviousNaturalWidth = mNaturalWidth; + mPreviousNaturalHeight = mNaturalHeight; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", mNaturalWidth); + message.setValueS32("height", mNaturalHeight); + DEBUGMSG("<--- Sending size change request to application with name: '%s' - size is %d x %d", mTextureSegmentName.c_str(), mNaturalWidth, mNaturalHeight); + sendMessage(message); + } + + return true; +} + + + +//static +bool +MediaPluginGStreamer010::closedown() +{ + if (!mDoneInit) + return false; // error + + ungrab_gst_syms(); + + mDoneInit = false; + + return true; +} + +MediaPluginGStreamer010::~MediaPluginGStreamer010() +{ + DEBUGMSG("MediaPluginGStreamer010 destructor"); + + closedown(); + + DEBUGMSG("GStreamer010 closing down"); +} + + +std::string +MediaPluginGStreamer010::getVersion() +{ + std::string plugin_version = "GStreamer010 media plugin, GStreamer version "; + if (mDoneInit && + llgst_version) + { + guint major, minor, micro, nano; + llgst_version(&major, &minor, µ, &nano); + plugin_version += llformat("%u.%u.%u.%u (runtime), %u.%u.%u.%u (headers)", (unsigned int)major, (unsigned int)minor, (unsigned int)micro, (unsigned int)nano, (unsigned int)GST_VERSION_MAJOR, (unsigned int)GST_VERSION_MINOR, (unsigned int)GST_VERSION_MICRO, (unsigned int)GST_VERSION_NANO); + } + else + { + plugin_version += "(unknown)"; + } + return plugin_version; +} + +void MediaPluginGStreamer010::receiveMessage(const char *message_string) +{ + //std::cerr << "MediaPluginGStreamer010::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + if ( load() ) + { + DEBUGMSG("GStreamer010 media instance set up"); + } + else + { + WARNMSG("GStreamer010 media instance failed to set up"); + } + + message.setValue("plugin_version", getVersion()); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + // lame to have to decide this now, it depends on the movie. Oh well. + mDepth = 4; + + mNaturalWidth = 1; + mNaturalHeight = 1; + mPreviousNaturalWidth = 1; + mPreviousNaturalHeight = 1; + mWidth = 1; + mHeight = 1; + mTextureWidth = 1; + mTextureHeight = 1; + + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV); + + message.setValueS32("depth", mDepth); + message.setValueS32("default_width", mWidth); + message.setValueS32("default_height", mHeight); + message.setValueU32("internalformat", GL_RGBA8); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); // we respond with grace and performance if asked to downscale + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + double time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + unload(); + closedown(); + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + U64 address_lo = message_in.getValueU32("address"); + U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; + info.mAddress = (void*)((address_lo) | + (address_hi * (U64(1)<<31))); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010::receiveMessage: shared memory added, name: %s, size: %d, address: %p", name.c_str(), int(info.mSize), info.mAddress); + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + + DEBUGMSG("MediaPluginGStreamer010::receiveMessage: shared memory remove, name = %s", name.c_str()); + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + + // Make sure the movie decoder is no longer pointed at the shared segment. + sizeChanged(); + } + mSharedSegments.erase(iter); + } + else + { + WARNMSG("MediaPluginGStreamer010::receiveMessage: unknown shared memory region!"); + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { + std::ostringstream str; + INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown base message: %s", message_name.c_str()); + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + std::ostringstream str; + INFOMSG("---->Got size change instruction from application with shm name: %s - size is %d x %d", name.c_str(), width, height); + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + INFOMSG("*** Got size change with matching shm, new size is %d x %d", width, height); + INFOMSG("*** Got size change with matching shm, texture size size is %d x %d", texture_width, texture_height); + + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + mWidth = width; + mHeight = height; + + if (texture_width > 1 || + texture_height > 1) // not a dummy size from the app, a real explicit forced size + { + INFOMSG("**** = REAL RESIZE REQUEST FROM APP"); + + GST_OBJECT_LOCK(mVideoSink); + mVideoSink->resize_forced = true; + mVideoSink->resize_try_width = texture_width; + mVideoSink->resize_try_height = texture_height; + GST_OBJECT_UNLOCK(mVideoSink); + } + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + } + } + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + navigateTo( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + double rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + // NOTE: we don't actually support rate. + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + double time = message_in.getValueReal("time"); + // defer the actual seek in case we haven't + // really truly started yet in which case there + // is nothing to seek upon + mSeekWanted = true; + mSeekDestination = time; + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + double volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else + { + INFOMSG("MediaPluginGStreamer010::receiveMessage: unknown message class: %s", message_class.c_str()); + } + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + if (MediaPluginGStreamer010::startup()) + { + MediaPluginGStreamer010 *self = new MediaPluginGStreamer010(host_send_func, host_user_data); + *plugin_send_func = MediaPluginGStreamer010::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; // okay + } + else + { + return -1; // failed to init + } +} + +#else // LL_GSTREAMER010_ENABLED + +// Stubbed-out class with constructor/destructor (necessary or windows linker +// will just think its dead code and optimize it all out) +class MediaPluginGStreamer010 : public MediaPluginBase +{ +public: + MediaPluginGStreamer010(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginGStreamer010(); + /* virtual */ void receiveMessage(const char *message_string); +}; + +MediaPluginGStreamer010::MediaPluginGStreamer010( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data) +{ + // no-op +} + +MediaPluginGStreamer010::~MediaPluginGStreamer010() +{ + // no-op +} + +void MediaPluginGStreamer010::receiveMessage(const char *message_string) +{ + // no-op +} + +// We're building without GStreamer enabled. Just refuse to initialize. +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return -1; +} + +#endif // LL_GSTREAMER010_ENABLED diff --git a/indra/media_plugins/quicktime/CMakeLists.txt b/indra/media_plugins/quicktime/CMakeLists.txt new file mode 100644 index 0000000000..db11c9ae21 --- /dev/null +++ b/indra/media_plugins/quicktime/CMakeLists.txt @@ -0,0 +1,83 @@ +# -*- cmake -*- + +project(media_plugin_quicktime) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) +include(QuickTimePlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(CARBON_LIBRARY Carbon) +endif (DARWIN) + + +### media_plugin_quicktime + +set(media_plugin_quicktime_SOURCE_FILES + media_plugin_quicktime.cpp + ) + +add_library(media_plugin_quicktime + SHARED + ${media_plugin_quicktime_SOURCE_FILES} +) + +target_link_libraries(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${QUICKTIME_LIBRARY} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_quicktime + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (QUICKTIME) + + add_definitions(-DLL_QUICKTIME_ENABLED=1) + + if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_quicktime + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + +# We use a bunch of deprecated system APIs. + set_source_files_properties( + media_plugin_quicktime.cpp PROPERTIES + COMPILE_FLAGS -Wno-deprecated-declarations + ) + find_library(CARBON_LIBRARY Carbon) + target_link_libraries(media_plugin_quicktime ${CARBON_LIBRARY}) + endif (DARWIN) +endif (QUICKTIME) + diff --git a/indra/media_plugins/quicktime/media_plugin_quicktime.cpp b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp new file mode 100644 index 0000000000..e9be458960 --- /dev/null +++ b/indra/media_plugins/quicktime/media_plugin_quicktime.cpp @@ -0,0 +1,984 @@ +/** + * @file media_plugin_quicktime.cpp + * @brief QuickTime plugin for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_QUICKTIME_ENABLED + +#if defined(LL_DARWIN) + #include +#elif defined(LL_WINDOWS) + #include "MacTypes.h" + #include "QTML.h" + #include "Movies.h" + #include "QDoffscreen.h" + #include "FixMath.h" +#endif + +// TODO: Make sure that the only symbol exported from this library is LLPluginInitEntryPoint +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + + /* virtual */ void receiveMessage(const char *message_string); + +private: + + int mNaturalWidth; + int mNaturalHeight; + Movie mMovieHandle; + GWorldPtr mGWorldHandle; + ComponentInstance mMovieController; + int mCurVolume; + bool mMediaSizeChanging; + bool mIsLooping; + const int mMinWidth; + const int mMaxWidth; + const int mMinHeight; + const int mMaxHeight; + F64 mPlayRate; + + enum ECommand { + COMMAND_NONE, + COMMAND_STOP, + COMMAND_PLAY, + COMMAND_FAST_FORWARD, + COMMAND_FAST_REWIND, + COMMAND_PAUSE, + COMMAND_SEEK, + }; + ECommand mCommand; + + // Override this to add current time and duration to the message + /*virtual*/ void setDirty(int left, int top, int right, int bottom) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "updated"); + + message.setValueS32("left", left); + message.setValueS32("top", top); + message.setValueS32("right", right); + message.setValueS32("bottom", bottom); + + if(mMovieHandle) + { + message.setValueReal("current_time", getCurrentTime()); + message.setValueReal("duration", getDuration()); + message.setValueReal("current_rate", Fix2X(GetMovieRate(mMovieHandle))); + } + + sendMessage(message); + } + + + static Rect rectFromSize(int width, int height) + { + Rect result; + + + result.left = 0; + result.top = 0; + result.right = width; + result.bottom = height; + + return result; + } + + Fixed getPlayRate(void) + { + Fixed result; + if(mPlayRate == 0.0f) + { + // Default to the movie's preferred rate + result = GetMoviePreferredRate(mMovieHandle); + if(result == 0) + { + // Don't return a 0 play rate, ever. + std::cerr << "Movie's preferred rate is 0, forcing to 1.0." << std::endl; + result = X2Fix(1.0f); + } + } + else + { + result = X2Fix(mPlayRate); + } + + return result; + } + + void load( const std::string url ) + { + if ( url.empty() ) + return; + + // Stop and unload any existing movie before starting another one. + unload(); + + setStatus(STATUS_LOADING); + + //In case std::string::c_str() makes a copy of the url data, + //make sure there is memory to hold it before allocating memory for handle. + //if fails, NewHandleClear(...) should return NULL. + const char* url_string = url.c_str() ; + Handle handle = NewHandleClear( ( Size )( url.length() + 1 ) ); + if ( NULL == handle || noErr != MemError() || NULL == *handle ) + { + setStatus(STATUS_ERROR); + return; + } + + BlockMove( url_string, *handle, ( Size )( url.length() + 1 ) ); + + OSErr err = NewMovieFromDataRef( &mMovieHandle, newMovieActive | newMovieDontInteractWithUser | newMovieAsyncOK | newMovieIdleImportOK, nil, handle, URLDataHandlerSubType ); + DisposeHandle( handle ); + if ( noErr != err ) + { + setStatus(STATUS_ERROR); + return; + }; + + // do pre-roll actions (typically fired for streaming movies but not always) + PrePrerollMovie( mMovieHandle, 0, getPlayRate(), moviePrePrerollCompleteCallback, ( void * )this ); + + Rect movie_rect = rectFromSize(mWidth, mHeight); + + // make a new movie controller + mMovieController = NewMovieController( mMovieHandle, &movie_rect, mcNotVisible | mcTopLeftMovie ); + + // movie controller + MCSetActionFilterWithRefCon( mMovieController, mcActionFilterCallBack, ( long )this ); + + SetMoviePlayHints( mMovieHandle, hintsAllowDynamicResize, hintsAllowDynamicResize ); + + // function that gets called when a frame is drawn + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, movieDrawingCompleteCallback, ( long )this ); + + setStatus(STATUS_LOADED); + + sizeChanged(); + }; + + bool unload() + { + if ( mMovieHandle ) + { + StopMovie( mMovieHandle ); + if ( mMovieController ) + { + MCMovieChanged( mMovieController, mMovieHandle ); + }; + }; + + if ( mMovieController ) + { + MCSetActionFilterWithRefCon( mMovieController, NULL, (long)this ); + DisposeMovieController( mMovieController ); + mMovieController = NULL; + }; + + if ( mMovieHandle ) + { + SetMovieDrawingCompleteProc( mMovieHandle, movieDrawingCallWhenChanged, nil, ( long )this ); + DisposeMovie( mMovieHandle ); + mMovieHandle = NULL; + }; + + if ( mGWorldHandle ) + { + DisposeGWorld( mGWorldHandle ); + mGWorldHandle = NULL; + }; + + setStatus(STATUS_NONE); + + return true; + } + + bool navigateTo( const std::string url ) + { + unload(); + load( url ); + + return true; + }; + + bool sizeChanged() + { + if ( ! mMovieHandle ) + return false; + + // Check to see whether the movie's natural size has updated + { + int width, height; + getMovieNaturalSize(&width, &height); + if((width != 0) && (height != 0) && ((width != mNaturalWidth) || (height != mNaturalHeight))) + { + mNaturalWidth = width; + mNaturalHeight = height; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_request"); + message.setValue("name", mTextureSegmentName); + message.setValueS32("width", width); + message.setValueS32("height", height); + sendMessage(message); + //std::cerr << "<--- Sending size change request to application with name: " << mTextureSegmentName << " - size is " << width << " x " << height << std::endl; + } + } + + // sanitize destination size + Rect dest_rect = rectFromSize(mWidth, mHeight); + + // media depth won't change + int depth_bits = mDepth * 8; + long rowbytes = mDepth * mTextureWidth; + + GWorldPtr old_gworld_handle = mGWorldHandle; + + if(mPixels != NULL) + { + // We have pixels. Set up a GWorld pointing at the texture. + OSErr result = NewGWorldFromPtr( &mGWorldHandle, depth_bits, &dest_rect, NULL, NULL, 0, (Ptr)mPixels, rowbytes); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + else + { + // We don't have pixels. Create a fake GWorld we can point the movie at when it's not safe to render normally. + Rect tempRect = rectFromSize(1, 1); + OSErr result = NewGWorld( &mGWorldHandle, depth_bits, &tempRect, NULL, NULL, 0); + if ( noErr != result ) + { + // TODO: unrecoverable?? throw exception? return something? + return false; + } + } + + SetMovieGWorld( mMovieHandle, mGWorldHandle, GetGWorldDevice( mGWorldHandle ) ); + + // If the GWorld was already set up, delete it. + if(old_gworld_handle != NULL) + { + DisposeGWorld( old_gworld_handle ); + } + + // Set up the movie display matrix + { + // scale movie to fit rect and invert vertically to match opengl image format + MatrixRecord transform; + SetIdentityMatrix( &transform ); // transforms are additive so start from identify matrix + double scaleX = (double) mWidth / mNaturalWidth; + double scaleY = -1.0 * (double) mHeight / mNaturalHeight; + double centerX = mWidth / 2.0; + double centerY = mHeight / 2.0; + ScaleMatrix( &transform, X2Fix( scaleX ), X2Fix( scaleY ), X2Fix( centerX ), X2Fix( centerY ) ); + SetMovieMatrix( mMovieHandle, &transform ); + } + + // update movie controller + if ( mMovieController ) + { + MCSetControllerPort( mMovieController, mGWorldHandle ); + MCPositionController( mMovieController, &dest_rect, &dest_rect, + mcTopLeftMovie | mcPositionDontInvalidate ); + MCMovieChanged( mMovieController, mMovieHandle ); + } + + + // Emit event with size change so the calling app knows about it too + // TODO: + //LLMediaEvent event( this ); + //mEventEmitter.update( &LLMediaObserver::onMediaSizeChange, event ); + + return true; + } + + static Boolean mcActionFilterCallBack( MovieController mc, short action, void *params, long ref ) + { + Boolean result = false; + + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + switch( action ) + { + // handle window resizing + case mcActionControllerSizeChanged: + // Ensure that the movie draws correctly at the new size + self->sizeChanged(); + break; + + // Block any movie controller actions that open URLs. + case mcActionLinkToURL: + case mcActionGetNextURL: + case mcActionLinkToURLExtended: + // Prevent the movie controller from handling the message + result = true; + break; + + default: + break; + }; + + return result; + }; + + static OSErr movieDrawingCompleteCallback( Movie call_back_movie, long ref ) + { + MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // IMPORTANT: typically, a consumer who is observing this event will set a flag + // when this event is fired then render later. Be aware that the media stream + // can change during this period - dimensions, depth, format etc. + //LLMediaEvent event( self ); +// self->updateQuickTime(); + // TODO ^^^ + + if ( self->mWidth > 0 && self->mHeight > 0 ) + self->setDirty( 0, 0, self->mWidth, self->mHeight ); + + return noErr; + }; + + static void moviePrePrerollCompleteCallback( Movie movie, OSErr preroll_err, void *ref ) + { + //MediaPluginQuickTime* self = ( MediaPluginQuickTime* )ref; + + // TODO: + //LLMediaEvent event( self ); + //self->mEventEmitter.update( &LLMediaObserver::onMediaPreroll, event ); + }; + + + void rewind() + { + GoToBeginningOfMovie( mMovieHandle ); + MCMovieChanged( mMovieController, mMovieHandle ); + }; + + bool processState() + { + if ( mCommand == COMMAND_PLAY ) + { + if ( mStatus == STATUS_LOADED || mStatus == STATUS_PAUSED || mStatus == STATUS_PLAYING ) + { + long state = GetMovieLoadState( mMovieHandle ); + + if ( state >= kMovieLoadStatePlaythroughOK ) + { + // if the movie is at the end (generally because it reached it naturally) + // and we play is requested, jump back to the start of the movie. + // note: this is different from having loop flag set. + if ( IsMovieDone( mMovieHandle ) ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + }; + + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + setStatus(STATUS_PLAYING); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_STOP ) + { + if ( mStatus == STATUS_PLAYING || mStatus == STATUS_PAUSED ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + rewind(); + + setStatus(STATUS_LOADED); + mCommand = COMMAND_NONE; + }; + }; + } + else + if ( mCommand == COMMAND_PAUSE ) + { + if ( mStatus == STATUS_PLAYING ) + { + if ( GetMovieLoadState( mMovieHandle ) >= kMovieLoadStatePlaythroughOK ) + { + Fixed rate = X2Fix( 0.0 ); + MCDoAction( mMovieController, mcActionPlay, (void*)rate ); + setStatus(STATUS_PAUSED); + mCommand = COMMAND_NONE; + }; + }; + }; + + return true; + }; + + void play(F64 rate) + { + mPlayRate = rate; + mCommand = COMMAND_PLAY; + }; + + void stop() + { + mCommand = COMMAND_STOP; + }; + + void pause() + { + mCommand = COMMAND_PAUSE; + }; + + void getMovieNaturalSize(int *movie_width, int *movie_height) + { + Rect rect; + + GetMovieNaturalBoundsRect( mMovieHandle, &rect ); + + int width = ( rect.right - rect.left ); + int height = ( rect.bottom - rect.top ); + + // make sure width and height fall in valid range + if ( width < mMinWidth ) + width = mMinWidth; + + if ( width > mMaxWidth ) + width = mMaxWidth; + + if ( height < mMinHeight ) + height = mMinHeight; + + if ( height > mMaxHeight ) + height = mMaxHeight; + + // return the new rect + *movie_width = width; + *movie_height = height; + } + + void updateQuickTime(int milliseconds) + { + if ( ! mMovieHandle ) + return; + + if ( ! mMovieController ) + return; + + // service QuickTime + // Calling it this way doesn't have good behavior on Windows... +// MoviesTask( mMovieHandle, milliseconds ); + // This was the original, but I think using both MoviesTask and MCIdle is redundant. Trying with only MCIdle. +// MoviesTask( mMovieHandle, 0 ); + + MCIdle( mMovieController ); + + if ( ! mGWorldHandle ) + return; + + if ( mMediaSizeChanging ) + return; + + // update state machine + processState(); + + // special code for looping - need to rewind at the end of the movie + if ( mIsLooping ) + { + // QT call to see if we are at the end - can't do with controller + if ( IsMovieDone( mMovieHandle ) ) + { + // go back to start + rewind(); + + if ( mMovieController ) + { + // kick off new play + MCDoAction( mMovieController, mcActionPrerollAndPlay, (void*)getPlayRate() ); + + // set the volume + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + }; + }; + }; + + int getDataWidth() const + { + if ( mGWorldHandle ) + { + int depth = mDepth; + + if (depth < 1) + depth = 1; + + // ALWAYS use the row bytes from the PixMap if we have a GWorld because + // sometimes it's not the same as mMediaDepth * mMediaWidth ! + PixMapHandle pix_map_handle = GetGWorldPixMap( mGWorldHandle ); + return QTGetPixMapHandleRowBytes( pix_map_handle ) / depth; + } + else + { + // TODO : return LLMediaImplCommon::getaDataWidth(); + return 0; + } + }; + + void seek( F64 time ) + { + if ( mMovieController ) + { + TimeRecord when; + when.scale = GetMovieTimeScale( mMovieHandle ); + when.base = 0; + + // 'time' is in (floating point) seconds. The timebase time will be in 'units', where + // there are 'scale' units per second. + SInt64 raw_time = ( SInt64 )( time * (double)( when.scale ) ); + + when.value.hi = ( SInt32 )( raw_time >> 32 ); + when.value.lo = ( SInt32 )( ( raw_time & 0x00000000FFFFFFFF ) ); + + MCDoAction( mMovieController, mcActionGoToTime, &when ); + }; + }; + + F64 getDuration() + { + TimeValue duration = GetMovieDuration( mMovieHandle ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)duration / (F64)scale; + }; + + F64 getCurrentTime() + { + TimeValue curr_time = GetMovieTime( mMovieHandle, 0 ); + TimeValue scale = GetMovieTimeScale( mMovieHandle ); + + return (F64)curr_time / (F64)scale; + }; + + void setVolume( F64 volume ) + { + mCurVolume = (short)(volume * ( double ) 0x100 ); + + if ( mMovieController ) + { + MCDoAction( mMovieController, mcActionSetVolume, (void*)mCurVolume ); + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds = 0) + { + updateQuickTime(milliseconds); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( unsigned char key ) + { + }; + +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data), + mMinWidth( 0 ), + mMaxWidth( 2048 ), + mMinHeight( 0 ), + mMaxHeight( 2048 ) +{ +// std::cerr << "MediaPluginQuickTime constructor" << std::endl; + + mNaturalWidth = -1; + mNaturalHeight = -1; + mMovieHandle = 0; + mGWorldHandle = 0; + mMovieController = 0; + mCurVolume = 0x99; + mMediaSizeChanging = false; + mIsLooping = false; + mCommand = COMMAND_NONE; + mPlayRate = 0.0f; + mStatus = STATUS_NONE; +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ +// std::cerr << "MediaPluginQuickTime destructor" << std::endl; + + ExitMovies(); + +#ifdef LL_WINDOWS + TerminateQTML(); +// std::cerr << "QuickTime closing down" << std::endl; +#endif +} + + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginQuickTime::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + // Normally a plugin would only specify one of these two subclasses, but this is a demo... +// versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME] = LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME_VERSION; + message.setValueLLSD("versions", versions); + + #ifdef LL_WINDOWS + if ( InitializeQTML( 0L ) != noErr ) + { + //TODO: If no QT on Windows, this fails - respond accordingly. + //return false; + } + else + { +// std::cerr << "QuickTime initialized" << std::endl; + }; + #endif + + EnterMovies(); + + std::string plugin_version = "QuickTime media plugin, QuickTime version "; + + long version = 0; + Gestalt( gestaltQuickTimeVersion, &version ); + std::ostringstream codec( "" ); + codec << std::hex << version << std::dec; + plugin_version += codec.str(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + #if defined(LL_WINDOWS) + // Values for Windows + mDepth = 3; + message.setValueU32("format", GL_RGB); + message.setValueU32("type", GL_UNSIGNED_BYTE); + + // We really want to pad the texture width to a multiple of 32 bytes, but since we're using 3-byte pixels, it doesn't come out even. + // Padding to a multiple of 3*32 guarantees it'll divide out properly. + message.setValueU32("padding", 32 * 3); + #else + // Values for Mac + mDepth = 4; + message.setValueU32("format", GL_BGRA_EXT); + #ifdef __BIG_ENDIAN__ + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8_REV ); + #else + message.setValueU32("type", GL_UNSIGNED_INT_8_8_8_8); + #endif + + // Pad texture width to a multiple of 32 bytes, to line up with cache lines. + message.setValueU32("padding", 32); + #endif + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGB); + message.setValueBoolean("coords_opengl", true); // true == use OpenGL-style coordinates, false == (0,0) is upper left. + message.setValueBoolean("allow_downsample", true); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // TODO: clean up here + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + U64 address_lo = message_in.getValueU32("address"); + U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; + info.mAddress = (void*)((address_lo) | + (address_hi * (U64(1)<<31))); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginQuickTime::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + + // Make sure the movie GWorld is no longer pointed at the shared segment. + sizeChanged(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + //std::cerr << "---->Got size change instruction from application with name: " << name << " - size is " << width << " x " << height << std::endl; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { +// std::cerr << "%%% Got size change, new size is " << width << " by " << height << std::endl; +// std::cerr << "%%%% texture size is " << texture_width << " by " << texture_height << std::endl; + + mPixels = (unsigned char*)iter->second.mAddress; + mTextureSegmentName = name; + mWidth = width; + mHeight = height; + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + mMediaSizeChanging = false; + + sizeChanged(); + + update(); + }; + }; + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + load( uri ); + sendStatus(); + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + + if(event == "down") + { + mouseDown(x, y); + } + else if(event == "up") + { + mouseUp(x, y); + } + else if(event == "move") + { + mouseMove(x, y); + }; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_TIME) + { + if(message_name == "stop") + { + stop(); + } + else if(message_name == "start") + { + F64 rate = 0.0; + if(message_in.hasValue("rate")) + { + rate = message_in.getValueReal("rate"); + } + play(rate); + } + else if(message_name == "pause") + { + pause(); + } + else if(message_name == "seek") + { + F64 time = message_in.getValueReal("time"); + seek(time); + } + else if(message_name == "set_loop") + { + bool loop = message_in.getValueBoolean("loop"); + mIsLooping = loop; + } + else if(message_name == "set_volume") + { + F64 volume = message_in.getValueReal("volume"); + setVolume(volume); + } + } + else + { +// std::cerr << "MediaPluginQuickTime::receiveMessage: unknown message class: " << message_class << std::endl; + }; + }; +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginQuickTime *self = new MediaPluginQuickTime(host_send_func, host_user_data); + *plugin_send_func = MediaPluginQuickTime::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + +#else // LL_QUICKTIME_ENABLED + +// Stubbed-out class with constructor/destructor (necessary or windows linker +// will just think its dead code and optimize it all out) +class MediaPluginQuickTime : public MediaPluginBase +{ +public: + MediaPluginQuickTime(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginQuickTime(); + /* virtual */ void receiveMessage(const char *message_string); +}; + +MediaPluginQuickTime::MediaPluginQuickTime( + LLPluginInstance::sendMessageFunction host_send_func, + void *host_user_data ) : + MediaPluginBase(host_send_func, host_user_data) +{ + // no-op +} + +MediaPluginQuickTime::~MediaPluginQuickTime() +{ + // no-op +} + +void MediaPluginQuickTime::receiveMessage(const char *message_string) +{ + // no-op +} + +// We're building without quicktime enabled. Just refuse to initialize. +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + return -1; +} + +#endif // LL_QUICKTIME_ENABLED diff --git a/indra/media_plugins/webkit/CMakeLists.txt b/indra/media_plugins/webkit/CMakeLists.txt new file mode 100644 index 0000000000..d96477279d --- /dev/null +++ b/indra/media_plugins/webkit/CMakeLists.txt @@ -0,0 +1,74 @@ +# -*- cmake -*- + +project(media_plugin_webkit) + +include(00-Common) +include(LLCommon) +include(LLImage) +include(LLPlugin) +include(LLMath) +include(LLRender) +include(LLWindow) +include(Linking) +include(PluginAPI) +include(MediaPluginBase) +include(FindOpenGL) + +include(WebKitLibPlugin) + +include_directories( + ${LLPLUGIN_INCLUDE_DIRS} + ${MEDIA_PLUGIN_BASE_INCLUDE_DIRS} + ${LLCOMMON_INCLUDE_DIRS} + ${LLMATH_INCLUDE_DIRS} + ${LLIMAGE_INCLUDE_DIRS} + ${LLRENDER_INCLUDE_DIRS} + ${LLWINDOW_INCLUDE_DIRS} +) + + +### media_plugin_webkit + +set(media_plugin_webkit_SOURCE_FILES + media_plugin_webkit.cpp + ) + +add_library(media_plugin_webkit + SHARED + ${media_plugin_webkit_SOURCE_FILES} +) + +target_link_libraries(media_plugin_webkit + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ${WEBKIT_PLUGIN_LIBRARIES} + ${PLUGIN_API_WINDOWS_LIBRARIES} +) + +add_dependencies(media_plugin_webkit + ${LLPLUGIN_LIBRARIES} + ${MEDIA_PLUGIN_BASE_LIBRARIES} + ${LLCOMMON_LIBRARIES} +) + +if (DARWIN) + # Don't prepend 'lib' to the executable name, and don't embed a full path in the library's install name + set_target_properties( + media_plugin_webkit + PROPERTIES + PREFIX "" + BUILD_WITH_INSTALL_RPATH 1 + INSTALL_NAME_DIR "@executable_path" + LINK_FLAGS "-exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/../base/media_plugin_base.exp" + ) + + # copy the webkit dylib to the build directory + add_custom_command( + TARGET media_plugin_webkit POST_BUILD +# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/libllqtwebkit.dylib + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/ + DEPENDS media_plugin_webkit ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib + ) + +endif (DARWIN) \ No newline at end of file diff --git a/indra/media_plugins/webkit/media_plugin_webkit.cpp b/indra/media_plugins/webkit/media_plugin_webkit.cpp new file mode 100644 index 0000000000..2928b7e6b3 --- /dev/null +++ b/indra/media_plugins/webkit/media_plugin_webkit.cpp @@ -0,0 +1,792 @@ +/** + * @file media_plugin_webkit.cpp + * @brief Webkit plugin for LLMedia API plugin system + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llqtwebkit.h" + +#include "linden_common.h" +#include "indra_constants.h" // for indra keyboard codes + +#include "llgl.h" + +#include "llplugininstance.h" +#include "llpluginmessage.h" +#include "llpluginmessageclasses.h" +#include "media_plugin_base.h" + +#if LL_WINDOWS +#include +#else +#include +#include +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +class MediaPluginWebKit : + public MediaPluginBase, + public LLEmbeddedBrowserWindowObserver +{ +public: + MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data); + ~MediaPluginWebKit(); + + /*virtual*/ void receiveMessage(const char *message_string); + +private: + + int mBrowserWindowId; + bool mBrowserInitialized; + bool mNeedsUpdate; + + bool mCanCut; + bool mCanCopy; + bool mCanPaste; + + //////////////////////////////////////////////////////////////////////////////// + // + void update(int milliseconds) + { + LLQtWebKit::getInstance()->pump( milliseconds ); + + checkEditState(); + + if ( mNeedsUpdate ) + { + const unsigned char* browser_pixels = LLQtWebKit::getInstance()->grabBrowserWindow( mBrowserWindowId ); + + unsigned int buffer_size = LLQtWebKit::getInstance()->getBrowserRowSpan( mBrowserWindowId ) * LLQtWebKit::getInstance()->getBrowserHeight( mBrowserWindowId ); + +// std::cerr << "webkit plugin: updating" << std::endl; + + // TODO: should get rid of this memcpy if possible + if ( mPixels && browser_pixels ) + { +// std::cerr << " memcopy of " << buffer_size << " bytes" << std::endl; + memcpy( mPixels, browser_pixels, buffer_size ); + } + + if ( mWidth > 0 && mHeight > 0 ) + { +// std::cerr << "Setting dirty, " << mWidth << " x " << mHeight << std::endl; + setDirty( 0, 0, mWidth, mHeight ); + } + + mNeedsUpdate = false; + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + // + bool initBrowser() + { + // already initialized + if ( mBrowserInitialized ) + return true; + + // not enough information to initialize the browser yet. + if ( mWidth < 0 || mHeight < 0 || mDepth < 0 || + mTextureWidth < 0 || mTextureHeight < 0 ) + { + return false; + }; + + // set up directories + char cwd[ FILENAME_MAX ]; // I *think* this is defined on all platforms we use + if (NULL == getcwd( cwd, FILENAME_MAX - 1 )) + { + llwarns << "Couldn't get cwd - probably too long - failing to init." << llendl; + return false; + } + std::string application_dir = std::string( cwd ); + std::string component_dir = application_dir; + std::string profileDir = application_dir + "/" + "browser_profile"; // cross platform? + + // window handle - needed on Windows and must be app window. +#if LL_WINDOWS + char window_title[ MAX_PATH ]; + GetConsoleTitleA( window_title, MAX_PATH ); + void* native_window_handle = (void*)FindWindowA( NULL, window_title ); +#else + void* native_window_handle = 0; +#endif + + // main browser initialization + bool result = LLQtWebKit::getInstance()->init( application_dir, component_dir, profileDir, native_window_handle ); + if ( result ) + { + // create single browser window + mBrowserWindowId = LLQtWebKit::getInstance()->createBrowserWindow( mWidth, mHeight ); + +#if LL_WINDOWS + // Enable plugins + LLQtWebKit::getInstance()->enablePlugins(true); +#else + // Disable plugins + LLQtWebKit::getInstance()->enablePlugins(false); +#endif + + // tell LLQtWebKit about the size of the browser window + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + + // observer events that LLQtWebKit emits + LLQtWebKit::getInstance()->addObserver( mBrowserWindowId, this ); + + // append details to agent string + LLQtWebKit::getInstance()->setBrowserAgentId( "LLPluginMedia Web Browser" ); + + // don't flip bitmap + LLQtWebKit::getInstance()->flipWindow( mBrowserWindowId, true ); + + // go to the "home page" + // Don't do this here -- it causes the dreaded "white flash" when loading a browser instance. +// LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, "about:blank" ); + + // set flag so we don't do this again + mBrowserInitialized = true; + + return true; + }; + + return false; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onCursorChanged(const EventType& event) + { + LLQtWebKit::ECursor llqt_cursor = (LLQtWebKit::ECursor)event.getIntValue(); + std::string name; + + switch(llqt_cursor) + { + case LLQtWebKit::C_ARROW: + name = "arrow"; + break; + case LLQtWebKit::C_IBEAM: + name = "ibeam"; + break; + case LLQtWebKit::C_SPLITV: + name = "splitv"; + break; + case LLQtWebKit::C_SPLITH: + name = "splith"; + break; + case LLQtWebKit::C_POINTINGHAND: + name = "hand"; + break; + + default: + llwarns << "Unknown cursor ID: " << (int)llqt_cursor << llendl; + break; + } + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "cursor_changed"); + message.setValue("name", name); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onPageChanged( const EventType& event ) + { + // flag that an update is required + mNeedsUpdate = true; + }; + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateBegin(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_begin"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + + setStatus(STATUS_LOADING); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onNavigateComplete(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "navigate_complete"); + message.setValue("uri", event.getEventUri()); + message.setValueS32("result_code", event.getIntValue()); + message.setValue("result_string", event.getStringValue()); + message.setValueBoolean("history_back_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK)); + message.setValueBoolean("history_forward_available", LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD)); + sendMessage(message); + + setStatus(STATUS_LOADED); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onUpdateProgress(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "progress"); + message.setValueS32("percent", event.getIntValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onStatusTextChange(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "status_text"); + message.setValue("status", event.getStringValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onLocationChange(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "location_changed"); + message.setValue("uri", event.getEventUri()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkHref(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_href"); + message.setValue("uri", event.getStringValue()); + message.setValue("target", event.getStringValue2()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // virtual + void onClickLinkNoFollow(const EventType& event) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER, "click_nofollow"); + message.setValue("uri", event.getStringValue()); + sendMessage(message); + } + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseDown( int x, int y ) + { + LLQtWebKit::getInstance()->mouseDown( mBrowserWindowId, x, y ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseUp( int x, int y ) + { + LLQtWebKit::getInstance()->mouseUp( mBrowserWindowId, x, y ); + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, true ); + checkEditState(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void mouseMove( int x, int y ) + { + LLQtWebKit::getInstance()->mouseMove( mBrowserWindowId, x, y ); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void keyPress( int key ) + { + int llqt_key; + + // The incoming values for 'key' will be the ones from indra_constants.h + // the outgoing values are the ones from llqtwebkit.h + + switch((KEY)key) + { + // This is the list that the llqtwebkit implementation actually maps into Qt keys. +// case KEY_XXX: llqt_key = LL_DOM_VK_CANCEL; break; +// case KEY_XXX: llqt_key = LL_DOM_VK_HELP; break; + case KEY_BACKSPACE: llqt_key = LL_DOM_VK_BACK_SPACE; break; + case KEY_TAB: llqt_key = LL_DOM_VK_TAB; break; +// case KEY_XXX: llqt_key = LL_DOM_VK_CLEAR; break; + case KEY_RETURN: llqt_key = LL_DOM_VK_RETURN; break; + case KEY_PAD_RETURN: llqt_key = LL_DOM_VK_ENTER; break; + case KEY_SHIFT: llqt_key = LL_DOM_VK_SHIFT; break; + case KEY_CONTROL: llqt_key = LL_DOM_VK_CONTROL; break; + case KEY_ALT: llqt_key = LL_DOM_VK_ALT; break; +// case KEY_XXX: llqt_key = LL_DOM_VK_PAUSE; break; + case KEY_CAPSLOCK: llqt_key = LL_DOM_VK_CAPS_LOCK; break; + case KEY_ESCAPE: llqt_key = LL_DOM_VK_ESCAPE; break; + case KEY_PAGE_UP: llqt_key = LL_DOM_VK_PAGE_UP; break; + case KEY_PAGE_DOWN: llqt_key = LL_DOM_VK_PAGE_DOWN; break; + case KEY_END: llqt_key = LL_DOM_VK_END; break; + case KEY_HOME: llqt_key = LL_DOM_VK_HOME; break; + case KEY_LEFT: llqt_key = LL_DOM_VK_LEFT; break; + case KEY_UP: llqt_key = LL_DOM_VK_UP; break; + case KEY_RIGHT: llqt_key = LL_DOM_VK_RIGHT; break; + case KEY_DOWN: llqt_key = LL_DOM_VK_DOWN; break; +// case KEY_XXX: llqt_key = LL_DOM_VK_PRINTSCREEN; break; + case KEY_INSERT: llqt_key = LL_DOM_VK_INSERT; break; + case KEY_DELETE: llqt_key = LL_DOM_VK_DELETE; break; +// case KEY_XXX: llqt_key = LL_DOM_VK_CONTEXT_MENU; break; + + default: + if(key < KEY_SPECIAL) + { + // Pass the incoming key through -- it should be regular ASCII, which should be correct for webkit. + llqt_key = key; + } + else + { + // Don't pass through untranslated special keys -- they'll be all wrong. + llqt_key = 0; + } + break; + } + +// std::cerr << "keypress, original code = 0x" << std::hex << key << ", converted code = 0x" << std::hex << llqt_key << std::dec << std::endl; + + if(llqt_key != 0) + { + LLQtWebKit::getInstance()->keyPress( mBrowserWindowId, llqt_key ); + } + + checkEditState(); + }; + + //////////////////////////////////////////////////////////////////////////////// + // + void unicodeInput( const std::string &utf8str ) + { + LLWString wstr = utf8str_to_wstring(utf8str); + + unsigned int i; + for(i=0; i < wstr.size(); i++) + { +// std::cerr << "unicode input, code = 0x" << std::hex << (unsigned long)(wstr[i]) << std::dec << std::endl; + + LLQtWebKit::getInstance()->unicodeInput(mBrowserWindowId, wstr[i]); + } + + checkEditState(); + }; + + void checkEditState(void) + { + bool can_cut = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT); + bool can_copy = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY); + bool can_paste = LLQtWebKit::getInstance()->userActionIsEnabled( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE); + + if((can_cut != mCanCut) || (can_copy != mCanCopy) || (can_paste != mCanPaste)) + { + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "edit_state"); + + if(can_cut != mCanCut) + { + mCanCut = can_cut; + message.setValueBoolean("cut", can_cut); + } + + if(can_copy != mCanCopy) + { + mCanCopy = can_copy; + message.setValueBoolean("copy", can_copy); + } + + if(can_paste != mCanPaste) + { + mCanPaste = can_paste; + message.setValueBoolean("paste", can_paste); + } + + sendMessage(message); + + } + } + +}; + +MediaPluginWebKit::MediaPluginWebKit(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data) : + MediaPluginBase(host_send_func, host_user_data) +{ +// std::cerr << "MediaPluginWebKit constructor" << std::endl; + + mBrowserWindowId = 0; + mBrowserInitialized = false; + mNeedsUpdate = true; + mCanCut = false; + mCanCopy = false; + mCanPaste = false; +} + +MediaPluginWebKit::~MediaPluginWebKit() +{ + // unhook observer + LLQtWebKit::getInstance()->remObserver( mBrowserWindowId, this ); + + // clean up + LLQtWebKit::getInstance()->reset(); + +// std::cerr << "MediaPluginWebKit destructor" << std::endl; +} + +void MediaPluginWebKit::receiveMessage(const char *message_string) +{ +// std::cerr << "MediaPluginWebKit::receiveMessage: received message: \"" << message_string << "\"" << std::endl; + LLPluginMessage message_in; + + if(message_in.parse(message_string) >= 0) + { + std::string message_class = message_in.getClass(); + std::string message_name = message_in.getName(); + if(message_class == LLPLUGIN_MESSAGE_CLASS_BASE) + { + if(message_name == "init") + { + LLPluginMessage message("base", "init_response"); + LLSD versions = LLSD::emptyMap(); + versions[LLPLUGIN_MESSAGE_CLASS_BASE] = LLPLUGIN_MESSAGE_CLASS_BASE_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA] = LLPLUGIN_MESSAGE_CLASS_MEDIA_VERSION; + versions[LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER] = LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER_VERSION; + message.setValueLLSD("versions", versions); + + std::string plugin_version = "Webkit media plugin, Webkit version "; + plugin_version += LLQtWebKit::getInstance()->getVersion(); + message.setValue("plugin_version", plugin_version); + sendMessage(message); + + // Plugin gets to decide the texture parameters to use. + mDepth = 4; + + message.setMessage(LLPLUGIN_MESSAGE_CLASS_MEDIA, "texture_params"); + message.setValueS32("default_width", 800); + message.setValueS32("default_height", 600); + message.setValueS32("depth", mDepth); + message.setValueU32("internalformat", GL_RGBA); + message.setValueU32("format", GL_RGBA); + message.setValueU32("type", GL_UNSIGNED_BYTE); + message.setValueBoolean("coords_opengl", true); + sendMessage(message); + } + else if(message_name == "idle") + { + // no response is necessary here. + F64 time = message_in.getValueReal("time"); + + // Convert time to milliseconds for update() + update((int)(time * 1000.0f)); + } + else if(message_name == "cleanup") + { + // TODO: clean up here + } + else if(message_name == "shm_added") + { + SharedSegmentInfo info; + U64 address_lo = message_in.getValueU32("address"); + U64 address_hi = message_in.hasValue("address_1") ? message_in.getValueU32("address_1") : 0; + info.mAddress = (void*)((address_lo) | + (address_hi * (U64(1)<<31))); + info.mSize = (size_t)message_in.getValueS32("size"); + std::string name = message_in.getValue("name"); + + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory added, name: " << name +// << ", size: " << info.mSize +// << ", address: " << info.mAddress +// << std::endl; + + mSharedSegments.insert(SharedSegmentMap::value_type(name, info)); + + } + else if(message_name == "shm_remove") + { + std::string name = message_in.getValue("name"); + +// std::cerr << "MediaPluginWebKit::receiveMessage: shared memory remove, name = " << name << std::endl; + + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + if(mPixels == iter->second.mAddress) + { + // This is the currently active pixel buffer. Make sure we stop drawing to it. + mPixels = NULL; + mTextureSegmentName.clear(); + } + mSharedSegments.erase(iter); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown shared memory region!" << std::endl; + } + + // Send the response so it can be cleaned up. + LLPluginMessage message("base", "shm_remove_response"); + message.setValue("name", name); + sendMessage(message); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown base message: " << message_name << std::endl; + } + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA) + { + if(message_name == "size_change") + { + std::string name = message_in.getValue("name"); + S32 width = message_in.getValueS32("width"); + S32 height = message_in.getValueS32("height"); + S32 texture_width = message_in.getValueS32("texture_width"); + S32 texture_height = message_in.getValueS32("texture_height"); + + if(!name.empty()) + { + // Find the shared memory region with this name + SharedSegmentMap::iterator iter = mSharedSegments.find(name); + if(iter != mSharedSegments.end()) + { + mPixels = (unsigned char*)iter->second.mAddress; + mWidth = width; + mHeight = height; + + // initialize (only gets called once) + initBrowser(); + + // size changed so tell the browser + LLQtWebKit::getInstance()->setSize( mBrowserWindowId, mWidth, mHeight ); + +// std::cerr << "webkit plugin: set size to " << mWidth << " x " << mHeight +// << ", rowspan is " << LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) << std::endl; + + S32 real_width = LLQtWebKit::getInstance()->getBrowserRowSpan(mBrowserWindowId) / LLQtWebKit::getInstance()->getBrowserDepth(mBrowserWindowId); + + // The actual width the browser will be drawing to is probably smaller... let the host know by modifying texture_width in the response. + if(real_width <= texture_width) + { + texture_width = real_width; + } + else + { + // This won't work -- it'll be bigger than the allocated memory. This is a fatal error. +// std::cerr << "Fatal error: browser rowbytes greater than texture width" << std::endl; + mDeleteMe = true; + return; + } + + mTextureWidth = texture_width; + mTextureHeight = texture_height; + + }; + }; + + LLPluginMessage message(LLPLUGIN_MESSAGE_CLASS_MEDIA, "size_change_response"); + message.setValue("name", name); + message.setValueS32("width", width); + message.setValueS32("height", height); + message.setValueS32("texture_width", texture_width); + message.setValueS32("texture_height", texture_height); + sendMessage(message); + + } + else if(message_name == "load_uri") + { + std::string uri = message_in.getValue("uri"); + +// std::cout << "loading URI: " << uri << std::endl; + + if(!uri.empty()) + { + LLQtWebKit::getInstance()->navigateTo( mBrowserWindowId, uri ); + } + } + else if(message_name == "mouse_event") + { + std::string event = message_in.getValue("event"); + S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + // std::string modifiers = message.getValue("modifiers"); + + if(event == "down") + { + mouseDown(x, y); + //std::cout << "Mouse down at " << x << " x " << y << std::endl; + } + else if(event == "up") + { + mouseUp(x, y); + //std::cout << "Mouse up at " << x << " x " << y << std::endl; + } + else if(event == "move") + { + mouseMove(x, y); + //std::cout << ">>>>>>>>>>>>>>>>>>>> Mouse move at " << x << " x " << y << std::endl; + } + } + else if(message_name == "scroll_event") + { + // S32 x = message_in.getValueS32("x"); + S32 y = message_in.getValueS32("y"); + // std::string modifiers = message.getValue("modifiers"); + + // We currently ignore horizontal scrolling. + // The scroll values are roughly 1 per wheel click, so we need to magnify them by some factor. + // Arbitrarily, I choose 16. + y *= 16; + LLQtWebKit::getInstance()->scrollByLines(mBrowserWindowId, y); + } + else if(message_name == "key_event") + { + std::string event = message_in.getValue("event"); + + // act on "key down" or "key repeat" + if ( (event == "down") || (event == "repeat") ) + { + S32 key = message_in.getValueS32("key"); + keyPress( key ); + }; + } + else if(message_name == "text_event") + { + std::string text = message_in.getValue("text"); + + unicodeInput(text); + } + if(message_name == "edit_cut") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_CUT ); + } + if(message_name == "edit_copy") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_COPY ); + } + if(message_name == "edit_paste") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_EDIT_PASTE ); + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media message: " << message_string << std::endl; + }; + } + else if(message_class == LLPLUGIN_MESSAGE_CLASS_MEDIA_BROWSER) + { + if(message_name == "focus") + { + bool val = message_in.getValueBoolean("focused"); + LLQtWebKit::getInstance()->focusBrowser( mBrowserWindowId, val ); + } + else if(message_name == "clear_cache") + { + LLQtWebKit::getInstance()->clearCache(); + } + else if(message_name == "clear_cookies") + { + LLQtWebKit::getInstance()->clearAllCookies(); + } + else if(message_name == "enable_cookies") + { + bool val = message_in.getValueBoolean("enable"); + LLQtWebKit::getInstance()->enableCookies( val ); + } + else if(message_name == "proxy_setup") + { + bool val = message_in.getValueBoolean("enable"); + std::string host = message_in.getValue("host"); + int port = message_in.getValueS32("port"); + LLQtWebKit::getInstance()->enableProxy( val, host, port ); + } + else if(message_name == "browse_stop") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_STOP ); + } + else if(message_name == "browse_reload") + { + // foo = message_in.getValueBoolean("ignore_cache"); + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_RELOAD ); + } + else if(message_name == "browse_forward") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_FORWARD ); + } + else if(message_name == "browse_back") + { + LLQtWebKit::getInstance()->userAction( mBrowserWindowId, LLQtWebKit::UA_NAVIGATE_BACK ); + } + else if(message_name == "set_status_redirect") + { + int code = message_in.getValueS32("code"); + std::string url = message_in.getValue("url"); + if ( 404 == code ) // browser lib only supports 404 right now + { + LLQtWebKit::getInstance()->set404RedirectUrl( mBrowserWindowId, url ); + }; + } + else if(message_name == "set_user_agent") + { + std::string user_agent = message_in.getValue("user_agent"); + LLQtWebKit::getInstance()->setBrowserAgentId( user_agent ); + } + else if(message_name == "init_history") + { + // Initialize browser history + LLSD history = message_in.getValueLLSD("history"); + // First, clear the URL history + LLQtWebKit::getInstance()->clearHistory(mBrowserWindowId); + // Then, add the history items in order + LLSD::array_iterator iter_history = history.beginArray(); + LLSD::array_iterator end_history = history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) { + LLQtWebKit::getInstance()->prependHistoryUrl(mBrowserWindowId, url); + } + } + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown media_browser message: " << message_string << std::endl; + }; + } + else + { +// std::cerr << "MediaPluginWebKit::receiveMessage: unknown message class: " << message_class << std::endl; + }; + } +} + +int init_media_plugin(LLPluginInstance::sendMessageFunction host_send_func, void *host_user_data, LLPluginInstance::sendMessageFunction *plugin_send_func, void **plugin_user_data) +{ + MediaPluginWebKit *self = new MediaPluginWebKit(host_send_func, host_user_data); + *plugin_send_func = MediaPluginWebKit::staticReceiveMessage; + *plugin_user_data = (void*)self; + + return 0; +} + diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 0c8486bd4f..297540ffc0 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -18,17 +18,17 @@ include(LLImage) include(LLImageJ2COJ) include(LLInventory) include(LLMath) -include(LLMedia) include(LLMessage) +include(LLPlugin) include(LLPrimitive) include(LLRender) include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) +include(LLXUIXML) include(LScript) include(Linking) -include(Mozlib) include(NDOF) include(GooglePerfTools) include(TemplateCheck) @@ -50,48 +50,60 @@ include_directories( ${LLIMAGE_INCLUDE_DIRS} ${LLINVENTORY_INCLUDE_DIRS} ${LLMATH_INCLUDE_DIRS} - ${LLMEDIA_INCLUDE_DIRS} ${LLMESSAGE_INCLUDE_DIRS} + ${LLPLUGIN_INCLUDE_DIRS} ${LLPRIMITIVE_INCLUDE_DIRS} ${LLRENDER_INCLUDE_DIRS} ${LLUI_INCLUDE_DIRS} ${LLVFS_INCLUDE_DIRS} ${LLWINDOW_INCLUDE_DIRS} ${LLXML_INCLUDE_DIRS} + ${LLXUIXML_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS} ${LSCRIPT_INCLUDE_DIRS}/lscript_compile ) set(viewer_SOURCE_FILES + llaccordionctrltab.cpp + llaccordionctrl.cpp + llactiveimwindow.cpp llagent.cpp llagentaccess.cpp llagentdata.cpp llagentlanguage.cpp llagentpilot.cpp + llagentui.cpp + llagentwearables.cpp llanimstatelabels.cpp llappviewer.cpp llassetuploadresponders.cpp llassetuploadqueue.cpp llaudiosourcevo.cpp - llbbox.cpp + llavataractions.cpp + llavatariconctrl.cpp + llavatarlist.cpp + llavatarlistitem.cpp + llavatarpropertiesprocessor.cpp + llbottomtray.cpp llbox.cpp + llbreadcrumbview.cpp llcallbacklist.cpp llcallingcard.cpp llcapabilitylistener.cpp llcaphttpsender.cpp + llchannelmanager.cpp llchatbar.cpp + llchatitemscontainerctrl.cpp + llchatmsgbox.cpp + llchiclet.cpp llclassifiedinfo.cpp llclassifiedstatsresponder.cpp llcloud.cpp - llcolorscheme.cpp llcolorswatch.cpp llcommandhandler.cpp llcommandlineparser.cpp - llcompass.cpp llcompilequeue.cpp llconfirmationmanager.cpp - llconsole.cpp - llcontainerview.cpp llcurrencyuimanager.cpp llcylinder.cpp lldebugmessagebox.cpp @@ -118,15 +130,16 @@ set(viewer_SOURCE_FILES lleventpoll.cpp llface.cpp llfasttimerview.cpp + llfavoritesbar.cpp llfeaturemanager.cpp llfilepicker.cpp llfirstuse.cpp + llfirsttimetipmanager.cpp llflexibleobject.cpp llfloaterabout.cpp llfloateractivespeakers.cpp llfloateranimpreview.cpp llfloaterauction.cpp - llfloateravatarinfo.cpp llfloateravatarpicker.cpp llfloateravatartextures.cpp llfloaterbeacons.cpp @@ -137,48 +150,42 @@ set(viewer_SOURCE_FILES llfloaterbuy.cpp llfloaterbuycurrency.cpp llfloaterbuyland.cpp + llfloatercall.cpp llfloatercamera.cpp llfloaterchat.cpp llfloaterchatterbox.cpp - llfloaterclassified.cpp llfloatercolorpicker.cpp llfloatercustomize.cpp llfloaterdaycycle.cpp llfloaterdirectory.cpp - llfloatereditui.cpp llfloaterenvsettings.cpp - llfloaterevent.cpp + llfloaterfirsttimetip.cpp llfloaterfriends.cpp llfloaterfonttest.cpp llfloatergesture.cpp llfloatergodtools.cpp - llfloatergroupinfo.cpp llfloatergroupinvite.cpp llfloatergroups.cpp llfloaterhandler.cpp llfloaterhardwaresettings.cpp - llfloaterhtml.cpp llfloaterhtmlcurrency.cpp - llfloaterhtmlhelp.cpp + llfloatermediabrowser.cpp llfloaterhtmlsimple.cpp llfloaterhud.cpp llfloaterimagepreview.cpp llfloaterinspect.cpp + llfloaterinventory.cpp llfloaterjoystick.cpp llfloaterlagmeter.cpp llfloaterland.cpp llfloaterlandholdings.cpp - llfloaterlandmark.cpp llfloatermap.cpp llfloatermemleak.cpp llfloatermute.cpp llfloaternamedesc.cpp - llfloaternewim.cpp llfloaternotificationsconsole.cpp - llfloaterobjectiminfo.cpp llfloateropenobject.cpp llfloaterparcel.cpp - llfloaterpermissionsmgr.cpp llfloaterperms.cpp llfloaterpostcard.cpp llfloaterpostprocess.cpp @@ -190,25 +197,28 @@ set(viewer_SOURCE_FILES llfloatersellland.cpp llfloatersettingsdebug.cpp llfloatersnapshot.cpp - llfloaterstats.cpp llfloatertelehub.cpp - llfloatertest.cpp + llfloatertestlistview.cpp llfloatertools.cpp llfloatertopobjects.cpp llfloatertos.cpp + llfloateruipreview.cpp llfloaterurldisplay.cpp llfloaterurlentry.cpp llfloatervoicedevicesettings.cpp llfloaterwater.cpp llfloaterwindlight.cpp llfloaterworldmap.cpp + llfoldertype.cpp llfolderview.cpp + llfolderviewitem.cpp llfollowcam.cpp - llframestats.cpp - llframestatview.cpp + llfriendcard.cpp llgesturemgr.cpp llgivemoney.cpp llglsandbox.cpp + llgroupactions.cpp + llgrouplist.cpp llgroupmgr.cpp llgroupnotify.cpp llhomelocationresponder.cpp @@ -224,15 +234,24 @@ set(viewer_SOURCE_FILES llhudrender.cpp llhudtext.cpp llhudview.cpp + llimhandler.cpp llimpanel.cpp llimview.cpp - llinventoryactions.cpp + llimcontrolpanel.cpp + llinspectavatar.cpp llinventorybridge.cpp llinventoryclipboard.cpp + llinventoryfilter.cpp llinventorymodel.cpp - llinventoryview.cpp lljoystickbutton.cpp + lllandmarkactions.cpp lllandmarklist.cpp + lllistbrowser.cpp + lllistview.cpp + lllocaltextureobject.cpp + lllocationhistory.cpp + lllocationinputctrl.cpp + llurllineeditorctrl.cpp lllogchat.cpp llloginhandler.cpp llmanip.cpp @@ -243,6 +262,7 @@ set(viewer_SOURCE_FILES llmediaremotectrl.cpp llmemoryview.cpp llmenucommands.cpp + llmetricperformancetester.cpp llmimetypes.cpp llmorphview.cpp llmoveview.cpp @@ -250,15 +270,25 @@ set(viewer_SOURCE_FILES llnamebox.cpp llnameeditor.cpp llnamelistctrl.cpp + llnavigationbar.cpp + llnearbychat.cpp + llnearbychatbar.cpp + llnearbychathandler.cpp llnetmap.cpp + llnotificationalerthandler.cpp + llnotificationgrouphandler.cpp + llnotificationinfohandler.cpp + llnotificationmanager.cpp llnotify.cpp + lloutputmonitorctrl.cpp lloverlaybar.cpp - llpanelaudioprefs.cpp - llpanelaudiovolume.cpp + llpanelappearance.cpp + llpanelappearancetab.cpp llpanelavatar.cpp + llpanelavatarrow.cpp + llpanelavatartag.cpp llpanelclassified.cpp llpanelcontents.cpp - llpaneldebug.cpp llpaneldirbrowser.cpp llpaneldirclassified.cpp llpaneldirevents.cpp @@ -267,72 +297,90 @@ set(viewer_SOURCE_FILES llpaneldirland.cpp llpaneldirpeople.cpp llpaneldirplaces.cpp - llpaneldirpopular.cpp - llpaneldisplay.cpp llpanelevent.cpp llpanelface.cpp - llpanelgeneral.cpp llpanelgroup.cpp llpanelgroupgeneral.cpp llpanelgroupinvite.cpp llpanelgrouplandmoney.cpp llpanelgroupnotices.cpp llpanelgrouproles.cpp - llpanelinput.cpp llpanelinventory.cpp + llpanelimcontrolpanel.cpp llpanelland.cpp + llpanellandaudio.cpp + llpanellandmarks.cpp llpanellandmedia.cpp - llpanellandobjects.cpp - llpanellandoptions.cpp llpanellogin.cpp - llpanelmorph.cpp - llpanelmsgs.cpp - llpanelnetwork.cpp + llpanellookinfo.cpp + llpanellooks.cpp + llpanelmedia.cpp + llpanelmediahud.cpp + llpanelmeprofile.cpp + llpanelmovetip.cpp llpanelobject.cpp + llpanelpeople.cpp llpanelpermissions.cpp llpanelpick.cpp + llpanelpicks.cpp llpanelplace.cpp - llpanelskins.cpp + llpanelplaceinfo.cpp + llpanelplaces.cpp + llpanelplacestab.cpp + llpanelprofile.cpp + llpanelprofileview.cpp + llpanelteleporthistory.cpp llpanelvolume.cpp - llpanelweb.cpp llparcelselection.cpp llpatchvertexarray.cpp llpolymesh.cpp llpolymorph.cpp - llprefschat.cpp - llprefsim.cpp - llprefsvoice.cpp llpreviewanim.cpp llpreview.cpp llpreviewgesture.cpp - llpreviewlandmark.cpp llpreviewnotecard.cpp llpreviewscript.cpp llpreviewsound.cpp llpreviewtexture.cpp llproductinforequest.cpp llprogressview.cpp + llrecentpeople.cpp llregionposition.cpp llremoteparcelrequest.cpp llsavedsettingsglue.cpp + llscreenchannel.cpp llselectmgr.cpp + llsidetray.cpp + llsidetraypanelcontainer.cpp llsky.cpp + llslurl.cpp llspatialpartition.cpp + llsplitbutton.cpp llsprite.cpp llsrv.cpp llstartup.cpp - llstatbar.cpp - llstatgraph.cpp llstatusbar.cpp - llstatview.cpp llstylemap.cpp llsurface.cpp llsurfacepatch.cpp + llsyswellitem.cpp + llsyswellwindow.cpp + llteleporthistory.cpp + llteleporthistorystorage.cpp + lltexglobalcolor.cpp lltexlayer.cpp + lltexlayerparams.cpp lltexturecache.cpp lltexturectrl.cpp lltexturefetch.cpp lltextureview.cpp + lltoast.cpp + lltoastalertpanel.cpp + lltoastgroupnotifypanel.cpp + lltoastimpanel.cpp + lltoastnotifypanel.cpp + lltoastpanel.cpp + lltoggleablemenu.cpp lltoolbar.cpp lltoolbrush.cpp lltoolcomp.cpp @@ -352,9 +400,7 @@ set(viewer_SOURCE_FILES lltoolselect.cpp lltoolselectland.cpp lltoolselectrect.cpp - lltoolview.cpp lltracker.cpp - lltrans.cpp lluploaddialog.cpp llurl.cpp llurldispatcher.cpp @@ -363,17 +409,15 @@ set(viewer_SOURCE_FILES llurlwhitelist.cpp lluserauth.cpp llvectorperfoptions.cpp - llvelocitybar.cpp llviewchildren.cpp llviewerassetstorage.cpp llvieweraudio.cpp llviewercamera.cpp llviewercontrol.cpp llviewerdisplay.cpp + llviewerfloaterreg.cpp llviewergenericmessage.cpp - llviewergesture.cpp - llviewerimage.cpp - llviewerimagelist.cpp + llviewergesture.cpp llviewerinventory.cpp llviewerjointattachment.cpp llviewerjoint.cpp @@ -385,6 +429,8 @@ set(viewer_SOURCE_FILES llviewerkeyboard.cpp llviewerlayer.cpp llviewermedia.cpp + llviewermediafocus.cpp + llviewermedia_streamingaudio.cpp llviewermenu.cpp llviewermenufile.cpp llviewermessage.cpp @@ -401,7 +447,9 @@ set(viewer_SOURCE_FILES llviewershadermgr.cpp llviewerstats.cpp llviewertexteditor.cpp + llviewertexture.cpp llviewertextureanim.cpp + llviewertexturelist.cpp llviewerthrottle.cpp llviewervisualparam.cpp llviewerwindow.cpp @@ -409,6 +457,7 @@ set(viewer_SOURCE_FILES llvlmanager.cpp llvoavatar.cpp llvoavatardefines.cpp + llvoavatarself.cpp llvocache.cpp llvoclouds.cpp llvograss.cpp @@ -416,6 +465,7 @@ set(viewer_SOURCE_FILES llvoiceclient.cpp llvoiceremotectrl.cpp llvoicevisualizer.cpp + llvoicecontrolpanel.cpp llvoinventorylistener.cpp llvopartgroup.cpp llvosky.cpp @@ -429,9 +479,10 @@ set(viewer_SOURCE_FILES llwaterparammanager.cpp llwaterparamset.cpp llwearable.cpp + llwearabledictionary.cpp llwearablelist.cpp llweb.cpp - llwebbrowserctrl.cpp + llmediactrl.cpp llwind.cpp llwlanimator.cpp llwldaycycle.cpp @@ -465,38 +516,48 @@ endif (LINUX) set(viewer_HEADER_FILES CMakeLists.txt ViewerInstall.cmake - + llaccordionctrltab.h + llaccordionctrl.h + llactiveimwindow.h llagent.h llagentaccess.h llagentdata.h llagentlanguage.h llagentpilot.h + llagentui.h + llagentwearables.h llanimstatelabels.h llappearance.h llappviewer.h llassetuploadresponders.h llassetuploadqueue.h llaudiosourcevo.h - llbbox.h + llavataractions.h + llavatariconctrl.h + llavatarlist.h + llavatarlistitem.h + llavatarpropertiesprocessor.h + llbottomtray.h llbox.h + llbreadcrumbview.h llcallbacklist.h llcallingcard.h llcapabilitylistener.h llcapabilityprovider.h llcaphttpsender.h + llchannelmanager.h llchatbar.h + llchatitemscontainerctrl.h + llchatmsgbox.h + llchiclet.h llclassifiedinfo.h llclassifiedstatsresponder.h llcloud.h - llcolorscheme.h llcolorswatch.h llcommandhandler.h llcommandlineparser.h - llcompass.h llcompilequeue.h llconfirmationmanager.h - llconsole.h - llcontainerview.h llcurrencyuimanager.h llcylinder.h lldebugmessagebox.h @@ -524,15 +585,16 @@ set(viewer_HEADER_FILES lleventpoll.h llface.h llfasttimerview.h + llfavoritesbar.h llfeaturemanager.h llfilepicker.h llfirstuse.h + llfirsttimetipmanager.h llflexibleobject.h llfloaterabout.h llfloateractivespeakers.h llfloateranimpreview.h llfloaterauction.h - llfloateravatarinfo.h llfloateravatarpicker.h llfloateravatartextures.h llfloaterbeacons.h @@ -543,48 +605,42 @@ set(viewer_HEADER_FILES llfloaterbuycontents.h llfloaterbuycurrency.h llfloaterbuyland.h + llfloatercall.h llfloatercamera.h llfloaterchat.h llfloaterchatterbox.h - llfloaterclassified.h llfloatercolorpicker.h llfloatercustomize.h llfloaterdaycycle.h llfloaterdirectory.h - llfloatereditui.h llfloaterenvsettings.h - llfloaterevent.h + llfloaterfirsttimetip.h llfloaterfonttest.h llfloaterfriends.h llfloatergesture.h llfloatergodtools.h - llfloatergroupinfo.h llfloatergroupinvite.h llfloatergroups.h llfloaterhandler.h llfloaterhardwaresettings.h - llfloaterhtml.h llfloaterhtmlcurrency.h - llfloaterhtmlhelp.h + llfloatermediabrowser.h llfloaterhtmlsimple.h llfloaterhud.h llfloaterimagepreview.h llfloaterinspect.h + llfloaterinventory.h llfloaterjoystick.h llfloaterlagmeter.h llfloaterland.h llfloaterlandholdings.h - llfloaterlandmark.h llfloatermap.h llfloatermemleak.h llfloatermute.h llfloaternamedesc.h - llfloaternewim.h llfloaternotificationsconsole.h - llfloaterobjectiminfo.h llfloateropenobject.h llfloaterparcel.h - llfloaterpermissionsmgr.h llfloaterpostcard.h llfloaterpostprocess.h llfloaterpreference.h @@ -596,24 +652,28 @@ set(viewer_HEADER_FILES llfloatersellland.h llfloatersettingsdebug.h llfloatersnapshot.h - llfloaterstats.h llfloatertelehub.h - llfloatertest.h + llfloatertestlistview.h llfloatertools.h llfloatertopobjects.h llfloatertos.h + llfloateruipreview.h llfloaterurldisplay.h llfloaterurlentry.h llfloatervoicedevicesettings.h llfloaterwater.h llfloaterwindlight.h llfloaterworldmap.h + llfoldertype.h llfolderview.h + llfoldervieweventlistener.h + llfolderviewitem.h llfollowcam.h - llframestats.h - llframestatview.h + llfriendcard.h llgesturemgr.h llgivemoney.h + llgroupactions.h + llgrouplist.h llgroupmgr.h llgroupnotify.h llhomelocationresponder.h @@ -631,13 +691,22 @@ set(viewer_HEADER_FILES llhudview.h llimpanel.h llimview.h + llimcontrolpanel.h + llinspectavatar.h llinventorybridge.h llinventoryclipboard.h + llinventoryfilter.h llinventorymodel.h - llinventoryview.h lljoystickbutton.h + lllandmarkactions.h lllandmarklist.h lllightconstants.h + lllistbrowser.h + lllistview.h + lllocaltextureobject.h + lllocationhistory.h + lllocationinputctrl.h + llurllineeditorctrl.h lllogchat.h llloginhandler.h llmanip.h @@ -648,6 +717,7 @@ set(viewer_HEADER_FILES llmediaremotectrl.h llmemoryview.h llmenucommands.h + llmetricperformancetester.h llmimetypes.h llmorphview.h llmoveview.h @@ -655,15 +725,23 @@ set(viewer_HEADER_FILES llnamebox.h llnameeditor.h llnamelistctrl.h + llnavigationbar.h + llnearbychat.h + llnearbychatbar.h + llnearbychathandler.h llnetmap.h + llnotificationhandler.h + llnotificationmanager.h llnotify.h + lloutputmonitorctrl.h lloverlaybar.h - llpanelaudioprefs.h - llpanelaudiovolume.h + llpanelappearance.h + llpanelappearancetab.h llpanelavatar.h + llpanelavatarrow.h + llpanelavatartag.h llpanelclassified.h llpanelcontents.h - llpaneldebug.h llpaneldirbrowser.h llpaneldirclassified.h llpaneldirevents.h @@ -672,75 +750,93 @@ set(viewer_HEADER_FILES llpaneldirland.h llpaneldirpeople.h llpaneldirplaces.h - llpaneldirpopular.h - llpaneldisplay.h llpanelevent.h llpanelface.h - llpanelgeneral.h llpanelgroup.h llpanelgroupgeneral.h llpanelgroupinvite.h llpanelgrouplandmoney.h llpanelgroupnotices.h llpanelgrouproles.h - llpanelinput.h llpanelinventory.h + llpanelimcontrolpanel.h llpanelland.h + llpanellandaudio.h + llpanellandmarks.h llpanellandmedia.h - llpanellandobjects.h - llpanellandoptions.h - llpanelLCD.h llpanellogin.h - llpanelmorph.h - llpanelmsgs.h - llpanelnetwork.h + llpanellookinfo.h + llpanellooks.h + llpanelmedia.h + llpanelmediahud.h + llpanelmeprofile.h + llpanelmovetip.h llpanelobject.h + llpanelpeople.h llpanelpermissions.h llpanelpick.h + llpanelpicks.h llpanelplace.h - llpanelskins.h + llpanelplaceinfo.h + llpanelplaces.h + llpanelplacestab.h + llpanelprofile.h + llpanelprofileview.h + llpanelteleporthistory.h llpanelvolume.h - llpanelweb.h llparcelselection.h llpatchvertexarray.h llpolymesh.h llpolymorph.h - llprefschat.h - llprefsim.h - llprefsvoice.h llpreview.h llpreviewanim.h llpreviewgesture.h - llpreviewlandmark.h llpreviewnotecard.h llpreviewscript.h llpreviewsound.h llpreviewtexture.h llproductinforequest.h llprogressview.h + llrecentpeople.h llregionposition.h llremoteparcelrequest.h llresourcedata.h + llrootview.h + llscreenchannel.h llsavedsettingsglue.h llselectmgr.h + llsidetray.h + llsidetraypanelcontainer.h llsky.h + llslurl.h llspatialpartition.h + llsplitbutton.h llsprite.h llsrv.h llstartup.h - llstatbar.h - llstatgraph.h llstatusbar.h - llstatview.h llstylemap.h llsurface.h llsurfacepatch.h + llsyswellitem.h + llsyswellwindow.h lltable.h + llteleporthistory.h + llteleporthistorystorage.h + lltexglobalcolor.h lltexlayer.h + lltexlayerparams.h lltexturecache.h lltexturectrl.h lltexturefetch.h lltextureview.h + lltoast.h + lltoastalertpanel.h + lltoastgroupnotifypanel.h + lltoastimpanel.h + lltoastnotifypanel.h + lltoastpanel.h + lltoggleablemenu.h lltool.h lltoolbar.h lltoolbrush.h @@ -760,9 +856,7 @@ set(viewer_HEADER_FILES lltoolselect.h lltoolselectland.h lltoolselectrect.h - lltoolview.h lltracker.h - lltrans.h lluiconstants.h lluploaddialog.h llurl.h @@ -772,7 +866,6 @@ set(viewer_HEADER_FILES llurlwhitelist.h lluserauth.h llvectorperfoptions.h - llvelocitybar.h llviewchildren.h llviewerassetstorage.h llvieweraudio.h @@ -780,10 +873,9 @@ set(viewer_HEADER_FILES llviewercamera.h llviewercontrol.h llviewerdisplay.h + llviewerfloaterreg.h llviewergenericmessage.h - llviewergesture.h - llviewerimage.h - llviewerimagelist.h + llviewergesture.h llviewerinventory.h llviewerjoint.h llviewerjointattachment.h @@ -792,6 +884,8 @@ set(viewer_HEADER_FILES llviewerkeyboard.h llviewerlayer.h llviewermedia.h + llviewermediaobserver.h + llviewermediafocus.h llviewermenu.h llviewermenufile.h llviewermessage.h @@ -809,7 +903,9 @@ set(viewer_HEADER_FILES llviewershadermgr.h llviewerstats.h llviewertexteditor.h + llviewertexture.h llviewertextureanim.h + llviewertexturelist.h llviewerthrottle.h llviewervisualparam.h llviewerwindow.h @@ -817,6 +913,7 @@ set(viewer_HEADER_FILES llvlmanager.h llvoavatar.h llvoavatardefines.h + llvoavatarself.h llvocache.h llvoclouds.h llvograss.h @@ -824,6 +921,7 @@ set(viewer_HEADER_FILES llvoiceclient.h llvoiceremotectrl.h llvoicevisualizer.h + llvoicecontrolpanel.h llvoinventorylistener.h llvopartgroup.h llvosky.h @@ -838,9 +936,10 @@ set(viewer_HEADER_FILES llwaterparammanager.h llwaterparamset.h llwearable.h + llwearabledictionary.h llwearablelist.h llweb.h - llwebbrowserctrl.h + llmediactrl.h llwind.h llwindebug.h llwlanimator.h @@ -937,6 +1036,10 @@ if (WINDOWS) ) endforeach( src_file ${viewer_SOURCE_FILES} ) list(APPEND viewer_SOURCE_FILES llviewerprecompiledheaders.cpp) + # llstartup.cpp needs special symbols for audio libraries, so it resets + # COMPILE_FLAGS below. Make sure it maintains precompiled header settings. + set(LLSTARTUP_COMPILE_FLAGS + "${LLSTARTUP_COMPILE_FLAGS} /Yullviewerprecompiledheaders.h") # Add resource files to the project. # viewerRes.rc is the only buildable file, but @@ -1000,12 +1103,11 @@ if (WINDOWS) ) set(viewer_LIBRARIES - advapi32 + ${WINDOWS_LIBRARIES} comdlg32 ${DINPUT_LIBRARY} ${DXGUID_LIBRARY} fmodvc - gdi32 kernel32 odbc32 odbccp32 @@ -1013,7 +1115,6 @@ if (WINDOWS) oleaut32 opengl32 shell32 - user32 Vfw32 winspool ) @@ -1035,16 +1136,21 @@ endif (WINDOWS) # Add the xui files. This is handy for searching for xui elements # from within the IDE. - -file(GLOB viewer_XUI_FILE_GLOB_LIST - ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en-us/*.xml) - set(viewer_XUI_FILES - ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/colors.xml - ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/colors_base.xml - ) + skins/default/colors.xml + skins/default/textures/textures.xml + + + + ) +file(GLOB DEFAULT_XUI_FILE_GLOB_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/*.xml) +list(APPEND viewer_XUI_FILES ${DEFAULT_XUI_FILE_GLOB_LIST}) + +file(GLOB DEFAULT_WIDGET_FILE_GLOB_LIST + ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/widgets/*.xml) +list(APPEND viewer_XUI_FILES ${DEFAULT_WIDGET_FILE_GLOB_LIST}) -list(APPEND viewer_XUI_FILES ${viewer_XUI_FILE_GLOB_LIST}) list(SORT viewer_XUI_FILES) source_group("XUI Files" FILES ${viewer_XUI_FILES}) @@ -1167,8 +1273,10 @@ if (WINDOWS) set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES + # *TODO -reenable this once we get server usage sorted out + #LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\"" LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS" - LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\"" + LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO" LINK_FLAGS_RELEASE ${release_flags} ) @@ -1231,6 +1339,9 @@ if (WINDOWS) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit) + if (PACKAGE) add_custom_target(package ALL DEPENDS ${CMAKE_CFG_INTDIR}/touched.bat) add_dependencies(package windows-updater windows-crash-logger) @@ -1243,8 +1354,8 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLIMAGE_LIBRARIES} ${LLIMAGEJ2COJ_LIBRARIES} ${LLINVENTORY_LIBRARIES} - ${LLMEDIA_LIBRARIES} ${LLMESSAGE_LIBRARIES} + ${LLPLUGIN_LIBRARIES} ${LLPRIMITIVE_LIBRARIES} ${LLRENDER_LIBRARIES} ${FREETYPE_LIBRARIES} @@ -1252,6 +1363,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLVFS_LIBRARIES} ${LLWINDOW_LIBRARIES} ${LLXML_LIBRARIES} + ${LLXUIXML_LIBRARIES} ${LSCRIPT_LIBRARIES} ${LLMATH_LIBRARIES} ${LLCOMMON_LIBRARIES} @@ -1263,14 +1375,13 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${OPENGL_LIBRARIES} ${FMODWRAPPER_LIBRARY} ${OPENGL_LIBRARIES} - ${MOZLIB_LIBRARIES} ${SDL_LIBRARY} ${SMARTHEAP_LIBRARY} ${UI_LIBRARIES} - ${QUICKTIME_LIBRARY} ${WINDOWS_LIBRARIES} ${XMLRPCEPI_LIBRARIES} ${ELFIO_LIBRARIES} + ${GOOGLE_PERFTOOLS_LIBRARIES} ) build_version(viewer) @@ -1307,9 +1418,12 @@ if (LINUX) DEPENDS secondlife-stripped ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit) + if (NOT INSTALL) add_custom_target(package ALL DEPENDS ${product}.tar.bz2) add_dependencies(package linux-crash-logger-strip-target) + add_dependencies(package linux-updater-strip-target) endif (NOT INSTALL) endif (LINUX) @@ -1344,6 +1458,8 @@ if (DARWIN) DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py ) + add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_quicktime media_plugin_webkit) + if (PACKAGE) add_custom_target(package ALL DEPENDS ${VIEWER_BINARY_NAME}) add_dependencies(package mac-updater mac-crash-logger) @@ -1408,3 +1524,69 @@ set_source_files_properties( ) LL_ADD_PROJECT_UNIT_TESTS(${VIEWER_BINARY_NAME} "${viewer_TEST_SOURCE_FILES}") +#set(TEST_DEBUG on) +set(test_sources llcapabilitylistener.cpp llviewerprecompiledheaders.cpp) +set(test_libs + ${LLMESSAGE_LIBRARIES} + ${WINDOWS_LIBRARIES} + ${LLVFS_LIBRARIES} + ${LLMATH_LIBRARIES} + ${LLCOMMON_LIBRARIES} + ) + +LL_ADD_INTEGRATION_TEST(llcapabilitylistener + "${test_sources}" + "${test_libs}" + ${PYTHON_EXECUTABLE} + "${CMAKE_SOURCE_DIR}/llmessage/tests/test_llsdmessage_peer.py" + ) + +#ADD_VIEWER_BUILD_TEST(llmemoryview viewer) + + +# Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py +if (WINDOWS) + get_target_property(BUILT_SLPLUGIN SLPlugin LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_SLPLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + COMMENT "Copying SLPlugin executable to the runtime folder." + ) + + get_target_property(BUILT_WEBKIT_PLUGIN media_plugin_webkit LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_WEBKIT_PLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + COMMENT "Copying WebKit Plugin to the runtime folder." + ) + + get_target_property(BUILT_QUICKTIME_PLUGIN media_plugin_quicktime LOCATION) + add_custom_command( + TARGET ${VIEWER_BINARY_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} + ARGS + -E + copy_if_different + ${BUILT_QUICKTIME_PLUGIN} + ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin + COMMENT "Copying Quicktime Plugin to the runtime folder." + ) +endif (WINDOWS) + +if (DARWIN) +# Don't do this here -- it's taken care of by viewer_manifest.py +# add_custom_command(TARGET ${VIEWER_BINARY_NAME} POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/llplugin/ +# DEPENDS ${CMAKE_SOURCE_DIR}/../libraries/universal-darwin/lib_release/libllqtwebkit.dylib +# ) +endif (DARWIN) diff --git a/indra/newview/English.lproj/InfoPlist.strings b/indra/newview/English.lproj/InfoPlist.strings index 8263a2381e..735424c647 100644 --- a/indra/newview/English.lproj/InfoPlist.strings +++ b/indra/newview/English.lproj/InfoPlist.strings @@ -2,6 +2,6 @@ CFBundleName = "Second Life"; -CFBundleShortVersionString = "Second Life version 1.24.4.0"; -CFBundleGetInfoString = "Second Life version 1.24.4.0, Copyright 2004-2008 Linden Research, Inc."; +CFBundleShortVersionString = "Second Life version 2.0.0.0"; +CFBundleGetInfoString = "Second Life version 2.0.0.0, Copyright 2004-2009 Linden Research, Inc."; diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index ba7e7965cd..7264044d37 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -32,7 +32,7 @@ CFBundleVersion - 1.24.4.0 + 2.0.0.0 CSResourcesFileMapped diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml index 5f11ed8e22..5f143431de 100644 --- a/indra/newview/app_settings/cmd_line.xml +++ b/indra/newview/app_settings/cmd_line.xml @@ -106,6 +106,54 @@ QuitAfterSeconds + logperformance + + desc + Log performance metrics for benchmarking + map-to + LogPerformance + + + logmetrics + + desc + Log metrics for benchmarking + map-to + LogMetrics + + + analyzeperformance + + desc + When used in conjunction with logperformance, analyzes result of log against baseline. + map-to + AnalyzePerformance + + + debugsession + + desc + Run as if RenderDebugGL is TRUE, but log errors until end of session. + map-to + DebugSession + + + replaysession + + desc + After login, replay last recorded session and quit. + map-to + ReplaySession + + + nonotifications + + desc + User will not get any notifications. NOTE: All notifications that occur will get added to ignore file for future runs. + map-to + IgnoreAllNotifications + + rotate map-to @@ -166,6 +214,16 @@ UserLogFile + graphicslevel + + desc + Set the detail level. + 0 - low, 1 - medium, 2 - high, 3 - ultra + + count + 1 + + setdefault desc diff --git a/indra/newview/app_settings/foldertypes.xml b/indra/newview/app_settings/foldertypes.xml new file mode 100644 index 0000000000..698158308e --- /dev/null +++ b/indra/newview/app_settings/foldertypes.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + diff --git a/indra/newview/app_settings/ignorable_dialogs.xml b/indra/newview/app_settings/ignorable_dialogs.xml new file mode 100644 index 0000000000..669235af1b --- /dev/null +++ b/indra/newview/app_settings/ignorable_dialogs.xml @@ -0,0 +1,291 @@ + + + + FirstAppearance + + Comment + Enables FirstAppearance warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstAttach + + Comment + Enables FirstAttach warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBalanceDecrease + + Comment + Enables FirstBalanceDecrease warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBalanceIncrease + + Comment + Enables FirstBalanceIncrease warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstBuild + + Comment + Enables FirstBuild warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstDebugMenus + + Comment + Enables FirstDebugMenus warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstFlexible + + Comment + Enables FirstFlexible warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstGoTo + + Comment + Enables FirstGoTo warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstInventory + + Comment + Enables FirstInventory warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstLeftClickNoHit + + Comment + Enables FirstLeftClickNoHit warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstMap + + Comment + Enables FirstMap warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstMedia + + Comment + Enables FirstMedia warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstOverrideKeys + + Comment + Enables FirstOverrideKeys warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSandbox + + Comment + Enables FirstSandbox warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSculptedPrim + + Comment + Enables FirstSculptedPrim warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstSit + + Comment + Enables FirstSit warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstStreamingMusic + + Comment + Enables FirstStreamingMusic warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstStreamingVideo + + Comment + Enables FirstStreamingVideo warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstTeleport + + Comment + Enables FirstTeleport warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + FirstVoice + + Comment + Enables FirstVoice warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + AboutDirectX9 + + Comment + Enables AboutDirectX9 warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + BrowserLaunch + + Comment + Enables BrowserLaunch warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + DeedObject + + Comment + Enables DeedObject warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + NewClassified + + Comment + Enables NewClassified warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + QuickTimeInstalled + + Comment + Enables QuickTimeInstalled warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + ReturnToOwner + + Comment + Enables ReturnToOwner warning dialog + Persist + 1 + Type + Boolean + Value + 1 + + + diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 5ebf14d093..4e2f836606 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -23,38 +23,6 @@ Value 0 - UserChatColor - - Comment - Color of your chat messages - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - AgentChatColor - - Comment - Color of chat messages from other residents - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - AlertedUnsupportedHardware Comment @@ -198,17 +166,6 @@ Value 0.5 - AudioLevelDistance - - Comment - Scale factor for audio engine (multiple of world scale, 2.0 = audio falls off twice as fast) - Persist - 1 - Type - F32 - Value - 1.0 - AudioLevelDoppler Comment @@ -307,6 +264,17 @@ F32 Value 0.5 + + AudioSteamingMedia + + Comment + Enable streaming + Persist + 1 + Type + Boolean + Value + 0 AudioStreamingMusic @@ -594,22 +562,6 @@ Value 0 - BackgroundChatColor - - Comment - Color of chat bubble background - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.0 - 0.0 - 1.0 - - BackgroundYieldTime Comment @@ -621,42 +573,10 @@ Value 40 - BackwardBtnRect + BottomPanelNew Comment - - Persist - 0 - Type - Rect - Value - - 45 - 29 - 66 - 4 - - - BasicHelpRect - - Comment - Rectangle for help window - Persist - 1 - Type - Rect - Value - - 0 - 404 - 467 - 0 - - - BeaconAlwaysOn - - Comment - Beacons / highlighting always on + Enable the new bottom panel Persist 1 Type @@ -884,6 +804,17 @@ Value 0 + BuildBtnEnabled + + Comment + + Persist + 0 + Type + Boolean + Value + 0 + BuildFeathering Comment @@ -972,17 +903,6 @@ Value 1 - BulkChangeIncludeLandmarks - - Comment - Bulk permission changes affect landmarks - Persist - 1 - Type - Boolean - Value - 1 - BulkChangeIncludeNotecards Comment @@ -1170,6 +1090,28 @@ Value + CacheLocationTopFolder + + Comment + Controls the top folder location of the local disk cache + Persist + 1 + Type + String + Value + + + CacheLocationTopFolder + + Comment + Controls the location of the local disk cache + Persist + 1 + Type + String + Value + + CacheSize Comment @@ -1240,10 +1182,10 @@ 6.0 - CameraOffsetDefault + CameraOffsetRearView Comment - Default camera offset from avatar + Initial camera offset from avatar in Rear View Persist 1 Type @@ -1255,6 +1197,36 @@ 0.75 + CameraOffsetFrontView + + Comment + Initial camera offset from avatar in Front View + Persist + 1 + Type + Vector3 + Value + + 2.2 + 0.0 + 0.0 + + + CameraOffsetGroupView + + Comment + Initial camera offset from avatar in Group View + Persist + 1 + Type + Vector3 + Value + + -1.0 + 0.7 + 0.5 + + CameraOffsetScale Comment @@ -1292,6 +1264,17 @@ Value 1.0 + CameraPreset + + Comment + Preset camera position - view (0 - rear, 1 - front, 2 - group) + Persist + 1 + Type + U32 + Value + 0 + ChatBarStealsFocus Comment @@ -1391,22 +1374,6 @@ Value 1 - ChatterboxRect - - Comment - Rectangle for chatterbox window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 350 - 0 - - CheesyBeacon Comment @@ -1421,7 +1388,7 @@ ClientSettingsFile Comment - Persisted client settings file name (per install). + Client settings file name (per install). Persist 0 Type @@ -1497,545 +1464,17 @@ - ColorPaletteEntry01 + CompressSnapshotsToDisk Comment - Color picker palette entry + Compress snapshots saved to disk (Using JPEG 2000) Persist 1 Type - Color4 + Boolean Value - - 0.0 - 0.0 - 0.0 - 1.0 - - - ColorPaletteEntry02 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.5 - 0.5 - 1.0 - - - ColorPaletteEntry03 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.0 - 0.0 - 1.0 - - - ColorPaletteEntry04 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.5 - 0.0 - 1.0 - - - ColorPaletteEntry05 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.5 - 0.0 - 1.0 - - - ColorPaletteEntry06 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.5 - 0.5 - 1.0 - - - ColorPaletteEntry07 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.0 - 0.5 - 1.0 - - - ColorPaletteEntry08 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.0 - 0.5 - 1.0 - - - ColorPaletteEntry09 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.5 - 0.0 - 1.0 - - - ColorPaletteEntry10 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.25 - 0.25 - 1.0 - - - ColorPaletteEntry11 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.5 - 1.0 - 1.0 - - - ColorPaletteEntry12 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.25 - 0.5 - 1.0 - - - ColorPaletteEntry13 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.0 - 1.0 - 1.0 - - - ColorPaletteEntry14 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.25 - 0.0 - 1.0 - - - ColorPaletteEntry15 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry16 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry17 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry18 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.75 - 0.75 - 0.75 - 1.0 - - - ColorPaletteEntry19 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 0.0 - 0.0 - 1.0 - - - ColorPaletteEntry20 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 0.0 - 1.0 - - - ColorPaletteEntry21 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 1.0 - 0.0 - 1.0 - - - ColorPaletteEntry22 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry23 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 0.0 - 1.0 - 1.0 - - - ColorPaletteEntry24 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 0.0 - 1.0 - 1.0 - - - ColorPaletteEntry25 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 0.5 - 1.0 - - - ColorPaletteEntry26 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.0 - 1.0 - 0.5 - 1.0 - - - ColorPaletteEntry27 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry28 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 0.5 - 0.5 - 1.0 - 1.0 - - - ColorPaletteEntry29 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 0.0 - 0.5 - 1.0 - - - ColorPaletteEntry30 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 0.5 - 0.0 - 1.0 - - - ColorPaletteEntry31 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - ColorPaletteEntry32 - - Comment - Color picker palette entry - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - - ColumnHeaderDropDownDelay - - Comment - Time in seconds of mouse click before column header shows sort options list - Persist - 1 - Type - F32 - Value - 0.300000011921 - - CompileOutputRect - - Comment - Rectangle for script Recompile Everything output window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 300 - 0 - - + 0 + ConnectAsGod Comment @@ -2223,6 +1662,17 @@ Value 0 + DebugPluginDisableTimeout + + Comment + Disable the code which watches for plugins that are crashed or hung + Persist + 1 + Type + Boolean + Value + 0 + DebugShowColor Comment @@ -3136,22 +2586,6 @@ Value 0 - EffectColor - - Comment - Particle effects color - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - EnableRippleWater Comment @@ -3361,6 +2795,28 @@ Value 1 + FirstSelectedDisabledPopups + + Comment + Return false if there is not disabled popup selected in the list of floater preferences popups + Persist + 0 + Type + Boolean + Value + 0 + + FirstSelectedEnabledPopups + + Comment + Return false if there is not enable popup selected in the list of floater preferences popups + Persist + 0 + Type + Boolean + Value + 0 + FixedWeather Comment @@ -3372,38 +2828,6 @@ Value 0 - FloaterAboutRect - - Comment - Rectangle for About window - Persist - 1 - Type - Rect - Value - - 0 - 440 - 470 - 0 - - - FloaterActiveSpeakersRect - - Comment - Rectangle for active speakers window - Persist - 1 - Type - Rect - Value - - 0 - 300 - 250 - 0 - - FloaterActiveSpeakersSortAscending Comment @@ -3426,618 +2850,95 @@ Value speaking_status - FloaterAdvancedSkyRect + FloaterMapNorth Comment - Rectangle for Advanced Sky Editor + Floater Map North Label Persist 1 Type - Rect + String Value - - 0 - 220 - 700 - 0 - + N - FloaterAdvancedWaterRect + FloaterMapNorthEast Comment - Rectangle for Advanced Water Editor + Floater Map North-East Label Persist 1 Type - Rect + String Value - - 0 - 240 - 700 - 0 - + NE - FloaterAudioVolumeRect + FloaterMapNorthWest Comment - Rectangle for Audio Volume window + Floater Map North-West Label Persist 1 Type - Rect + String Value - - 0 - 440 - 470 - 0 - + NW - FloaterBeaconsRect - - Comment - Rectangle for beacon and highlight controls - Persist - 1 - Type - Rect - Value - - 200 - 250 - 250 - 200 - - - FloaterBuildOptionsRect + FloaterMapEast Comment - Rectangle for build options window. + Floater Map East Label Persist 1 Type - Rect + String Value - - 0 - 0 - 0 - 0 - + E - FloaterBumpRect + FloaterMapWest Comment - Rectangle for Bumps/Hits window + Floater Map West Label Persist 1 Type - Rect + String Value - - 0 - 180 - 400 - 0 - + W - FloaterBuyContentsRect + FloaterMapSouth Comment - Rectangle for Buy Contents window + Floater Map South Label Persist 1 Type - Rect + String Value - - 0 - 250 - 300 - 0 - + S - FloaterBuyRect + FloaterMapSouthEast Comment - Rectangle for buy window + Floater Map South-East Label Persist 1 Type - Rect + String Value - - 0 - 250 - 300 - 0 - + SE - FloaterCameraRect3 + FloaterMapSouthWest Comment - Rectangle for camera control window + Floater Map South-West Label Persist 1 Type - Rect + String Value - - 0 - 64 - 176 - 0 - - - FloaterChatRect - - Comment - Rectangle for chat history - Persist - 1 - Type - Rect - Value - - 0 - 172 - 500 - 0 - - - FloaterClothingRect - - Comment - Rectangle for clothing window - Persist - 1 - Type - Rect - Value - - 0 - 480 - 320 - 0 - - - FloaterContactsRect - - Comment - Rectangle for chat history - Persist - 1 - Type - Rect - Value - - 0 - 390 - 395 - 0 - - - FloaterCustomizeAppearanceRect - - Comment - Rectangle for avatar customization window - Persist - 1 - Type - Rect - Value - - 0 - 540 - 494 - 0 - - - FloaterDayCycleRect - - Comment - Rectangle for Day Cycle Editor - Persist - 1 - Type - Rect - Value - - 0 - 646 - 275 - 0 - - - FloaterEnvRect - - Comment - Rectangle for Environment Editor - Persist - 1 - Type - Rect - Value - - 0 - 150 - 600 - 0 - - - FloaterFindRect2 - - Comment - Rectangle for Find window - Persist - 1 - Type - Rect - Value - - 0 - 570 - 780 - 0 - - - FloaterFriendsRect - - Comment - Rectangle for friends window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 250 - 0 - - - FloaterGestureRect2 - - Comment - Rectangle for gestures window - Persist - 1 - Type - Rect - Value - - 0 - 465 - 350 - 0 - - - FloaterHUDRect2 - - Comment - Rectangle for HUD Floater window - Persist - 1 - Type - Rect - Value - - - 0 - 292 - 362 - 0 - - - FloaterHtmlRect - - Comment - Rectangle for HTML window - Persist - 1 - Type - Rect - Value - - 100 - 460 - 370 - 100 - - - FloaterIMRect - - Comment - Rectangle for IM window - Persist - 1 - Type - Rect - Value - - 0 - 160 - 500 - 0 - - - FloaterInspectRect - - Comment - Rectangle for Object Inspect window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 400 - 0 - - - FloaterInventoryRect - - Comment - Rectangle for inventory window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 300 - 0 - - - FloaterJoystickRect - - Comment - Rectangle for joystick controls window. - Persist - 1 - Type - Rect - Value - - 0 - 0 - 0 - 0 - - - FloaterLagMeter - - Comment - Rectangle for lag meter - Persist - 1 - Type - Rect - Value - - 0 - 142 - 350 - 0 - - - FloaterLandRect5 - - Comment - Rectangle for About Land window - Persist - 1 - Type - Rect - Value - - 0 - 370 - 460 - 0 - - - FloaterLandmarkRect - - Comment - Rectangle for landmark picker - Persist - 1 - Type - Rect - Value - - 0 - 290 - 310 - 0 - - - FloaterMediaRect - - Comment - Rectangle for media browser window - Persist - 1 - Type - Rect - Value - - 16 - 650 - 600 - 128 - - - FloaterMiniMapRect - - Comment - Rectangle for world map - Persist - 1 - Type - Rect - Value - - 0 - 225 - 200 - 0 - - - FloaterMoveRect2 - - Comment - Rectangle for avatar control window - Persist - 1 - Type - Rect - Value - - 0 - 58 - 135 - 0 - - - FloaterMuteRect3 - - Comment - Rectangle for mute window - Persist - 1 - Type - Rect - Value - - 0 - 300 - 300 - 0 - + SW - FloaterObjectIMInfo - - Comment - Rectangle for floater object im info windows - Persist - 1 - Type - Rect - Value - - 0 - 300 - 300 - 0 - - - FloaterOpenObjectRect - - Comment - Rectangle for Open Object window - Persist - 1 - Type - Rect - Value - - 0 - 350 - 300 - 0 - - - FloaterPayRectB - - Comment - Rectangle for pay window - Persist - 1 - Type - Rect - Value - - 0 - 150 - 400 - 0 - - - FloaterPermPrefsRect - - Comment - Rectangle for initial permissions preferences - Persist - 1 - Type - Rect - Value - - 200 - 250 - 250 - 200 - - - FloaterRegionInfo - - Comment - Rectangle for region info window - Persist - 1 - Type - Rect - Value - - 0 - 512 - 480 - 0 - - - FloaterScriptDebugRect - - Comment - Rectangle for Script Error/Debug window - Persist - 1 - Type - Rect - Value - - 0 - 130 - 450 - 0 - - - FloaterSnapshotRect - - Comment - Rectangle for snapshot window - Persist - 1 - Type - Rect - Value - - 0 - 200 - 200 - 400 - - FloaterStatisticsRect Comment @@ -4054,32 +2955,16 @@ 0 - FloaterViewBottom + FlyBtnEnabled Comment - [DO NOT MODIFY] Controls layout of floating windows within SL window + Persist - 1 + 0 Type - S32 + Boolean Value - -1 - - FloaterWorldMapRect2 - - Comment - Rectangle for world map window - Persist 1 - Type - Rect - Value - - 0 - 0 - 0 - 0 - FlyBtnState @@ -4290,14 +3175,14 @@ Value 0 - FocusOffsetDefault + FocusOffsetRearView Comment - Default focus point offset relative to avatar (x-axis is forward) + Initial focus point offset relative to avatar for the camera preset Rear View (x-axis is forward) Persist 1 Type - Vector3 + Vector3D Value 1.0 @@ -4305,6 +3190,36 @@ 1.0 + FocusOffsetFrontView + + Comment + Initial focus point offset relative to avatar for the camera preset Front View + Persist + 1 + Type + Vector3D + Value + + 0.0 + 0.0 + 0.0 + + + FocusOffsetGroupView + + Comment + Initial focus point offset relative to avatar for the camera preset Group View + Persist + 1 + Type + Vector3D + Value + + 1.5 + 0.7 + 1.0 + + FocusPosOnLogout Comment @@ -4496,22 +3411,6 @@ Value 0 - ForwardBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 45 - 54 - 66 - 29 - - FreezeTime Comment @@ -4523,17 +3422,6 @@ Value 0 - FullScreen - - Comment - Run SL in fullscreen mode - Persist - 1 - Type - Boolean - Value - 0 - FullScreenAspectRatio Comment @@ -4676,23 +3564,7 @@ S32 Value 400 - - HTMLLinkColor - - Comment - Color of hyperlinks - Persist - 1 - Type - Color4 - Value - - 0.600000023842 - 0.600000023842 - 1.0 - 1.0 - - + HelpHomeURL Comment @@ -4726,22 +3598,6 @@ Value 0 - HtmlFindRect - - Comment - Rectangle for HTML find window - Persist - 1 - Type - Rect - Value - - 16 - 650 - 600 - 128 - - HtmlHelpLastPage Comment @@ -4753,54 +3609,6 @@ Value - HtmlHelpRect - - Comment - Rectangle for HTML help window - Persist - 1 - Type - Rect - Value - - 16 - 650 - 600 - 128 - - - HtmlReleaseMessage - - Comment - Rectangle for HTML Release Message Floater window - Persist - 1 - Type - Rect - Value - - 46 - 520 - 400 - 128 - - - IMChatColor - - Comment - Color of instant messages from other residents - Persist - 1 - Type - Color4 - Value - - 1.0 - 1.0 - 1.0 - 1.0 - - IMInChatConsole Comment @@ -4834,6 +3642,17 @@ Value 1 + IgnoreAllNotifications + + Comment + Ignore all notifications so we never need user input on them. + Persist + 0 + Type + Boolean + Value + 0 + IgnorePixelDepth Comment @@ -5098,22 +3917,6 @@ Value 0 - LSLHelpRect - - Comment - Rectangle for LSL help window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 400 - 0 - - LSLHelpURL Comment @@ -5423,16 +4226,16 @@ Value 0 - LoginLastLocation + LoginLocation Comment Login at same location you last logged out Persist 1 Type - Boolean + String Value - 1 + last LoginPage @@ -5632,7 +4435,40 @@ Value 0 - MemoryLogFrequency + MediaControlFadeTime + + Comment + Amount of time (in seconds) that the media control fades + Persist + 1 + Type + F32 + Value + 1.5 + + MediaControlTimeout + + Comment + Amount of time (in seconds) for media controls to fade with no mouse activity + Persist + 1 + Type + F32 + Value + 3.0 + + MediaOnAPrimUI + + Comment + Whether or not to show the "link sharing" UI + Persist + 1 + Type + Boolean + Value + 0 + + MemoryLogFrequency Comment Seconds between display of Memory in log (0 for never) @@ -5643,6 +4479,17 @@ Value 600.0 + MemProfiling + + Comment + You want to use tcmalloc's memory profiling options. + Persist + 1 + Type + Boolean + Value + 0 + MenuAccessKeyTime Comment @@ -5753,38 +4600,6 @@ Value 0 - MoveDownBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 91 - 29 - 116 - 4 - - - MoveUpBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 91 - 54 - 116 - 29 - - MuteAmbient Comment @@ -5871,7 +4686,7 @@ Type Boolean Value - 1 + 0 NearMeRange @@ -5882,7 +4697,7 @@ Type F32 Value - 20 + 130 NextOwnerCopy @@ -5928,6 +4743,17 @@ Value + NewCacheLocationTopFolder + + Comment + Change the top folder location of the local disk cache to this + Persist + 1 + Type + String + Value + + NextLoginLocation Comment @@ -5994,22 +4820,6 @@ Value 0 - NotecardEditorRect - - Comment - Rectangle for notecard editor - Persist - 1 - Type - Rect - Value - - 0 - 400 - 400 - 0 - - NotifyBoxHeight Comment @@ -6032,6 +4842,94 @@ Value 350 + NotificationToastTime + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 5 + + ToastOpaqueTime + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 4 + + StartUpToastTime + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 5 + + ToastMargin + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 5 + + ChannelBottomPanelMargin + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 35 + + NotificationChannelRightMargin + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 10 + + NavBarMargin + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 60 + + OverflowToastHeight + + Comment + Width of notification messages + Persist + 1 + Type + S32 + Value + 72 + NotifyMoneyChange Comment @@ -6076,22 +4974,6 @@ Value 0 - ObjectChatColor - - Comment - Color of chat messages from objects - Persist - 1 - Type - Color4 - Value - - 0.699999988079 - 0.899999976158 - 0.699999988079 - 1 - - OpenDebugStatAdvanced Comment @@ -6192,6 +5074,17 @@ 0 OutBandwidth + + Comment + Expand render stats display + Persist + 1 + Type + Boolean + Value + 1 + + OutBandwidth Comment Outgoing bandwidth throttle (bps) @@ -6202,22 +5095,6 @@ Value 0.0 - OverdrivenColor - - Comment - Color of various indicators when resident is speaking too loud. - Persist - 1 - Type - Color4 - Value - - 1.0 - 0.0 - 0.0 - 1.0 - - OverlayTitle Comment @@ -6295,22 +5172,6 @@ Value 344 - PermissionsManagerRect - - Comment - Rectangle for permissions manager window - Persist - 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - PickerContextOpacity Comment @@ -6355,17 +5216,6 @@ Value 2.5 - PinTalkViewOpen - - Comment - Stay in IM after hitting return - Persist - 1 - Type - Boolean - Value - 1 - PingInterpolate Comment @@ -6421,166 +5271,6 @@ Value 13 - PreviewAnimRect - - Comment - Rectangle for animation preview window - Persist - 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - - PreviewClassifiedRect - - Comment - Rectangle for URL preview window - Persist - 1 - Type - Rect - Value - - 0 - 530 - 420 - 0 - - - PreviewEventRect - - Comment - Rectangle for Event preview window - Persist - 1 - Type - Rect - Value - - 0 - 530 - 420 - 0 - - - PreviewLandmarkRect - - Comment - Rectangle for landmark preview window - Persist - 1 - Type - Rect - Value - - 0 - 90 - 300 - 0 - - - PreviewObjectRect - - Comment - Rectangle for object preview window - Persist - 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - - PreviewScriptRect - - Comment - Rectangle for script preview window - Persist - 1 - Type - Rect - Value - - 0 - 586 - 576 - 0 - - - PreviewSoundRect - - Comment - Rectangle for sound preview window - Persist - 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - - PreviewTextureRect - - Comment - Rectangle for texture preview window - Persist - 1 - Type - Rect - Value - - 0 - 400 - 400 - 0 - - - PreviewURLRect - - Comment - Rectangle for URL preview window - Persist - 1 - Type - Rect - Value - - 0 - 90 - 300 - 0 - - - PreviewWearableRect - - Comment - Rectangle for wearable preview window - Persist - 1 - Type - Rect - Value - - 0 - 85 - 300 - 0 - - ProbeHardwareOnStartup Comment @@ -6592,22 +5282,6 @@ Value 1 - PropertiesRect - - Comment - Rectangle for inventory item properties window - Persist - 1 - Type - Rect - Value - - 0 - 320 - 350 - 0 - - PurgeCacheOnNextStartup Comment @@ -6805,8 +5479,19 @@ Boolean Value 1 - - RenderAvatarCloth + + RenderAvatar + + Comment + Render Avatars + Persist + 0 + Type + Boolean + Value + 1 + + RenderAvatarCloth Comment Controls if avatars use wavy cloth @@ -6989,16 +5674,16 @@ Value 1 - RenderCustomSettings + RenderDebugAlphaMask Comment - Do you want to set the graphics settings yourself + Test Alpha Masking Cutoffs. Persist 1 Type - Boolean + F32 Value - 0 + 0.5 RenderDebugGL @@ -7427,7 +6112,7 @@ Value 0 - RenderHideGroupTitleAll + RenderShowGroupTitleAll Comment Show group titles in name labels @@ -7436,7 +6121,7 @@ Type Boolean Value - 0 + 1 RenderInitError @@ -7504,17 +6189,6 @@ Value 512 - RenderName - - Comment - Controls display of names above avatars (0 = never, 1 = fade, 2 = always) - Persist - 1 - Type - S32 - Value - 2 - RenderNameFadeDuration Comment @@ -7526,16 +6200,16 @@ Value 1.0 - RenderNameHideSelf + RenderNameShowSelf Comment - Don't display own name above avatar + Display own name above avatar Persist 1 Type Boolean Value - 0 + 1 RenderNameShowTime @@ -7944,22 +6618,6 @@ Value 0 - ScriptErrorColor - - Comment - Color of script error messages - Persist - 1 - Type - Color4 - Value - - 0.8235294117 - 0.2745098039 - 0.2745098039 - 1.0 - - ScriptErrorsAsChat Comment @@ -8142,10 +6800,10 @@ Value 0 - ShowActiveSpeakers + ShowAdvancedGraphicsSettings Comment - Display active speakers list on login + Show advanced graphics settings Persist 1 Type @@ -8163,6 +6821,17 @@ Boolean Value 0 + + AvatarNameTagMode + + Comment + Select Avatar Name Tag Mode + Persist + 1 + Type + S32 + Value + 1 ShowAxes @@ -8186,39 +6855,6 @@ Value 1 - ShowCameraControls - - Comment - Display camera controls on login - Persist - 1 - Type - Boolean - Value - 1 - - ShowChatHistory - - Comment - - Persist - 0 - Type - Boolean - Value - 0 - - ShowCommunicate - - Comment - - Persist - 0 - Type - Boolean - Value - 0 - ShowConsoleWindow Comment @@ -8230,6 +6866,17 @@ Value 0 + ShowCoordinatesOption + + Comment + Show Coordinates in Location Input Field + Persist + 1 + Type + Boolean + Value + 0 + ShowCrosshairs Comment @@ -8252,28 +6899,6 @@ Value 0 - ShowDebugStats - - Comment - Show performance stats display - Persist - 1 - Type - Boolean - Value - 0 - - ShowDirectory - - Comment - - Persist - 0 - Type - Boolean - Value - 0 - ShowEmptyFoldersWhenSearching Comment @@ -8296,17 +6921,6 @@ Value 1 - ShowInventory - - Comment - Open inventory window on login - Persist - 1 - Type - Boolean - Value - 0 - ShowLandHoverTip Comment @@ -8317,19 +6931,30 @@ Boolean Value 0 - - ShowLeaders + + ShowPGSearchAll Comment - + Show/Hide Navigation Bar Favorites Panel Persist - 0 + 1 Type Boolean Value - 0 + 1 - ShowPGSearchAll + ShowNavbarFavoritesPanel + + Comment + Show/Hide Navigation Bar Navigation Panel + Persist + 1 + Type + Boolean + Value + 1 + + ShowNavbarNavigationPanel Comment Display results of search All that are flagged as PG @@ -8563,28 +7188,6 @@ Value 0 - ShowMiniMap - - Comment - Display mini map on login - Persist - 1 - Type - Boolean - Value - 0 - - ShowMovementControls - - Comment - Display movement controls on login - Persist - 1 - Type - Boolean - Value - 1 - ShowNearClip Comment @@ -8673,7 +7276,7 @@ Value 0 - ShowSearchBar + ShowNetStats Comment Show the Search Bar in the Status Overlay @@ -8682,7 +7285,7 @@ Type Boolean Value - 1 + 0 ShowSelectionBeam @@ -8704,7 +7307,7 @@ Type Boolean Value - 0 + 1 ShowTangentBasis @@ -8727,17 +7330,6 @@ Boolean Value 1 - - ShowTools - - Comment - - Persist - 0 - Type - Boolean - Value - 0 ShowTutorial @@ -8772,17 +7364,6 @@ Value 0 - ShowWorldMap - - Comment - Display world map on login - Persist - 1 - Type - Boolean - Value - 0 - ShowXUINames Comment @@ -8816,6 +7397,17 @@ Value default + SkinningSettingsFile + + Comment + Client skin color setting file name (per install). + Persist + 0 + Type + String + Value + + SkyAmbientScale Comment @@ -8848,8 +7440,8 @@ Color3 Value - 0.699999988079 - 0.699999988079 + 0.67 + 0.67 1.0 @@ -8890,38 +7482,6 @@ Value 1 - SlideLeftBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 20 - 54 - 45 - 29 - - - SlideRightBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 66 - 54 - 91 - 29 - - SmallAvatarNames Comment @@ -9021,22 +7581,6 @@ Value 0 - SpeakingColor - - Comment - Color of various indicators when resident is speaking on a voice channel. - Persist - 1 - Type - Color4 - Value - - 0.0 - 1.0 - 0.0 - 1.0 - - SpeedTest Comment @@ -9125,44 +7669,6 @@ Value fss.txt - StatusBarHeight - - Comment - Height of menu/status bar at top of screen (pixels) - Persist - 1 - Type - S32 - Value - 26 - - StatusBarPad - - Comment - Spacing between popup buttons at bottom of screen (Stand up, Release Controls) - Persist - 1 - Type - S32 - Value - 10 - - SystemChatColor - - Comment - Color of chat messages from SL System - Persist - 1 - Type - Color4 - Value - - 0.800000011921 - 1.0 - 1.0 - 1.0 - - SystemLanguage Comment @@ -9172,7 +7678,7 @@ Type String Value - en-us + en TabToTextFieldsOnly @@ -9218,22 +7724,6 @@ Value 0 - TexturePickerRect - - Comment - Rectangle for texture picker - Persist - 1 - Type - Rect - Value - - 0 - 290 - 350 - 0 - - TexturePickerShowFolders Comment @@ -9278,22 +7768,6 @@ Value 500.0 - ToolHelpRect - - Comment - - Persist - 0 - Type - Rect - Value - - 8 - 178 - 75 - 162 - - ToolTipDelay Comment @@ -9305,6 +7779,17 @@ Value 0.699999988079 + ToolTipFadeTime + + Comment + Seconds over which tooltip fades away + Persist + 1 + Type + F32 + Value + 0.2 + ToolboxAutoMove Comment @@ -9316,22 +7801,6 @@ Value 0 - ToolboxRect - - Comment - Rectangle for tools window - Persist - 1 - Type - Rect - Value - - 0 - 100 - 100 - 100 - - TrackFocusObject Comment @@ -9343,38 +7812,6 @@ Value 1 - TurnLeftBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 20 - 29 - 45 - 4 - - - TurnRightBtnRect - - Comment - - Persist - 0 - Type - Rect - Value - - 66 - 29 - 91 - 4 - - TutorialURL Comment @@ -9408,6 +7845,182 @@ Value 1 + UIAvatariconctrlSymbolHPad + + Comment + UI Avatar Icon Control Symbol Horizontal Pad + Persist + 1 + Type + S32 + Value + 2 + + UIAvatariconctrlSymbolVPad + + Comment + UI Avatar Icon Control Symbol Vertical Pad + Persist + 1 + Type + S32 + Value + 2 + + UIAvatariconctrlSymbolSize + + Comment + UI Avatar Icon Control Symbol Size + Persist + 1 + Type + S32 + Value + 5 + + UIAvatariconctrlSymbolPosition + + Comment + UI Avatar Icon Control Symbol Position (TopLeft|TopRight|BottomLeft|BottomRight) + Persist + 1 + Type + String + Value + BottomRight + + UIButtonOrigHPad + + Comment + UI Button Original Horizontal Pad + Persist + 1 + Type + S32 + Value + 6 + + UICheckboxctrlBtnSize + + Comment + UI Checkbox Control Button Size + Persist + 1 + Type + S32 + Value + 13 + + UICheckboxctrlHeight + + Comment + UI Checkbox Control Height + Persist + 1 + Type + S32 + Value + 16 + + UICheckboxctrlHPad + + Comment + UI Checkbox Control Horizontal Pad + Persist + 1 + Type + S32 + Value + 2 + + UICheckboxctrlSpacing + + Comment + UI Checkbox Control Spacing + Persist + 1 + Type + S32 + Value + 5 + + UICheckboxctrlVPad + + Comment + UI Checkbox Control Vertical Pad + Persist + 1 + Type + S32 + Value + 2 + + UICloseBoxFromTop + + Comment + Size of UI floater close box from top + Persist + 1 + Type + S32 + Value + 1 + + UIExtraTriangleHeight + + Comment + UI extra triangle height + Persist + 1 + Type + S32 + Value + -2 + + UIExtraTriangleWidth + + Comment + UI extra triangle width + Persist + 1 + Type + S32 + Value + 2 + + UIFloaterCloseBoxSize + + Comment + Size of UI floater close box size + Persist + 1 + Type + S32 + Value + 16 + + UIFloaterHeaderSize + + Comment + Size of UI floater header size + Persist + 1 + Type + S32 + Value + 18 + + UIFloaterHPad + + Comment + Size of UI floater horizontal pad + Persist + 1 + Type + S32 + Value + 6 + UIFloaterTestBool Comment @@ -9419,720 +8032,16 @@ Value 0 - UIImgBtnCloseActiveUUID + UIFloaterVPad Comment - - Persist - 0 - Type - String - Value - 47a8c844-cd2a-4b1a-be01-df8b1612fe5d - - UIImgBtnCloseInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 779e4fa3-9b13-f74a-fba9-3886fe9c86ba - - UIImgBtnClosePressedUUID - - Comment - - Persist - 0 - Type - String - Value - e5821134-23c0-4bd0-af06-7fa95b9fb01a - - UIImgBtnForwardInUUID - - Comment - - Persist - 0 - Type - String - Value - 54197a61-f5d1-4c29-95d2-c071d08849cb - - UIImgBtnForwardOutUUID - - Comment - - Persist - 0 - Type - String - Value - a0eb4021-1b20-4a53-892d-8faa9265a6f5 - - UIImgBtnJumpLeftInUUID - - Comment - - Persist - 0 - Type - String - Value - 9cad3e6d-2d6d-107d-f8ab-5ba272b5bfe1 - - UIImgBtnJumpLeftOutUUID - - Comment - - Persist - 0 - Type - String - Value - 3c18c87e-5f50-14e2-e744-f44734aa365f - - UIImgBtnJumpRightInUUID - - Comment - - Persist - 0 - Type - String - Value - 7dabc040-ec13-2309-ddf7-4f161f6de2f4 - - UIImgBtnJumpRightOutUUID - - Comment - - Persist - 0 - Type - String - Value - ff9a71eb-7414-4cf8-866e-a701deb7c3cf - - UIImgBtnLeftInUUID - - Comment - - Persist - 0 - Type - String - Value - 95463c78-aaa6-464d-892d-3a805b6bb7bf - - UIImgBtnLeftOutUUID - - Comment - - Persist - 0 - Type - String - Value - 13a93910-6b44-45eb-ad3a-4d1324c59bac - - UIImgBtnMinimizeActiveUUID - - Comment - - Persist - 0 - Type - String - Value - 34c9398d-bb78-4643-9633-46a2fa3e9637 - - UIImgBtnMinimizeInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 6e72abba-1378-437f-bf7a-f0c15f3e99a3 - - UIImgBtnMinimizePressedUUID - - Comment - - Persist - 0 - Type - String - Value - 39801651-26cb-4926-af57-7af9352c273c - - UIImgBtnMoveDownInUUID - - Comment - - Persist - 0 - Type - String - Value - b92a70b9-c841-4c94-b4b3-cee9eb460d48 - - UIImgBtnMoveDownOutUUID - - Comment - - Persist - 0 - Type - String - Value - b5abc9fa-9e62-4e03-bc33-82c4c1b6b689 - - UIImgBtnMoveUpInUUID - - Comment - - Persist - 0 - Type - String - Value - 49b4b357-e430-4b56-b9e0-05b8759c3c82 - - UIImgBtnMoveUpOutUUID - - Comment - - Persist - 0 - Type - String - Value - f887146d-829f-4e39-9211-cf872b78f97c - - UIImgBtnPanDownInUUID - - Comment - - Persist - 0 - Type - String - Value - e5821134-23c0-4bd0-af06-7fa95b9fb01a - - UIImgBtnPanDownOutUUID - - Comment - - Persist - 0 - Type - String - Value - 47a8c844-cd2a-4b1a-be01-df8b1612fe5d - - UIImgBtnPanLeftInUUID - - Comment - - Persist - 0 - Type - String - Value - e5821134-23c0-4bd0-af06-7fa95b9fb01a - - UIImgBtnPanLeftOutUUID - - Comment - - Persist - 0 - Type - String - Value - 47a8c844-cd2a-4b1a-be01-df8b1612fe5d - - UIImgBtnPanRightInUUID - - Comment - - Persist - 0 - Type - String - Value - e5821134-23c0-4bd0-af06-7fa95b9fb01a - - UIImgBtnPanRightOutUUID - - Comment - - Persist - 0 - Type - String - Value - 47a8c844-cd2a-4b1a-be01-df8b1612fe5d - - UIImgBtnPanUpInUUID - - Comment - - Persist - 0 - Type - String - Value - e5821134-23c0-4bd0-af06-7fa95b9fb01a - - UIImgBtnPanUpOutUUID - - Comment - - Persist - 0 - Type - String - Value - 47a8c844-cd2a-4b1a-be01-df8b1612fe5d - - UIImgBtnRestoreActiveUUID - - Comment - - Persist - 0 - Type - String - Value - 111b39de-8928-4690-b7b2-e17d5c960277 - - UIImgBtnRestoreInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 0eafa471-70af-4882-b8c1-40a310929744 - - UIImgBtnRestorePressedUUID - - Comment - - Persist - 0 - Type - String - Value - 90a0ed5c-2e7b-4845-9958-a64a1b30f312 - - UIImgBtnRightInUUID - - Comment - - Persist - 0 - Type - String - Value - 5e616d0d-4335-476f-9977-560bccd009da - - UIImgBtnRightOutUUID - - Comment - - Persist - 0 - Type - String - Value - 5a44fd04-f52b-4c30-8b00-4a31e27614bd - - UIImgBtnScrollDownInUUID - - Comment - - Persist - 0 - Type - String - Value - d2421bab-2eaf-4863-b8f6-5e4c52519247 - - UIImgBtnScrollDownOutUUID - - Comment - - Persist - 0 - Type - String - Value - b4ecdecf-5c8d-44e7-b882-17a77e88ed55 - - UIImgBtnScrollLeftInUUID - - Comment - - Persist - 0 - Type - String - Value - ea137a32-6718-4d05-9c22-7d570d27b2cd - - UIImgBtnScrollLeftOutUUID - - Comment - - Persist - 0 - Type - String - Value - 43773e8d-49aa-48e0-80f3-a04715f4677a - - UIImgBtnScrollRightInUUID - - Comment - - Persist - 0 - Type - String - Value - b749de64-e903-4c3c-ac0b-25fb6fa39cb5 - - UIImgBtnScrollRightOutUUID - - Comment - - Persist - 0 - Type - String - Value - 3d700d19-e708-465d-87f2-46c8c0ee7938 - - UIImgBtnScrollUpInUUID - - Comment - - Persist - 0 - Type - String - Value - a93abdf3-27b5-4e22-a8fa-c48216cd2e3a - - UIImgBtnScrollUpOutUUID - - Comment - - Persist - 0 - Type - String - Value - dad084d7-9a46-452a-b0ff-4b9f1cefdde9 - - UIImgBtnSlideLeftInUUID - - Comment - - Persist - 0 - Type - String - Value - 724996f5-b956-46f6-9844-4fcfce1d5e83 - - UIImgBtnSlideLeftOutUUID - - Comment - - Persist - 0 - Type - String - Value - 82476321-0374-4c26-9567-521535ab4cd7 - - UIImgBtnSlideRightInUUID - - Comment - - Persist - 0 - Type - String - Value - 7eeb57d2-3f37-454d-a729-8b217b8be443 - - UIImgBtnSlideRightOutUUID - - Comment - - Persist - 0 - Type - String - Value - 1fbe4e60-0607-44d1-a50a-032eff56ae75 - - UIImgBtnSpinDownInUUID - - Comment - - Persist - 0 - Type - String - Value - a985ac71-052f-48e6-9c33-d931c813ac92 - - UIImgBtnSpinDownOutUUID - - Comment - - Persist - 0 - Type - String - Value - b6d240dd-5602-426f-b606-bbb49a30726d - - UIImgBtnSpinUpInUUID - - Comment - - Persist - 0 - Type - String - Value - c8450082-96a0-4319-8090-d3ff900b4954 - - UIImgBtnSpinUpOutUUID - - Comment - - Persist - 0 - Type - String - Value - 56576e6e-6710-4e66-89f9-471b59122794 - - UIImgBtnTabBottomInUUID - - Comment - - Persist - 0 - Type - String - Value - c001d8fd-a869-4b6f-86a1-fdcb106df9c7 - - UIImgBtnTabBottomOutUUID - - Comment - - Persist - 0 - Type - String - Value - bf0a8779-689b-48c3-bb9a-6af546366ef4 - - UIImgBtnTabBottomPartialInUUID - - Comment - - Persist - 0 - Type - String - Value - eb0b0904-8c91-4f24-b500-1180b91140de - - UIImgBtnTabBottomPartialOutUUID - - Comment - - Persist - 0 - Type - String - Value - 8dca716c-b29c-403a-9886-91c028357d6e - - UIImgBtnTabTopInUUID - - Comment - - Persist - 0 - Type - String - Value - 16d032e8-817b-4368-8a4e-b7b947ae3889 - - UIImgBtnTabTopOutUUID - - Comment - - Persist - 0 - Type - String - Value - 1ed83f57-41cf-4052-a3b4-2e8bb78d8191 - - UIImgBtnTabTopPartialInUUID - - Comment - - Persist - 0 - Type - String - Value - 7c6c6c26-0e25-4438-89bd-30d8b8e9d704 - - UIImgBtnTabTopPartialOutUUID - - Comment - - Persist - 0 - Type - String - Value - 932ad585-0e45-4a57-aa23-4cf81beeb7b0 - - UIImgBtnTearOffActiveUUID - - Comment - - Persist - 0 - Type - String - Value - 74e1a96f-4833-a24d-a1bb-1bce1468b0e7 - - UIImgBtnTearOffInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 74e1a96f-4833-a24d-a1bb-1bce1468b0e7 - - UIImgBtnTearOffPressedUUID - - Comment - - Persist - 0 - Type - String - Value - d2524c13-4ba6-af7c-e305-8ac6cc18d86a - - UIImgCheckboxActiveSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - cf4a2ed7-1533-4686-9dde-df9a37ddca55 - - UIImgCheckboxActiveUUID - - Comment - - Persist - 0 - Type - String - Value - 05bb64ee-96fd-4243-b74e-f40a41bc53ba - - UIImgCheckboxInactiveSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - c817c642-9abd-4236-9287-ae0513fe7d2b - - UIImgCheckboxInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 7d94cb59-32a2-49bf-a516-9e5a2045f9d9 - - UIImgCreateSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - 0098b015-3daf-4cfe-a72f-915369ea97c2 - - UIImgCreateUUID - - Comment - - Persist - 0 - Type - String - Value - 7a0b1bdb-b5d9-4df5-bac2-ba230da93b5b - - UIImgCrosshairsUUID - - Comment - Image to use for crosshair display (UUID texture reference) + Size of UI floater vertical pad Persist 1 Type - String + S32 Value - 6e1a3980-bf2d-4274-8970-91e60d85fb52 + 6 UIImgDefaultEyesUUID @@ -10233,6 +8142,28 @@ Value 5748decc-f629-461c-9a36-a35a221fe21f + UIImgDefaultAlphaUUID + + Comment + + Persist + 0 + Type + String + Value + 5748decc-f629-461c-9a36-a35a221fe21f + + UIImgDefaultTattooUUID + + Comment + + Persist + 0 + Type + String + Value + 5748decc-f629-461c-9a36-a35a221fe21f + UIImgDefaultUnderwearUUID Comment @@ -10244,7 +8175,7 @@ Value 5748decc-f629-461c-9a36-a35a221fe21f - UIImgDirectionArrowUUID + StartUpChannelUUID Comment @@ -10253,9 +8184,9 @@ Type String Value - 586383e8-4d9b-4fba-9196-2b5938e79c2c - - UIImgFaceSelectedUUID + B56AF90D-6684-48E4-B1E4-722D3DEB2CB6 + + NearByChatChannelUUID Comment @@ -10264,9 +8195,9 @@ Type String Value - b4870163-6208-42a9-9801-93133bf9a6cd - - UIImgFaceUUID + E1158BD6-661C-4981-9DAD-4DCBFF062502 + + NotificationChannelUUID Comment @@ -10275,9 +8206,9 @@ Type String Value - ce15fd63-b0b6-463c-a37d-ea6393208b3e - - UIImgFocusSelectedUUID + AEED3193-8709-4693-8558-7452CCA97AE5 + + AlertChannelUUID Comment @@ -10286,162 +8217,8 @@ Type String Value - ab6a730e-ddfd-4982-9a32-c6de3de6d31d - - UIImgFocusUUID - - Comment - - Persist - 0 - Type - String - Value - 57bc39d1-288c-4519-aea6-6d1786a5c274 - - UIImgGrabSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - c1e21504-f136-451d-b8e9-929037812f1d - - UIImgGrabUUID - - Comment - - Persist - 0 - Type - String - Value - c63f124c-6340-4fbf-b59e-0869a44adb64 - - UIImgMoveSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - 46f17c7b-8381-48c3-b628-6a406e060dd6 - - UIImgMoveUUID - - Comment - - Persist - 0 - Type - String - Value - 2fa5dc06-bcdd-4e09-a426-f9f262d4fa65 - - UIImgRadioActiveSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - 52f09e07-5816-4052-953c-94c6c10479b7 - - UIImgRadioActiveUUID - - Comment - - Persist - 0 - Type - String - Value - 7a1ba9b8-1047-4d1e-9cfc-bc478c80b63f - - UIImgRadioInactiveSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - 1975db39-aa29-4251-aea0-409ac09d414d - - UIImgRadioInactiveUUID - - Comment - - Persist - 0 - Type - String - Value - 90688481-67ff-4af0-be69-4aa084bcad1e - - UIImgResizeBottomRightUUID - - Comment - - Persist - 0 - Type - String - Value - e3690e25-9690-4f6c-a745-e7dcd885285a - - UIImgRotateSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - cdfb7fde-0d13-418a-9d89-2bd91019fc95 - - UIImgRotateUUID - - Comment - - Persist - 0 - Type - String - Value - c34b1eaa-aae3-4351-b082-e26c0b636779 - - UIImgScaleSelectedUUID - - Comment - - Persist - 0 - Type - String - Value - 55aa57ef-508a-47f7-8867-85d21c5a810d - - UIImgScaleUUID - - Comment - - Persist - 0 - Type - String - Value - 88a90fef-b448-4883-9344-ecf378a60433 - + F3E07BC8-A973-476D-8C7F-F3B7293975D1 + UIImgWhiteUUID Comment @@ -10453,6 +8230,193 @@ Value 5748decc-f629-461c-9a36-a35a221fe21f + UILineEditorCursorThickness + + Comment + UI Line Editor Cursor Thickness + Persist + 1 + Type + S32 + Value + 2 + + UILineEditorHPad + + Comment + UI Line Editor Horizontal Pad + Persist + 1 + Type + S32 + Value + 2 + + UILineEditorVPad + + Comment + UI Line Editor Vertical Pad + Persist + 1 + Type + S32 + Value + 3 + + UIMaxComboWidth + + Comment + Maximum width of combo box + Persist + 1 + Type + S32 + Value + 500 + + UIMinimizedWidth + + Comment + Size of UI floater minimized width + Persist + 1 + Type + S32 + Value + 160 + + UIMultiSliderctrlSpacing + + Comment + UI multi slider ctrl spacing + Persist + 1 + Type + S32 + Value + 4 + + UIMultiTrackHeight + + Comment + UI multi track height + Persist + 1 + Type + S32 + Value + 6 + + UIPreeditMarkerBrightness + + Comment + UI Preedit Marker Brightness + Persist + 1 + Type + F32 + Value + 0.4 + + UIPreeditMarkerGap + + Comment + UI Preedit Marker Gap + Persist + 1 + Type + S32 + Value + 1 + + UIPreeditMarkerPosition + + Comment + UI Preedit Marker Position + Persist + 1 + Type + S32 + Value + 4 + + UIPreeditMarkerThickness + + Comment + UI Preedit Marker Thickness + Persist + 1 + Type + S32 + Value + 1 + + UIPreeditStandoutBrightness + + Comment + UI Preedit Standout Brightness + Persist + 1 + Type + F32 + Value + 0.6 + + UIPreeditStandoutGap + + Comment + UI Preedit Standout Gap + Persist + 1 + Type + S32 + Value + 1 + + UIPreeditStandoutPosition + + Comment + UI Preedit Standout Position + Persist + 1 + Type + S32 + Value + 4 + + UIPreeditStandoutThickness + + Comment + UI Preedit Standout Thickness + Persist + 1 + Type + S32 + Value + 2 + + UIResizeBarHeight + + Comment + Size of UI resize bar height + Persist + 1 + Type + S32 + Value + 3 + + UIResizeBarOverlap + + Comment + Size of UI resize bar overlap + Persist + 1 + Type + S32 + Value + 1 + UIScaleFactor Comment @@ -10464,6 +8428,39 @@ Value 1.0 + UIScrollbarSize + + Comment + UI scrollbar size + Persist + 1 + Type + S32 + Value + 15 + + UISliderctrlHeight + + Comment + UI slider ctrl height + Persist + 1 + Type + S32 + Value + 16 + + UISliderctrlSpacing + + Comment + UI slider ctrl spacing + Persist + 1 + Type + S32 + Value + 4 + UISndAlert Comment @@ -10826,6 +8823,193 @@ String Value c80260ba-41fd-8a46-768a-6bf236360e3a + + UISpinctrlBtnHeight + + Comment + UI spin control button height + Persist + 1 + Type + S32 + Value + 8 + + UISpinctrlBtnWidth + + Comment + UI spin control button width + Persist + 1 + Type + S32 + Value + 16 + + UISpinctrlDefaultLabelWidth + + Comment + UI spin control default label width + Persist + 1 + Type + S32 + Value + 10 + + UISpinctrlSpacing + + Comment + UI spin control spacing + Persist + 1 + Type + S32 + Value + 2 + + UITabCntrArrowBtnSize + + Comment + UI Tab Container Arrow Button Size + Persist + 1 + Type + S32 + Value + 16 + + UITabCntrvArrowBtnSize + + Comment + UI Tab Container V Arrow Button Size + Persist + 1 + Type + S32 + Value + 16 + + UITabCntrvPad + + Comment + UI Tab Container V Pad + Persist + 1 + Type + S32 + Value + 0 + + UITabCntrButtonPanelOverlap + + Comment + UI Tab Container Button Panel Overlap + Persist + 1 + Type + S32 + Value + 1 + + UITabCntrCloseBtnSize + + Comment + UI Tab Container Close Button Size + Persist + 1 + Type + S32 + Value + 16 + + UITabCntrTabHeight + + Comment + UI Tab Container Tab Height + Persist + 1 + Type + S32 + Value + 16 + + UITabCntrTabHPad + + Comment + UI Tab Container Tab Horizontal Pad + Persist + 1 + Type + S32 + Value + 4 + + UITabCntrTabPartialWidth + + Comment + UI Tab Container Tab Partial Width + Persist + 1 + Type + S32 + Value + 12 + + UITabCntrVertTabMinWidth + + Comment + UI Tab Container Vertical Tab Minimum Width + Persist + 1 + Type + S32 + Value + 100 + + UITabPadding + + Comment + UI Tab Padding + Persist + 1 + Type + S32 + Value + 15 + + UITextEditorBorder + + Comment + UI Text Editor Border + Persist + 1 + Type + S32 + Value + 1 + + UITextEditorHPad + + Comment + UI Text Horizontal Pad + Persist + 1 + Type + S32 + Value + 4 + + UITextEditorVPadTop + + Comment + UI Text Vertical Pad Top + Persist + 1 + Type + S32 + Value + 4 UploadBakedTexOld @@ -11312,6 +9496,17 @@ Value 44125 + WarningsAsChat + + Comment + Display warning messages in chat history + Persist + 1 + Type + Boolean + Value + 0 + WLSkyDetail Comment @@ -11323,325 +9518,6 @@ Value 64 - WarnAboutBadPCI - - Comment - Enables AboutBadPCI warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnAboutDirectX9 - - Comment - Enables AboutDirectX9 warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnAboutOldGraphicsDriver - - Comment - Enables AboutOldGraphicsDriver warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnAboutPCIGraphics - - Comment - Enables AboutPCIGraphics warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnBrowserLaunch - - Comment - Enables BrowserLaunch warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnDeedObject - - Comment - Enables DeedObject warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstAppearance - - Comment - Enables FirstAppearance warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstAttach - - Comment - Enables FirstAttach warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstBalanceDecrease - - Comment - Enables FirstBalanceDecrease warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstBalanceIncrease - - Comment - Enables FirstBalanceIncrease warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstBuild - - Comment - Enables FirstBuild warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstDebugMenus - - Comment - Enables FirstDebugMenus warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstFlexible - - Comment - Enables FirstFlexible warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstGoTo - - Comment - Enables FirstGoTo warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstInventory - - Comment - Enables FirstInventory warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstLeftClickNoHit - - Comment - Enables FirstLeftClickNoHit warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstMap - - Comment - Enables FirstMap warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstMedia - - Comment - Enables FirstMedia warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstOverrideKeys - - Comment - Enables FirstOverrideKeys warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstSandbox - - Comment - Enables FirstSandbox warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstSculptedPrim - - Comment - Enables FirstSculptedPrim warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstSit - - Comment - Enables FirstSit warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstStreamingMusic - - Comment - Enables FirstStreamingMusic warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstStreamingVideo - - Comment - Enables FirstStreamingVideo warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstTeleport - - Comment - Enables FirstTeleport warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnFirstVoice - - Comment - Enables FirstVoice warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnNewClassified - - Comment - Enables NewClassified warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnQuickTimeInstalled - - Comment - Enables QuickTimeInstalled warning dialog - Persist - 1 - Type - Boolean - Value - 1 - - WarnReturnToOwner - - Comment - Enables ReturnToOwner warning dialog - Persist - 1 - Type - Boolean - Value - 1 - WatchdogEnabled Comment @@ -11708,6 +9584,17 @@ Value 1 + WindowFullScreen + + Comment + Run SL in fullscreen mode + Persist + 1 + Type + Boolean + Value + 0 + WindowHeight Comment @@ -11774,6 +9661,17 @@ Value 150000.0 + XUIEditor + + Comment + Path to program used to edit XUI files + Persist + 1 + Type + String + Value + 150000.0 + YawFromMousePosition Comment @@ -11818,22 +9716,6 @@ Value 0.40000000596 - llOwnerSayChatColor - - Comment - Color of chat messages from objects only visible to the owner - Persist - 1 - Type - Color4 - Value - - 0.990000009537 - 0.990000009537 - 0.689999997616 - 1.0 - - particlesbeacon Comment diff --git a/indra/newview/app_settings/settings_files.xml b/indra/newview/app_settings/settings_files.xml index ec55745358..aa5b301959 100644 --- a/indra/newview/app_settings/settings_files.xml +++ b/indra/newview/app_settings/settings_files.xml @@ -4,10 +4,10 @@ @@ -6451,8 +6459,6 @@ - + + + + + + + @@ -6659,6 +6677,13 @@ + + + + + - - - - + + + + + @@ -7843,6 +7870,12 @@ + + + + - - - - - - - - + + + + + @@ -8619,6 +8648,14 @@ + + + + + @@ -8798,6 +8835,7 @@ domain="0" /> + @@ -11258,5 +11296,36 @@ + + + + + + + + + + diff --git a/indra/newview/character/checkerboard.tga b/indra/newview/character/checkerboard.tga new file mode 100644 index 0000000000..1950d7403d Binary files /dev/null and b/indra/newview/character/checkerboard.tga differ diff --git a/indra/newview/character/invisible_head.tga b/indra/newview/character/invisible_head.tga new file mode 100755 index 0000000000..2673a237d5 Binary files /dev/null and b/indra/newview/character/invisible_head.tga differ diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt index 56de9c610a..733670f311 100644 --- a/indra/newview/gpu_table.txt +++ b/indra/newview/gpu_table.txt @@ -70,8 +70,8 @@ ATI M72 .*ATI.*M72.* 1 1 ATI M76 .*ATI.*M76.* 3 1 ATI Mobility Radeon 7xxx .*ATI.*Mobility.*Radeon 7.* 0 1 ATI Mobility Radeon 8xxx .*ATI.*Mobility.*Radeon 8.* 0 1 -ATI Mobility Radeon 9800 .*ATI.*Mobility.*98.* 1 1 -ATI Mobility Radeon 9700 .*ATI.*Mobility.*97.* 1 1 +ATI Mobility Radeon 9800 .*ATI.*Mobility.*98.* 0 1 +ATI Mobility Radeon 9700 .*ATI.*Mobility.*97.* 0 1 ATI Mobility Radeon 9600 .*ATI.*Mobility.*96.* 0 1 ATI Mobility Radeon HD 2300 .*ATI.*Mobility.*HD.*23.* 1 1 ATI Mobility Radeon HD 2400 .*ATI.*Mobility.*HD.*24.* 1 1 @@ -162,7 +162,10 @@ Intel Montara .*Intel.*Montara.* 0 0 Intel Springdale .*Intel.*Springdale.* 0 0 Matrox .*Matrox.* 0 0 Mesa .*Mesa.* 0 0 +NVIDIA GT 120 .*NVIDIA.*GeForce.*GT.*12.* 3 1 +NVIDIA GT 130 .*NVIDIA.*GeForce.*GT.*13.* 3 1 NVIDIA GTX 260 .*NVIDIA.*GeForce.*GTX.*26.* 3 1 +NVIDIA GTX 270 .*NVIDIA.*GeForce.*GTX.*27.* 3 1 NVIDIA GTX 280 .*NVIDIA.*GeForce.*GTX.*28.* 3 1 NVIDIA GTX 290 .*NVIDIA.*GeForce.*GTX.*29.* 3 1 NVIDIA C51 .*NVIDIA.*C51.* 0 1 @@ -263,7 +266,6 @@ NVIDIA Quadro FX 4500 .*Quadro.*FX.*4500.* 3 1 NVIDIA Quadro FX .*Quadro FX.* 1 1 NVIDIA Quadro NVS .*Quadro NVS.* 0 1 NVIDIA RIVA TNT .*RIVA TNT.* 0 0 -NVIDIA PCI .*NVIDIA.*/PCI/SSE2 0 0 S3 .*S3 Graphics.* 0 0 SiS SiS.* 0 0 Trident Trident.* 0 0 diff --git a/indra/newview/installers/windows/installer_template.nsi b/indra/newview/installers/windows/installer_template.nsi index 87218008bd..73a548cdc6 100644 --- a/indra/newview/installers/windows/installer_template.nsi +++ b/indra/newview/installers/windows/installer_template.nsi @@ -498,7 +498,8 @@ RMDir "$INSTDIR" IfFileExists "$INSTDIR" FOLDERFOUND NOFOLDER FOLDERFOUND: - MessageBox MB_YESNO $(DeleteProgramFilesMB) IDNO NOFOLDER + ; Silent uninstall always removes all files (/SD IDYES) + MessageBox MB_YESNO $(DeleteProgramFilesMB) /SD IDYES IDNO NOFOLDER RMDir /r "$INSTDIR" NOFOLDER: diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index 99c973f7ea..07a8f951ee 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -75,8 +75,9 @@ Life Linux client is very similar to that for Windows, as detailed at: 3. INSTALLING & RUNNING -=-=-=-=-=-=-=-=-=-=-=- -The Second Life Linux client entirely runs out of the directory you have -unpacked it into - no installation step is required. +The Second Life Linux client can entirely run from the directory you have +unpacked it into - no installation step is required. If you wish to +perform a separate installation step anyway, you may run './install.sh' Run ./secondlife from the installation directory to start Second Life. @@ -96,10 +97,7 @@ you wish. 4. KNOWN ISSUES -=-=-=-=-=-=-=- -* UPDATING - when the client detects that a new version of Second Life - is available, it will ask you if you wish to download the new version. - This option is not implemented; to upgrade, you should manually download a - new version from the Second Life web site, . +* No significant known issues at this time. 5. TROUBLESHOOTING diff --git a/indra/newview/linux_tools/handle_secondlifeprotocol.sh b/indra/newview/linux_tools/handle_secondlifeprotocol.sh index 7ff86d1b93..203012132e 100755 --- a/indra/newview/linux_tools/handle_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/handle_secondlifeprotocol.sh @@ -11,7 +11,7 @@ if [ -z "$URL" ]; then fi RUN_PATH=`dirname "$0" || echo .` -cd "${RUN_PATH}" +cd "${RUN_PATH}/.." exec ./secondlife -url \'"${URL}"\' diff --git a/indra/newview/linux_tools/install.sh b/indra/newview/linux_tools/install.sh new file mode 100755 index 0000000000..c94510267a --- /dev/null +++ b/indra/newview/linux_tools/install.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# Install the Second Life Viewer. This script can install the viewer both +# system-wide and for an individual user. + +VT102_STYLE_NORMAL='\E[0m' +VT102_COLOR_RED='\E[31m' + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` +tarball_path=${RUN_PATH} + +function prompt() +{ + local prompt=$1 + local input + + echo -n "$prompt" + + while read input; do + case $input in + [Yy]* ) + return 1 + ;; + [Nn]* ) + return 0 + ;; + * ) + echo "Please enter yes or no." + echo -n "$prompt" + esac + done +} + +function die() +{ + warn $1 + exit 1 +} + +function warn() +{ + echo -n -e $VT102_COLOR_RED + echo $1 + echo -n -e $VT102_STYLE_NORMAL +} + +function homedir_install() +{ + warn "You are not running as a privileged user, so you will only be able" + warn "to install the Second Life Viewer in your home directory. If you" + warn "would like to install the Second Life Viewer system-wide, please run" + warn "this script as the root user, or with the 'sudo' command." + echo + + prompt "Proceed with the installation? [Y/N]: " + if [[ $? == 0 ]]; then + exit 0 + fi + + install_to_prefix "$HOME/.secondlife-install" + $HOME/.secondlife-install/etc/refresh_desktop_app_entry.sh +} + +function root_install() +{ + local default_prefix="/opt/secondlife-install" + + echo -n "Enter the desired installation directory [${default_prefix}]: "; + read + if [[ "$REPLY" = "" ]] ; then + local install_prefix=$default_prefix + else + local install_prefix=$REPLY + fi + + install_to_prefix "$install_prefix" + + mkdir -p /usr/local/share/applications + ${install_prefix}/etc/refresh_desktop_app_entry.sh +} + +function install_to_prefix() +{ + test -e "$1" && backup_previous_installation "$1" + mkdir -p "$1" || die "Failed to create installation directory!" + + echo " - Installing to $1" + + cp -a "${tarball_path}"/* "$1/" || die "Failed to complete the installation!" +} + +function backup_previous_installation() +{ + local backup_dir="$1".backup-$(date -I) + echo " - Backing up previous installation to $backup_dir" + + mv "$1" "$backup_dir" || die "Failed to create backup of existing installation!" +} + + +if [ "$UID" == "0" ]; then + root_install +else + homedir_install +fi diff --git a/indra/newview/linux_tools/refresh_desktop_app_entry.sh b/indra/newview/linux_tools/refresh_desktop_app_entry.sh new file mode 100755 index 0000000000..d2b2a732d5 --- /dev/null +++ b/indra/newview/linux_tools/refresh_desktop_app_entry.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +SCRIPTSRC=`readlink -f "$0" || echo "$0"` +RUN_PATH=`dirname "${SCRIPTSRC}" || echo .` + +install_prefix=${RUN_PATH}/.. + +function install_desktop_entry() +{ + local installation_prefix="$1" + local desktop_entries_dir="$2" + + local desktop_entry="\ +[Desktop Entry]\n\ +Name=Second Life\n\ +Comment=Client for the On-line Virtual World, Second Life\n\ +Exec=${installation_prefix}/secondlife\n\ +Icon=${installation_prefix}/secondlife_icon.png\n\ +Terminal=false\n\ +Type=Application\n\ +Categories=Application;Network;\n\ +StartupNotify=true\n\ +X-Desktop-File-Install-Version=3.0" + + echo " - Installing menu entries in ${desktop_entries_dir}" + mkdir -vp "${desktop_entries_dir}" + echo -e $desktop_entry > "${desktop_entries_dir}/secondlife-viewer.desktop" || "Failed to install application menu!" +} + +if [ "$UID" == "0" ]; then + # system-wide + install_desktop_entry "$install_prefix" /usr/local/share/applications +else + # user-specific + install_desktop_entry "$install_prefix" "$HOME/.local/share/applications" +fi diff --git a/indra/newview/linux_tools/register_secondlifeprotocol.sh b/indra/newview/linux_tools/register_secondlifeprotocol.sh index 4ab96f97d6..c7b4d55461 100755 --- a/indra/newview/linux_tools/register_secondlifeprotocol.sh +++ b/indra/newview/linux_tools/register_secondlifeprotocol.sh @@ -7,10 +7,10 @@ HANDLER="$1" RUN_PATH=`dirname "$0" || echo .` -cd "${RUN_PATH}" +cd "${RUN_PATH}/.." if [ -z "$HANDLER" ]; then - HANDLER=`pwd`/handle_secondlifeprotocol.sh + HANDLER=`pwd`/etc/handle_secondlifeprotocol.sh fi # Register handler for GNOME-aware apps diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index dfe19c1232..3209654498 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -91,7 +91,11 @@ echo "Running from ${RUN_PATH}" cd "${RUN_PATH}" # Re-register the secondlife:// protocol handler every launch, for now. -./register_secondlifeprotocol.sh +./etc/register_secondlifeprotocol.sh + +# Re-register the application with the desktop system every launch, for now. +./etc/refresh_desktop_app_entry.sh + ## Before we mess with LD_LIBRARY_PATH, save the old one to restore for ## subprocesses that care. export SAVED_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}" @@ -116,7 +120,7 @@ fi export SL_ENV='LD_LIBRARY_PATH="`pwd`"/lib:"`pwd`"/app_settings/mozilla-runtime-linux-i686:"${LD_LIBRARY_PATH}"' export SL_CMD='$LL_WRAPPER bin/do-not-directly-run-secondlife-bin' -export SL_OPT="`cat gridargs.dat` $@" +export SL_OPT="`cat etc/gridargs.dat` $@" # Run the program eval ${SL_ENV} ${SL_CMD} ${SL_OPT} || LL_RUN_ERR=runerr diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index cc443d05c0..214065f080 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -32,115 +32,89 @@ #include "llviewerprecompiledheaders.h" -#include "stdtypes.h" -#include "stdenums.h" - #include "llagent.h" +#include "llagentwearables.h" -#include "llcamera.h" -#include "llcoordframe.h" -#include "indra_constants.h" -#include "llmath.h" -#include "llcriticaldamp.h" -#include "llfocusmgr.h" -#include "llglheaders.h" -#include "llparcel.h" -#include "llpermissions.h" -#include "llregionhandle.h" -#include "m3math.h" -#include "m4math.h" -#include "message.h" -#include "llquaternion.h" -#include "v3math.h" -#include "v4math.h" -#include "llsmoothstep.h" -#include "llsdutil.h" -//#include "vmath.h" - -#include "imageids.h" -#include "llbox.h" -#include "llbutton.h" +#include "llanimationstates.h" #include "llcallingcard.h" -#include "llchatbar.h" #include "llconsole.h" #include "lldrawable.h" -#include "llface.h" #include "llfirstuse.h" -#include "llfloater.h" +#include "llfloaterreg.h" #include "llfloateractivespeakers.h" -#include "llfloateravatarinfo.h" -#include "llfloaterbuildoptions.h" #include "llfloatercamera.h" -#include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterdirectory.h" -#include "llfloatergroupinfo.h" -#include "llfloatergroups.h" + #include "llfloaterland.h" -#include "llfloatermap.h" #include "llfloatermute.h" #include "llfloatersnapshot.h" #include "llfloatertools.h" #include "llfloaterworldmap.h" + +#include "llgroupactions.h" + +#include "llfocusmgr.h" #include "llgroupmgr.h" #include "llhomelocationresponder.h" -#include "llhudeffectlookat.h" +#include "llimview.h" #include "llhudmanager.h" -#include "llinventorymodel.h" -#include "llinventoryview.h" #include "lljoystickbutton.h" #include "llmenugl.h" #include "llmorphview.h" #include "llmoveview.h" -#include "llnotify.h" +#include "llparcel.h" #include "llquantize.h" +#include "llrand.h" +#include "llregionhandle.h" #include "llsdutil.h" #include "llselectmgr.h" #include "llsky.h" -#include "llrendersphere.h" +#include "llslurl.h" +#include "llsmoothstep.h" +#include "llsidetray.h" #include "llstatusbar.h" -#include "llstartup.h" -#include "llimview.h" +#include "llteleportflags.h" +#include "llteleporthistory.h" #include "lltool.h" #include "lltoolcomp.h" -#include "lltoolfocus.h" -#include "lltoolgrab.h" #include "lltoolmgr.h" -#include "lltoolpie.h" -#include "lltoolview.h" -#include "llui.h" // for make_ui_sound +#include "lluictrlfactory.h" #include "llurldispatcher.h" + #include "llviewercamera.h" -#include "llviewerinventory.h" -#include "llviewermenu.h" -#include "llviewernetwork.h" +#include "llviewerdisplay.h" +#include "llviewermediafocus.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" -#include "llviewerparceloverlay.h" -#include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" -#include "llviewerdisplay.h" -#include "llvoavatar.h" -#include "llvoground.h" -#include "llvosky.h" -#include "llwearable.h" -#include "llwearablelist.h" +#include "llviewercontrol.h" +#include "llviewerjoystick.h" + +#include "llvoavatarself.h" +#include "llwindow.h" #include "llworld.h" #include "llworldmap.h" + #include "pipeline.h" -#include "roles_constants.h" -#include "llviewercontrol.h" -#include "llappviewer.h" -#include "llviewerjoystick.h" -#include "llfollowcam.h" +#include "lltrans.h" +#include "llbottomtray.h" +#include "llnearbychatbar.h" #include "stringize.h" #include "llcapabilitylistener.h" +#include "llnavigationbar.h" //to show/hide navigation bar when changing mouse look state +#include "llagentui.h" + using namespace LLVOAvatarDefines; extern LLMenuBarGL* gMenuBarView; +const BOOL ANIMATE = TRUE; +const U8 AGENT_STATE_TYPING = 0x04; +const U8 AGENT_STATE_EDITING = 0x10; + //drone wandering constants const F32 MAX_WANDER_TIME = 20.f; // seconds const F32 MAX_HEADING_HALF_ERROR = 0.2f; // radians @@ -216,7 +190,7 @@ const F64 CHAT_AGE_FAST_RATE = 3.0; // The agent instance. LLAgent gAgent; -// +//-------------------------------------------------------------------- // Statics // @@ -242,6 +216,19 @@ void LLAgentFriendObserver::changed(U32 mask) } } +bool handleSlowMotionAnimation(const LLSD& newvalue) +{ + if (newvalue.asBoolean()) + { + gAgent.getAvatarObject()->setAnimTimeFactor(0.2f); + } + else + { + gAgent.getAvatarObject()->setAnimTimeFactor(1.0f); + } + return true; +} + // ************************************************************ // Enabled this definition to compile a 'hacked' viewer that // locally believes the end user has godlike powers. @@ -264,19 +251,12 @@ LLAgent::LLAgent() : mHideGroupTitle(FALSE), mGroupID(), - mMapOriginX(0.F), - mMapOriginY(0.F), - mMapWidth(0), - mMapHeight(0), - mLookAt(NULL), mPointAt(NULL), mHUDTargetZoom(1.f), mHUDCurZoom(1.f), mInitialized(FALSE), - mNumPendingQueries(0), - mActiveCacheQueries(NULL), mForceMouselook(FALSE), mDoubleTapRunTimer(), @@ -304,6 +284,8 @@ LLAgent::LLAgent() : mLastCameraMode( CAMERA_MODE_THIRD_PERSON ), mViewsPushed(FALSE), + mCameraPreset(CAMERA_PRESET_REAR_VIEW), + mCustomAnim(FALSE), mShowAvatar(TRUE), mCameraAnimating( FALSE ), @@ -317,7 +299,6 @@ LLAgent::LLAgent() : mCameraFocusOffset(), mCameraFOVDefault(DEFAULT_FIELD_OF_VIEW), - mCameraOffsetDefault(), mCameraCollidePlane(), mCurrentCameraDistance(2.f), // meters, set in init() @@ -384,7 +365,7 @@ LLAgent::LLAgent() : mAutoPilotFinishedCallback(NULL), mAutoPilotCallbackData(NULL), - mEffectColor(0.f, 1.f, 1.f, 1.f), + mEffectColor(LLColor4(0.f, 1.f, 1.f, 1.f)), mHaveHomePosition(FALSE), mHomeRegionHandle( 0 ), @@ -395,24 +376,14 @@ LLAgent::LLAgent() : mFirstLogin(FALSE), mGenderChosen(FALSE), - mAgentWearablesUpdateSerialNum(0), - mWearablesLoaded(FALSE), - mTextureCacheQueryID(0), mAppearanceSerialNum(0) { - U32 i; - for (i = 0; i < TOTAL_CONTROLS; i++) + for (U32 i = 0; i < TOTAL_CONTROLS; i++) { mControlsTakenCount[i] = 0; mControlsTakenPassedOnCount[i] = 0; } - mActiveCacheQueries = new S32[BAKED_NUM_INDICES]; - for (i = 0; i < (U32)BAKED_NUM_INDICES; i++) - { - mActiveCacheQueries[i] = 0; - } - mFollowCam.setMaxCameraDistantFromSubject( MAX_CAMERA_DISTANCE_FROM_AGENT ); } @@ -422,6 +393,9 @@ LLAgent::LLAgent() : //----------------------------------------------------------------------------- void LLAgent::init() { + gSavedSettings.declareBOOL("SlowMotionAnimation", FALSE, "Declared in code", FALSE); + gSavedSettings.getControl("SlowMotionAnimation")->getSignal()->connect(boost::bind(&handleSlowMotionAnimation, _2)); + mDrawDistance = gSavedSettings.getF32("RenderFarClip"); // *Note: this is where LLViewerCamera::getInstance() used to be constructed. @@ -430,22 +404,33 @@ void LLAgent::init() // Leave at 0.1 meters until we have real near clip management LLViewerCamera::getInstance()->setNear(0.1f); LLViewerCamera::getInstance()->setFar(mDrawDistance); // if you want to change camera settings, do so in camera.h - LLViewerCamera::getInstance()->setAspect( gViewerWindow->getDisplayAspectRatio() ); // default, overridden in LLViewerWindow::reshape + LLViewerCamera::getInstance()->setAspect( gViewerWindow->getWorldViewAspectRatio() ); // default, overridden in LLViewerWindow::reshape LLViewerCamera::getInstance()->setViewHeightInPixels(768); // default, overridden in LLViewerWindow::reshape setFlying( gSavedSettings.getBOOL("FlyingAtExit") ); mCameraFocusOffsetTarget = LLVector4(gSavedSettings.getVector3("CameraOffsetBuild")); - mCameraOffsetDefault = gSavedSettings.getVector3("CameraOffsetDefault"); + + mCameraPreset = (ECameraPreset) gSavedSettings.getU32("CameraPreset"); + + mCameraOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getVector3("CameraOffsetRearView"); + mCameraOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getVector3("CameraOffsetFrontView"); + mCameraOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getVector3("CameraOffsetGroupView"); + + mFocusOffsetInitial[CAMERA_PRESET_REAR_VIEW] = gSavedSettings.getVector3d("FocusOffsetRearView"); + mFocusOffsetInitial[CAMERA_PRESET_FRONT_VIEW] = gSavedSettings.getVector3d("FocusOffsetFrontView"); + mFocusOffsetInitial[CAMERA_PRESET_GROUP_VIEW] = gSavedSettings.getVector3d("FocusOffsetGroupView"); + mCameraCollidePlane.clearVec(); - mCurrentCameraDistance = mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale"); + mCurrentCameraDistance = getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale"); mTargetCameraDistance = mCurrentCameraDistance; mCameraZoomFraction = 1.f; mTrackFocusObject = gSavedSettings.getBOOL("TrackFocusObject"); -// LLDebugVarMessageBox::show("Camera Lag", &CAMERA_FOCUS_HALF_LIFE, 0.5f, 0.01f); + mEffectColor = LLUIColorTable::instance().getColor("EffectColor"); - mEffectColor = gSavedSettings.getColor4("EffectColor"); + gSavedSettings.getControl("PreferredMaturity")->getValidateSignal()->connect(boost::bind(&LLAgent::validateMaturity, this, _2)); + gSavedSettings.getControl("PreferredMaturity")->getSignal()->connect(boost::bind(&LLAgent::handleMaturity, this, _2)); mInitialized = TRUE; } @@ -456,7 +441,9 @@ void LLAgent::init() void LLAgent::cleanup() { setSitCamera(LLUUID::null); + mAvatarObject = NULL; + if(mLookAt) { mLookAt->markDead() ; @@ -478,9 +465,6 @@ LLAgent::~LLAgent() { cleanup(); - delete [] mActiveCacheQueries; - mActiveCacheQueries = NULL; - // *Note: this is where LLViewerCamera::getInstance() used to be deleted. } @@ -529,12 +513,16 @@ void LLAgent::resetView(BOOL reset_camera, BOOL change_camera) LLViewerJoystick::getInstance()->moveAvatar(true); } - gFloaterTools->close(); + //Camera Tool is needed for Free Camera Control Mode + if (!LLFloaterCamera::inFreeCameraMode()) + { + LLFloaterReg::hideInstance("build"); + + // Switch back to basic toolset + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + } gViewerWindow->showCursor(); - - // Switch back to basic toolset - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); } @@ -785,7 +773,7 @@ void LLAgent::setFlying(BOOL fly) } // don't allow taking off while sitting - if (fly && mAvatarObject->mIsSitting) + if (fly && mAvatarObject->isSitting()) { return; } @@ -814,6 +802,11 @@ void LLAgent::setFlying(BOOL fly) clearControlFlags(AGENT_CONTROL_FLY); gSavedSettings.setBOOL("FlyBtnState", FALSE); } + + + // Update Movement Controls according to Fly mode + LLFloaterMove::setFlyingMode(fly); + mbFlagsDirty = TRUE; } @@ -822,12 +815,29 @@ void LLAgent::setFlying(BOOL fly) //----------------------------------------------------------------------------- // toggleFlying() //----------------------------------------------------------------------------- +// static void LLAgent::toggleFlying() { - BOOL fly = !(mControlFlags & AGENT_CONTROL_FLY); + BOOL fly = !(gAgent.mControlFlags & AGENT_CONTROL_FLY); - setFlying( fly ); - resetView(); + gAgent.setFlying( fly ); + gAgent.resetView(); +} + +// static +bool LLAgent::enableFlying() +{ + BOOL sitting = FALSE; + if (gAgent.getAvatarObject()) + { + sitting = gAgent.getAvatarObject()->isSitting(); + } + return !sitting; +} + +void LLAgent::standUp() +{ + setControlFlags(AGENT_CONTROL_STAND_UP); } @@ -904,6 +914,8 @@ void LLAgent::setRegion(LLViewerRegion *regionp) mRegionsVisited.insert(handle); LLSelectMgr::getInstance()->updateSelectionCenter(); + + LLFloaterMove::sUpdateFlyingStatus(); } @@ -928,25 +940,6 @@ LLHost LLAgent::getRegionHost() const } } -//----------------------------------------------------------------------------- -// getSLURL() -// returns empty() if getRegion() == NULL -//----------------------------------------------------------------------------- -std::string LLAgent::getSLURL() const -{ - std::string slurl; - LLViewerRegion *regionp = getRegion(); - if (regionp) - { - LLVector3d agentPos = getPositionGlobal(); - S32 x = llround( (F32)fmod( agentPos.mdV[VX], (F64)REGION_WIDTH_METERS ) ); - S32 y = llround( (F32)fmod( agentPos.mdV[VY], (F64)REGION_WIDTH_METERS ) ); - S32 z = llround( (F32)agentPos.mdV[VZ] ); - slurl = LLURLDispatcher::buildSLURL(regionp->getName(), x, y, z); - } - return slurl; -} - //----------------------------------------------------------------------------- // inPrelude() //----------------------------------------------------------------------------- @@ -1260,7 +1253,7 @@ F32 LLAgent::clampPitchToLimits(F32 angle) F32 angle_from_skyward = acos( mFrameAgent.getAtAxis() * skyward ); - if (mAvatarObject.notNull() && mAvatarObject->mIsSitting) + if (mAvatarObject.notNull() && mAvatarObject->isSitting()) { look_down_limit = 130.f * DEG_TO_RAD; } @@ -1890,7 +1883,7 @@ void LLAgent::cameraOrbitIn(const F32 meters) { if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON) { - F32 camera_offset_dist = llmax(0.001f, mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale")); + F32 camera_offset_dist = llmax(0.001f, getCameraOffsetInitial().magVec() * gSavedSettings.getF32("CameraOffsetScale")); mCameraZoomFraction = (mTargetCameraDistance - meters) / camera_offset_dist; @@ -2124,8 +2117,7 @@ void LLAgent::setAFK() gAwayTimer.start(); if (gAFKMenu) { - //*TODO:Translate - gAFKMenu->setLabel(std::string("Set Not Away")); + gAFKMenu->setLabel(LLTrans::getString("AvatarSetNotAway")); } } } @@ -2148,8 +2140,7 @@ void LLAgent::clearAFK() clearControlFlags(AGENT_CONTROL_AWAY); if (gAFKMenu) { - //*TODO:Translate - gAFKMenu->setLabel(std::string("Set Away")); + gAFKMenu->setLabel(LLTrans::getString("AvatarSetAway")); } } } @@ -2171,10 +2162,8 @@ void LLAgent::setBusy() mIsBusy = TRUE; if (gBusyMenu) { - //*TODO:Translate - gBusyMenu->setLabel(std::string("Set Not Busy")); + gBusyMenu->setLabel(LLTrans::getString("AvatarSetNotBusy")); } - LLFloaterMute::getInstance()->updateButtons(); } //----------------------------------------------------------------------------- @@ -2186,10 +2175,8 @@ void LLAgent::clearBusy() sendAnimationRequest(ANIM_AGENT_BUSY, ANIM_REQUEST_STOP); if (gBusyMenu) { - //*TODO:Translate - gBusyMenu->setLabel(std::string("Set Busy")); + gBusyMenu->setLabel(LLTrans::getString("AvatarSetBusy")); } - LLFloaterMute::getInstance()->updateButtons(); } //----------------------------------------------------------------------------- @@ -2512,13 +2499,11 @@ void LLAgent::autoPilot(F32 *delta_yaw) void LLAgent::propagate(const F32 dt) { // Update UI based on agent motion - LLFloaterMove *floater_move = LLFloaterMove::getInstance(); + LLFloaterMove *floater_move = LLFloaterReg::findTypedInstance("moveview"); if (floater_move) { floater_move->mForwardButton ->setToggleState( mAtKey > 0 || mWalkKey > 0 ); floater_move->mBackwardButton ->setToggleState( mAtKey < 0 || mWalkKey < 0 ); - floater_move->mSlideLeftButton ->setToggleState( mLeftKey > 0 ); - floater_move->mSlideRightButton->setToggleState( mLeftKey < 0 ); floater_move->mTurnLeftButton ->setToggleState( mYawKey > 0.f ); floater_move->mTurnRightButton ->setToggleState( mYawKey < 0.f ); floater_move->mMoveUpButton ->setToggleState( mUpKey > 0 ); @@ -2603,7 +2588,7 @@ void LLAgent::updateLookAt(const S32 mouse_x, const S32 mouse_y) else { // *FIX: rotate mframeagent by sit object's rotation? - LLQuaternion look_rotation = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); // use camera's current rotation + LLQuaternion look_rotation = mAvatarObject->isSitting() ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); // use camera's current rotation LLVector3 look_offset = LLVector3(2.f, 0.f, 0.f) * look_rotation * av_inv_rot; setLookAt(LOOKAT_TARGET_IDLE, mAvatarObject, look_offset); } @@ -2669,7 +2654,7 @@ std::ostream& operator<<(std::ostream &s, const LLAgent &agent) //----------------------------------------------------------------------------- // setAvatarObject() //----------------------------------------------------------------------------- -void LLAgent::setAvatarObject(LLVOAvatar *avatar) +void LLAgent::setAvatarObject(LLVOAvatarSelf *avatar) { mAvatarObject = avatar; @@ -2696,8 +2681,6 @@ void LLAgent::setAvatarObject(LLVOAvatar *avatar) { mPointAt->setSourceObject(avatar); } - - sendAgentWearablesRequest(); } // TRUE if your own avatar needs to be rendered. Usually only @@ -2748,7 +2731,7 @@ void LLAgent::startTyping() { sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_START); } - gChatBar->sendChatFromViewer("", CHAT_TYPE_START, FALSE); + LLNearbyChatBar::getInstance()->sendChatFromViewer("", CHAT_TYPE_START, FALSE); } //----------------------------------------------------------------------------- @@ -2760,7 +2743,7 @@ void LLAgent::stopTyping() { clearRenderState(AGENT_STATE_TYPING); sendAnimationRequest(ANIM_AGENT_TYPE, ANIM_REQUEST_STOP); - gChatBar->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); + LLNearbyChatBar::getInstance()->sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); } } @@ -2814,13 +2797,6 @@ U8 LLAgent::getRenderState() //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -static const LLFloaterView::skip_list_t& get_skip_list() -{ - static LLFloaterView::skip_list_t skip_list; - skip_list.insert(LLFloaterMap::getInstance()); - return skip_list; -} - //----------------------------------------------------------------------------- // endAnimationUpdateUI() //----------------------------------------------------------------------------- @@ -2839,17 +2815,33 @@ void LLAgent::endAnimationUpdateUI() gViewerWindow->showCursor(); // show menus gMenuBarView->setVisible(TRUE); + LLNavigationBar::getInstance()->setVisible(TRUE); gStatusBar->setVisibleForMouselook(true); + LLBottomTray::getInstance()->setVisible(TRUE); + + LLSideTray::getInstance()->setVisible(TRUE); + + LLPanelStandStopFlying::getInstance()->setVisible(TRUE); + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLFloaterCamera::toPrevModeIfInAvatarViewMode(); + // Only pop if we have pushed... if (TRUE == mViewsPushed) { +#if 0 // Use this once all floaters are registered + LLFloaterReg::restoreVisibleInstances(); +#else // Use this for now + LLFloaterView::skip_list_t skip_list; + skip_list.insert(LLFloaterReg::findInstance("mini_map")); + gFloaterView->popVisibleAll(skip_list); +#endif mViewsPushed = FALSE; - gFloaterView->popVisibleAll(get_skip_list()); } + gAgent.setLookAt(LOOKAT_TARGET_CLEAR); if( gMorphView ) { @@ -2891,13 +2883,6 @@ void LLAgent::endAnimationUpdateUI() LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - // HACK: If we're quitting, and we were in customize avatar, don't - // let the mini-map go visible again. JC - if (!LLAppViewer::instance()->quitRequested()) - { - LLFloaterMap::getInstance()->popVisible(); - } - if( gMorphView ) { gMorphView->setVisible( FALSE ); @@ -2924,26 +2909,46 @@ void LLAgent::endAnimationUpdateUI() { // hide menus gMenuBarView->setVisible(FALSE); + LLNavigationBar::getInstance()->setVisible(FALSE); gStatusBar->setVisibleForMouselook(false); + LLBottomTray::getInstance()->setVisible(FALSE); + + LLSideTray::getInstance()->setVisible(FALSE); + + LLPanelStandStopFlying::getInstance()->setVisible(FALSE); + // clear out camera lag effect mCameraLag.clearVec(); // JC - Added for always chat in third person option gFocusMgr.setKeyboardFocus(NULL); + //Making sure Camera Controls floater is in the right state + //when entering Mouse Look using wheel scrolling + LLFloaterCamera::updateIfNotInAvatarViewMode(); + LLToolMgr::getInstance()->setCurrentToolset(gMouselookToolset); mViewsPushed = TRUE; - gFloaterView->pushVisibleAll(FALSE, get_skip_list()); + // hide all floaters except the mini map + +#if 0 // Use this once all floaters are registered + std::set exceptions; + exceptions.insert("mini_map"); + LLFloaterReg::hideVisibleInstances(exceptions); +#else // Use this for now + LLFloaterView::skip_list_t skip_list; + skip_list.insert(LLFloaterReg::findInstance("mini_map")); + gFloaterView->pushVisibleAll(FALSE, skip_list); +#endif if( gMorphView ) { gMorphView->setVisible(FALSE); } - gIMMgr->setFloaterOpen( FALSE ); gConsole->setVisible( TRUE ); if (mAvatarObject.notNull()) @@ -2992,15 +2997,6 @@ void LLAgent::endAnimationUpdateUI() { LLToolMgr::getInstance()->setCurrentToolset(gFaceEditToolset); - LLFloaterMap::getInstance()->pushVisible(FALSE); - /* - LLView *view; - for (view = gFloaterView->getFirstChild(); view; view = gFloaterView->getNextChild()) - { - view->pushVisible(FALSE); - } - */ - if( gMorphView ) { gMorphView->setVisible( TRUE ); @@ -3042,7 +3038,7 @@ void LLAgent::updateCamera() validateFocusObject(); if (mAvatarObject.notNull() && - mAvatarObject->mIsSitting && + mAvatarObject->isSitting() && camera_mode == CAMERA_MODE_MOUSELOOK) { //Ventrella @@ -3073,21 +3069,25 @@ void LLAgent::updateCamera() } // Update UI with our camera inputs - LLFloaterCamera::getInstance()->mRotate->setToggleState( + LLFloaterCamera* camera_floater = LLFloaterReg::findTypedInstance("camera"); + if (camera_floater) + { + camera_floater->mRotate->setToggleState( mOrbitRightKey > 0.f, // left mOrbitUpKey > 0.f, // top mOrbitLeftKey > 0.f, // right mOrbitDownKey > 0.f); // bottom - LLFloaterCamera::getInstance()->mZoom->setToggleState( + camera_floater->mZoom->setToggleState( mOrbitInKey > 0.f, // top mOrbitOutKey > 0.f); // bottom - LLFloaterCamera::getInstance()->mTrack->setToggleState( + camera_floater->mTrack->setToggleState( mPanLeftKey > 0.f, // left mPanUpKey > 0.f, // top mPanRightKey > 0.f, // right mPanDownKey > 0.f); // bottom + } // Handle camera movement based on keyboard. const F32 ORBIT_OVER_RATE = 90.f * DEG_TO_RAD; // radians per second @@ -3163,7 +3163,7 @@ void LLAgent::updateCamera() // (2) focus, and (3) upvector. They can then be queried elsewhere in llAgent. //-------------------------------------------------------------------------------- // *TODO: use combined rotation of frameagent and sit object - LLQuaternion avatarRotationForFollowCam = mAvatarObject->mIsSitting ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); + LLQuaternion avatarRotationForFollowCam = mAvatarObject->isSitting() ? mAvatarObject->getRenderRotation() : mFrameAgent.getQuaternion(); LLFollowCamParams* current_cam = LLFollowCamMgr::getActiveFollowCamParams(); if (current_cam) @@ -3343,7 +3343,7 @@ void LLAgent::updateCamera() } mLastPositionGlobal = global_pos; - if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->mIsSitting && cameraMouselook()) + if (LLVOAvatar::sVisibleInFirstPerson && mAvatarObject.notNull() && !mAvatarObject->isSitting() && cameraMouselook()) { LLVector3 head_pos = mAvatarObject->mHeadp->getWorldPosition() + LLVector3(0.08f, 0.f, 0.05f) * mAvatarObject->mHeadp->getWorldRotation() + @@ -3523,7 +3523,7 @@ LLVector3d LLAgent::calcFocusPositionTargetGlobal() } return mFocusTargetGlobal; } - else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->mIsSitting && mSitCameraReferenceObject.notNull()) + else if (mSitCameraEnabled && mAvatarObject.notNull() && mAvatarObject->isSitting() && mSitCameraReferenceObject.notNull()) { // sit camera LLVector3 object_pos = mSitCameraReferenceObject->getRenderPosition(); @@ -3542,7 +3542,6 @@ LLVector3d LLAgent::calcThirdPersonFocusOffset() { // ...offset from avatar LLVector3d focus_offset; - focus_offset.setVec(gSavedSettings.getVector3("FocusOffsetDefault")); LLQuaternion agent_rot = mFrameAgent.getQuaternion(); if (!mAvatarObject.isNull() && mAvatarObject->getParent()) @@ -3550,7 +3549,7 @@ LLVector3d LLAgent::calcThirdPersonFocusOffset() agent_rot *= ((LLViewerObject*)(mAvatarObject->getParent()))->getRenderRotation(); } - focus_offset = focus_offset * agent_rot; + focus_offset = mFocusOffsetInitial[mCameraPreset] * agent_rot; return focus_offset; } @@ -3627,7 +3626,6 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) LLVector3d frame_center_global = mAvatarObject.isNull() ? getPositionGlobal() : getPosGlobalFromAgent(mAvatarObject->mRoot.getWorldPosition()); - LLVector3 upAxis = getUpAxis(); BOOL isConstrained = FALSE; LLVector3d head_offset; head_offset.setVec(mThirdPersonHeadOffset); @@ -3647,7 +3645,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) return LLVector3d::zero; } head_offset.clearVec(); - if (mAvatarObject->mIsSitting && mAvatarObject->getParent()) + if (mAvatarObject->isSitting() && mAvatarObject->getParent()) { mAvatarObject->updateHeadOffset(); head_offset.mdV[VX] = mAvatarObject->mHeadOffset.mV[VX]; @@ -3661,7 +3659,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) else { head_offset.mdV[VZ] = mAvatarObject->mHeadOffset.mV[VZ]; - if (mAvatarObject->mIsSitting) + if (mAvatarObject->isSitting()) { head_offset.mdV[VZ] += 0.1; } @@ -3677,7 +3675,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) if (mSitCameraEnabled && mAvatarObject.notNull() - && mAvatarObject->mIsSitting + && mAvatarObject->isSitting() && mSitCameraReferenceObject.notNull()) { // sit camera @@ -3690,7 +3688,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) } else { - local_camera_offset = mCameraZoomFraction * mCameraOffsetDefault * gSavedSettings.getF32("CameraOffsetScale"); + local_camera_offset = mCameraZoomFraction * getCameraOffsetInitial() * gSavedSettings.getF32("CameraOffsetScale"); // are we sitting down? if (mAvatarObject.notNull() && mAvatarObject->getParent()) @@ -3709,7 +3707,7 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) local_camera_offset = mFrameAgent.rotateToAbsolute( local_camera_offset ); } - if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->mIsSitting)) + if (!mCameraCollidePlane.isExactlyZero() && (mAvatarObject.isNull() || !mAvatarObject->isSitting())) { LLVector3 plane_normal; plane_normal.setVec(mCameraCollidePlane.mV); @@ -3887,6 +3885,12 @@ LLVector3d LLAgent::calcCameraPositionTargetGlobal(BOOL *hit_limit) } +LLVector3 LLAgent::getCameraOffsetInitial() +{ + return mCameraOffsetInitial[mCameraPreset]; +} + + //----------------------------------------------------------------------------- // handleScrollWheel() //----------------------------------------------------------------------------- @@ -3921,10 +3925,12 @@ void LLAgent::handleScrollWheel(S32 clicks) } else if (mFocusOnAvatar && mCameraMode == CAMERA_MODE_THIRD_PERSON) { - F32 current_zoom_fraction = mTargetCameraDistance / (mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale")); + F32 camera_offset_initial_mag = getCameraOffsetInitial().magVec(); + + F32 current_zoom_fraction = mTargetCameraDistance / (camera_offset_initial_mag * gSavedSettings.getF32("CameraOffsetScale")); current_zoom_fraction *= 1.f - pow(ROOT_ROOT_TWO, clicks); - cameraOrbitIn(current_zoom_fraction * mCameraOffsetDefault.magVec() * gSavedSettings.getF32("CameraOffsetScale")); + cameraOrbitIn(current_zoom_fraction * camera_offset_initial_mag * gSavedSettings.getF32("CameraOffsetScale")); } else { @@ -4135,7 +4141,7 @@ void LLAgent::changeCameraToThirdPerson(BOOL animate) if (mAvatarObject.notNull()) { - if (!mAvatarObject->mIsSitting) + if (!mAvatarObject->isSitting()) { mAvatarObject->mPelvisp->setPosition(LLVector3::zero); } @@ -4217,7 +4223,7 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_ani return; } - setControlFlags(AGENT_CONTROL_STAND_UP); // force stand up + standUp(); // force stand up gViewerWindow->getWindow()->resetBusyCount(); if (gFaceEditToolset) @@ -4255,7 +4261,7 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_ani gFocusMgr.setKeyboardFocus( NULL ); gFocusMgr.setMouseCapture( NULL ); - LLVOAvatar::onCustomizeStart(); + LLVOAvatarSelf::onCustomizeStart(); } if (mAvatarObject.notNull()) @@ -4297,6 +4303,20 @@ void LLAgent::changeCameraToCustomizeAvatar(BOOL avatar_animate, BOOL camera_ani } +void LLAgent::switchCameraPreset(ECameraPreset preset) +{ + //zoom is supposed to be reset for the front and group views + mCameraZoomFraction = 1.f; + + //focusing on avatar in that case means following him on movements + mFocusOnAvatar = TRUE; + + mCameraPreset = preset; + + gSavedSettings.setU32("CameraPreset", mCameraPreset); +} + + // // Focus point management // @@ -4940,6 +4960,9 @@ int LLAgent::convertTextToMaturity(char text) bool LLAgent::sendMaturityPreferenceToServer(int preferredMaturity) { + if (!getRegion()) + return false; + // Update agent access preference on the server std::string url = getRegion()->getCapability("UpdateAgentInformation"); if (!url.empty()) @@ -4999,15 +5022,19 @@ const LLAgentAccess& LLAgent::getAgentAccess() return mAgentAccess; } - -void LLAgent::buildFullname(std::string& name) const +bool LLAgent::validateMaturity(const LLSD& newvalue) { - if (mAvatarObject.notNull()) - { - name = mAvatarObject->getFullname(); - } + return mAgentAccess.canSetMaturity(newvalue.asInteger()); } +void LLAgent::handleMaturity(const LLSD& newvalue) +{ + sendMaturityPreferenceToServer(newvalue.asInteger()); +} + +//---------------------------------------------------------------------------- + +//*TODO remove, is not used anywhere as of August 20, 2009 void LLAgent::buildFullnameAndTitle(std::string& name) const { if (isGroupMember()) @@ -5161,54 +5188,6 @@ BOOL LLAgent::setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOO return FALSE; } -// utility to build a location string -void LLAgent::buildLocationString(std::string& str) -{ - const LLVector3& agent_pos_region = getPositionAgent(); - S32 pos_x = S32(agent_pos_region.mV[VX]); - S32 pos_y = S32(agent_pos_region.mV[VY]); - S32 pos_z = S32(agent_pos_region.mV[VZ]); - - // Round the numbers based on the velocity - LLVector3 agent_velocity = getVelocity(); - F32 velocity_mag_sq = agent_velocity.magVecSquared(); - - const F32 FLY_CUTOFF = 6.f; // meters/sec - const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF; - const F32 WALK_CUTOFF = 1.5f; // meters/sec - const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF; - - if (velocity_mag_sq > FLY_CUTOFF_SQ) - { - pos_x -= pos_x % 4; - pos_y -= pos_y % 4; - } - else if (velocity_mag_sq > WALK_CUTOFF_SQ) - { - pos_x -= pos_x % 2; - pos_y -= pos_y % 2; - } - - // create a defult name and description for the landmark - std::string buffer; - if( LLViewerParcelMgr::getInstance()->getAgentParcelName().empty() ) - { - // the parcel doesn't have a name - buffer = llformat("%.32s (%d, %d, %d)", - getRegion()->getName().c_str(), - pos_x, pos_y, pos_z); - } - else - { - // the parcel has a name, so include it in the landmark name - buffer = llformat("%.32s, %.32s (%d, %d, %d)", - LLViewerParcelMgr::getInstance()->getAgentParcelName().c_str(), - getRegion()->getName().c_str(), - pos_x, pos_y, pos_z); - } - str = buffer; -} - LLQuaternion LLAgent::getHeadRotation() { if (mAvatarObject.isNull() || !mAvatarObject->mPelvisp || !mAvatarObject->mHeadp) @@ -5370,30 +5349,6 @@ BOOL LLAgent::allowOperation(PermissionBit op, return perm.allowOperationBy(op, agent_proxy, group_proxy); } - -void LLAgent::getName(std::string& name) -{ - name.clear(); - - if (mAvatarObject.notNull()) - { - LLNameValue *first_nv = mAvatarObject->getNVPair("FirstName"); - LLNameValue *last_nv = mAvatarObject->getNVPair("LastName"); - if (first_nv && last_nv) - { - name = first_nv->printData() + " " + last_nv->printData(); - } - else - { - llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl; - } - } - else - { - name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName"); - } -} - const LLColor4 &LLAgent::getEffectColor() { return mEffectColor; @@ -5409,16 +5364,46 @@ void LLAgent::initOriginGlobal(const LLVector3d &origin_global) mAgentOriginGlobal = origin_global; } +BOOL LLAgent::leftButtonGrabbed() const +{ + return (!cameraMouselook() && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (cameraMouselook() && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0) + || (!cameraMouselook() && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) + || (cameraMouselook() && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0); +} + +BOOL LLAgent::rotateGrabbed() const +{ + return (mControlsTakenCount[CONTROL_YAW_POS_INDEX] > 0) + || (mControlsTakenCount[CONTROL_YAW_NEG_INDEX] > 0); +} + +BOOL LLAgent::forwardGrabbed() const +{ + return (mControlsTakenCount[CONTROL_AT_POS_INDEX] > 0); +} + +BOOL LLAgent::backwardGrabbed() const +{ + return (mControlsTakenCount[CONTROL_AT_NEG_INDEX] > 0); +} + +BOOL LLAgent::upGrabbed() const +{ + return (mControlsTakenCount[CONTROL_UP_POS_INDEX] > 0); +} + +BOOL LLAgent::downGrabbed() const +{ + return (mControlsTakenCount[CONTROL_UP_NEG_INDEX] > 0); +} + void update_group_floaters(const LLUUID& group_id) { - LLFloaterGroupInfo::refreshGroup(group_id); - - // update avatar info - LLFloaterAvatarInfo* fa = LLFloaterAvatarInfo::getInstance(gAgent.getID()); - if(fa) - { - fa->resetGroupList(); - } + + LLGroupActions::refresh(group_id); + //*TODO Implement group update for Profile View + // still actual as of July 31, 2009 (DZ) if (gIMMgr) { @@ -5464,7 +5449,7 @@ void LLAgent::processAgentDropGroup(LLMessageSystem *msg, void **) LLGroupMgr::getInstance()->clearGroupData(group_id); // close the floater for this group, if any. - LLFloaterGroupInfo::closeGroup(group_id); + LLGroupActions::closeGroup(group_id); // refresh the group panel of the search window, if necessary. LLFloaterDirectory::refreshGroup(group_id); } @@ -5487,7 +5472,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode !input.has("body") ) { //what to do with badly formed message? - response->status(400); + response->statusUnknownError(400); response->result(LLSD("Invalid message parameters")); } @@ -5543,7 +5528,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode LLGroupMgr::getInstance()->clearGroupData(group_id); // close the floater for this group, if any. - LLFloaterGroupInfo::closeGroup(group_id); + LLGroupActions::closeGroup(group_id); // refresh the group panel of the search window, //if necessary. LLFloaterDirectory::refreshGroup(group_id); @@ -5560,7 +5545,7 @@ class LLAgentDropGroupViewerNode : public LLHTTPNode else { //what to do with badly formed message? - response->status(400); + response->statusUnknownError(400); response->result(LLSD("Invalid message parameters")); } } @@ -5854,9 +5839,9 @@ void LLAgent::processControlRelease(LLMessageSystem *msg, void **) //static void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data) { - gAgent.mNumPendingQueries--; + gAgentQueryManager.mNumPendingQueries--; - LLVOAvatar* avatarp = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); if (!avatarp || avatarp->isDead()) { llwarns << "No avatar for user in cached texture update!" << llendl; @@ -5886,12 +5871,12 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * if (texture_id.notNull() && (S32)texture_index < BAKED_NUM_INDICES - && gAgent.mActiveCacheQueries[ texture_index ] == query_id) + && gAgentQueryManager.mActiveCacheQueries[texture_index] == query_id) { //llinfos << "Received cached texture " << (U32)texture_index << ": " << texture_id << llendl; - avatarp->setCachedBakedTexture(getTextureIndex((EBakedTextureIndex)texture_index), texture_id); + avatarp->setCachedBakedTexture(LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)texture_index), texture_id); //avatarp->setTETexture( LLVOAvatar::sBakedTextureIndices[texture_index], texture_id ); - gAgent.mActiveCacheQueries[ texture_index ] = 0; + gAgentQueryManager.mActiveCacheQueries[texture_index] = 0; num_results++; } } @@ -5900,7 +5885,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * avatarp->updateMeshTextures(); - if (gAgent.mNumPendingQueries == 0) + if (gAgentQueryManager.mNumPendingQueries == 0) { // RN: not sure why composites are disabled at this point avatarp->setCompositeUpdatesEnabled(TRUE); @@ -5910,8 +5895,7 @@ void LLAgent::processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void * BOOL LLAgent::anyControlGrabbed() const { - U32 i; - for (i = 0; i < TOTAL_CONTROLS; i++) + for (U32 i = 0; i < TOTAL_CONTROLS; i++) { if (gAgent.mControlsTakenCount[i] > 0) return TRUE; @@ -6003,13 +5987,14 @@ bool LLAgent::teleportCore(bool is_local) // process_teleport_location_reply // close the map and find panels so we can see our destination - LLFloaterWorldMap::hide(NULL); - LLFloaterDirectory::hide(NULL); + LLFloaterReg::hideInstance("world_map"); + LLFloaterReg::hideInstance("search"); // hide land floater too - it'll be out of date - LLFloaterLand::hideInstance(); - + LLFloaterReg::hideInstance("about_land"); + LLViewerParcelMgr::getInstance()->deselectLand(); + LLViewerMediaFocus::getInstance()->setFocusFace(false, NULL, 0, NULL); // Close all pie menus, deselect land, etc. // Don't change the camera until we know teleport succeeded. JC @@ -6169,12 +6154,17 @@ void LLAgent::setTeleportState(ETeleportState state) mTeleportState = state; if (mTeleportState > TELEPORT_NONE && gSavedSettings.getBOOL("FreezeTime")) { - LLFloaterSnapshot::hide(0); + LLFloaterReg::hideInstance("snapshot"); } if (mTeleportState == TELEPORT_MOVING) { // We're outa here. Save "back" slurl. - mTeleportSourceSLURL = getSLURL(); + mTeleportSourceSLURL = LLAgentUI::buildSLURL(); + } + else if(mTeleportState == TELEPORT_ARRIVING) + { + // Let the interested parties know we've teleported. + LLViewerParcelMgr::getInstance()->onTeleportFinished(false, getPositionGlobal()); } } @@ -6303,878 +6293,6 @@ void LLAgent::requestLeaveGodMode() sendReliableMessage(); } -// wearables -LLAgent::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() -{ - gAgent.createStandardWearablesAllDone(); -} - -LLAgent::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() -{ - gAgent.sendAgentWearablesUpdate(); -} - -LLAgent::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( - LLPointer cb, S32 index, LLWearable* wearable, U32 todo) : - mIndex(index), - mWearable(wearable), - mTodo(todo), - mCB(cb) -{ -} - -void LLAgent::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) -{ - if (inv_item.isNull()) - return; - - gAgent.addWearabletoAgentInventoryDone(mIndex, inv_item, mWearable); - - if (mTodo & CALL_UPDATE) - { - gAgent.sendAgentWearablesUpdate(); - } - if (mTodo & CALL_RECOVERDONE) - { - gAgent.recoverMissingWearableDone(); - } - /* - * Do this for every one in the loop - */ - if (mTodo & CALL_CREATESTANDARDDONE) - { - gAgent.createStandardWearablesDone(mIndex); - } - if (mTodo & CALL_MAKENEWOUTFITDONE) - { - gAgent.makeNewOutfitDone(mIndex); - } -} - -void LLAgent::addWearabletoAgentInventoryDone( - S32 index, - const LLUUID& item_id, - LLWearable* wearable) -{ - if (item_id.isNull()) - return; - - LLUUID old_item_id = mWearableEntry[index].mItemID; - mWearableEntry[index].mItemID = item_id; - mWearableEntry[index].mWearable = wearable; - if (old_item_id.notNull()) - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); - LLViewerInventoryItem* item = gInventory.getItem(item_id); - if(item && wearable) - { - // We're changing the asset id, so we both need to set it - // locally via setAssetUUID() and via setTransactionID() which - // will be decoded on the server. JC - item->setAssetUUID(wearable->getID()); - item->setTransactionID(wearable->getTransactionID()); - gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); - item->updateServer(FALSE); - } - gInventory.notifyObservers(); -} - -void LLAgent::sendAgentWearablesUpdate() -{ - // First make sure that we have inventory items for each wearable - S32 i; - for(i=0; i < WT_COUNT; ++i) - { - LLWearable* wearable = mWearableEntry[ i ].mWearable; - if (wearable) - { - if( mWearableEntry[ i ].mItemID.isNull() ) - { - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - i, - wearable, - addWearableToAgentInventoryCallback::CALL_NONE); - addWearableToAgentInventory(cb, wearable); - } - else - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, - mWearableEntry[i].mItemID ); - } - } - } - - // Then make sure the inventory is in sync with the avatar. - gInventory.notifyObservers(); - - // Send the AgentIsNowWearing - gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); - - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); - - lldebugs << "sendAgentWearablesUpdate()" << llendl; - for(i=0; i < WT_COUNT; ++i) - { - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - - U8 type_u8 = (U8)i; - gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8 ); - - LLWearable* wearable = mWearableEntry[ i ].mWearable; - if( wearable ) - { - //llinfos << "Sending wearable " << wearable->getName() << llendl; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, mWearableEntry[ i ].mItemID ); - } - else - { - //llinfos << "Not wearing wearable type " << LLWearable::typeToTypeName((EWearableType)i) << llendl; - gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null ); - } - - lldebugs << " " << LLWearable::typeToTypeLabel((EWearableType)i) << ": " << (wearable ? wearable->getID() : LLUUID::null) << llendl; - } - gAgent.sendReliableMessage(); -} - -void LLAgent::saveWearable( EWearableType type, BOOL send_update ) -{ - LLWearable* old_wearable = mWearableEntry[(S32)type].mWearable; - if( old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion()) ) - { - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable ); - mWearableEntry[(S32)type].mWearable = new_wearable; - - LLInventoryItem* item = gInventory.getItem(mWearableEntry[(S32)type].mItemID); - if( item ) - { - // Update existing inventory item - LLPointer template_item = - new LLViewerInventoryItem(item->getUUID(), - item->getParentUUID(), - item->getPermissions(), - new_wearable->getID(), - new_wearable->getAssetType(), - item->getInventoryType(), - item->getName(), - item->getDescription(), - item->getSaleInfo(), - item->getFlags(), - item->getCreationDate()); - template_item->setTransactionID(new_wearable->getTransactionID()); - template_item->updateServer(FALSE); - gInventory.updateItem(template_item); - } - else - { - // Add a new inventory item (shouldn't ever happen here) - U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (send_update) - { - todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - (S32)type, - new_wearable, - todo); - addWearableToAgentInventory(cb, new_wearable); - return; - } - - getAvatarObject()->wearableUpdated( type ); - - if( send_update ) - { - sendAgentWearablesUpdate(); - } - } -} - -void LLAgent::saveWearableAs( - EWearableType type, - const std::string& new_name, - BOOL save_in_lost_and_found) -{ - if(!isWearableCopyable(type)) - { - llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; - return; - } - LLWearable* old_wearable = getWearable(type); - if(!old_wearable) - { - llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; - return; - } - LLInventoryItem* item = gInventory.getItem(mWearableEntry[type].mItemID); - if(!item) - { - llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; - return; - } - std::string trunc_name(new_name); - LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( - old_wearable, - trunc_name); - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - new_wearable, - addWearableToAgentInventoryCallback::CALL_UPDATE); - LLUUID category_id; - if (save_in_lost_and_found) - { - category_id = gInventory.findCategoryUUIDForType( - LLAssetType::AT_LOST_AND_FOUND); - } - else - { - // put in same folder as original - category_id = item->getParentUUID(); - } - - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - category_id, - new_name, - cb); - -/* - LLWearable* old_wearable = getWearable( type ); - if( old_wearable ) - { - std::string old_name = old_wearable->getName(); - old_wearable->setName( new_name ); - LLWearable* new_wearable = gWearableList.createCopyFromAvatar( old_wearable ); - old_wearable->setName( old_name ); - - LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID ); - if( item ) - { - new_wearable->setPermissions(item->getPermissions()); - if (save_in_lost_and_found) - { - category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); - } - else - { - // put in same folder as original - category_id = item->getParentUUID(); - } - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(view) - { - view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); - } - } - - mWearableEntry[ type ].mWearable = new_wearable; - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - addWearableToAgentInventoryCallback::CALL_UPDATE); - addWearableToAgentInventory(cb, new_wearable, category_id); - } -*/ -} - -void LLAgent::revertWearable( EWearableType type ) -{ - LLWearable* wearable = mWearableEntry[(S32)type].mWearable; - if( wearable ) - { - wearable->writeToAvatar( TRUE ); - } - sendAgentSetAppearance(); -} - -void LLAgent::revertAllWearables() -{ - for( S32 i=0; i < WT_COUNT; i++ ) - { - revertWearable( (EWearableType)i ); - } -} - -void LLAgent::saveAllWearables() -{ - //if(!gInventory.isLoaded()) - //{ - // return; - //} - - for( S32 i=0; i < WT_COUNT; i++ ) - { - saveWearable( (EWearableType)i, FALSE ); - } - sendAgentWearablesUpdate(); -} - -// Called when the user changes the name of a wearable inventory item that is currenlty being worn. -void LLAgent::setWearableName( const LLUUID& item_id, const std::string& new_name ) -{ - for( S32 i=0; i < WT_COUNT; i++ ) - { - if( mWearableEntry[i].mItemID == item_id ) - { - LLWearable* old_wearable = mWearableEntry[i].mWearable; - llassert( old_wearable ); - - std::string old_name = old_wearable->getName(); - old_wearable->setName( new_name ); - LLWearable* new_wearable = gWearableList.createCopy( old_wearable ); - LLInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - new_wearable->setPermissions(item->getPermissions()); - } - old_wearable->setName( old_name ); - - mWearableEntry[i].mWearable = new_wearable; - sendAgentWearablesUpdate(); - break; - } - } -} - - -BOOL LLAgent::isWearableModifiable(EWearableType type) -{ - LLUUID item_id = getWearableItem(type); - if(!item_id.isNull()) - { - LLInventoryItem* item = gInventory.getItem(item_id); - if(item && item->getPermissions().allowModifyBy(gAgent.getID(), - gAgent.getGroupID())) - { - return TRUE; - } - } - return FALSE; -} - -BOOL LLAgent::isWearableCopyable(EWearableType type) -{ - LLUUID item_id = getWearableItem(type); - if(!item_id.isNull()) - { - LLInventoryItem* item = gInventory.getItem(item_id); - if(item && item->getPermissions().allowCopyBy(gAgent.getID(), - gAgent.getGroupID())) - { - return TRUE; - } - } - return FALSE; -} - -U32 LLAgent::getWearablePermMask(EWearableType type) -{ - LLUUID item_id = getWearableItem(type); - if(!item_id.isNull()) - { - LLInventoryItem* item = gInventory.getItem(item_id); - if(item) - { - return item->getPermissions().getMaskOwner(); - } - } - return PERM_NONE; -} - -LLInventoryItem* LLAgent::getWearableInventoryItem(EWearableType type) -{ - LLUUID item_id = getWearableItem(type); - LLInventoryItem* item = NULL; - if(item_id.notNull()) - { - item = gInventory.getItem(item_id); - } - return item; -} - -LLWearable* LLAgent::getWearableFromWearableItem( const LLUUID& item_id ) -{ - for( S32 i=0; i < WT_COUNT; i++ ) - { - if( mWearableEntry[i].mItemID == item_id ) - { - return mWearableEntry[i].mWearable; - } - } - return NULL; -} - - -void LLAgent::sendAgentWearablesRequest() -{ - gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - sendReliableMessage(); -} - -// Used to enable/disable menu items. -// static -BOOL LLAgent::selfHasWearable( void* userdata ) -{ - EWearableType type = (EWearableType)(intptr_t)userdata; - return gAgent.getWearable( type ) != NULL; -} - -BOOL LLAgent::isWearingItem( const LLUUID& item_id ) -{ - return (getWearableFromWearableItem( item_id ) != NULL); -} - -// static -void LLAgent::processAgentInitialWearablesUpdate( LLMessageSystem* mesgsys, void** user_data ) -{ - // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates - // that may result from AgentWearablesRequest having been sent more than once. - static bool first = true; - if (!first) return; - first = false; - - LLUUID agent_id; - gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id ); - - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( avatar && (agent_id == avatar->getID()) ) - { - gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgent.mAgentWearablesUpdateSerialNum ); - - S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); - if( num_wearables < 4 ) - { - // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). - // The fact that they don't have any here (only a dummy is sent) implies that this account existed - // before we had wearables, or that the database has gotten messed up. - return; - } - - //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; - // Add wearables - LLUUID asset_id_array[ WT_COUNT ]; - S32 i; - for( i=0; i < num_wearables; i++ ) - { - U8 type_u8 = 0; - gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i ); - if( type_u8 >= WT_COUNT ) - { - continue; - } - EWearableType type = (EWearableType) type_u8; - - LLUUID item_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i ); - - LLUUID asset_id; - gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i ); - if( asset_id.isNull() ) - { - LLWearable::removeFromAvatar( type, FALSE ); - } - else - { - LLAssetType::EType asset_type = LLWearable::typeToAssetType( type ); - if( asset_type == LLAssetType::AT_NONE ) - { - continue; - } - - gAgent.mWearableEntry[type].mItemID = item_id; - asset_id_array[type] = asset_id; - } - - lldebugs << " " << LLWearable::typeToTypeLabel(type) << llendl; - } - - // now that we have the asset ids...request the wearable assets - for( i = 0; i < WT_COUNT; i++ ) - { - if( !gAgent.mWearableEntry[i].mItemID.isNull() ) - { - gWearableList.getAsset( - asset_id_array[i], - LLStringUtil::null, - LLWearable::typeToAssetType( (EWearableType) i ), - LLAgent::onInitialWearableAssetArrived, (void*)(intptr_t)i ); - } - } - } -} - -// A single wearable that the avatar was wearing on start-up has arrived from the database. -// static -void LLAgent::onInitialWearableAssetArrived( LLWearable* wearable, void* userdata ) -{ - EWearableType type = (EWearableType)(intptr_t)userdata; - - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( !avatar ) - { - return; - } - - if( wearable ) - { - llassert( type == wearable->getType() ); - gAgent.mWearableEntry[ type ].mWearable = wearable; - - // disable composites if initial textures are baked - avatar->setupComposites(); - gAgent.queryWearableCache(); - - wearable->writeToAvatar( FALSE ); - avatar->setCompositeUpdatesEnabled(TRUE); - gInventory.addChangedMask( LLInventoryObserver::LABEL, gAgent.mWearableEntry[type].mItemID ); - } - else - { - // Somehow the asset doesn't exist in the database. - gAgent.recoverMissingWearable( type ); - } - - gInventory.notifyObservers(); - - // Have all the wearables that the avatar was wearing at log-in arrived? - if( !gAgent.mWearablesLoaded ) - { - gAgent.mWearablesLoaded = TRUE; - for( S32 i = 0; i < WT_COUNT; i++ ) - { - if( !gAgent.mWearableEntry[i].mItemID.isNull() && !gAgent.mWearableEntry[i].mWearable ) - { - gAgent.mWearablesLoaded = FALSE; - break; - } - } - } - - if( gAgent.mWearablesLoaded ) - { - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - gAgent.sendAgentSetAppearance(); - - // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time. - // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive. - if( !gAgent.cameraCustomizeAvatar() ) - { - avatar->requestLayerSetUploads(); - } - } -} - -// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the -// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that -// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) -void LLAgent::recoverMissingWearable( EWearableType type ) -{ - // Try to recover by replacing missing wearable with a new one. - LLNotifications::instance().add("ReplacedMissingWearable"); - lldebugs << "Wearable " << LLWearable::typeToTypeLabel( type ) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; - LLWearable* new_wearable = gWearableList.createNewWearable(type); - - S32 type_s32 = (S32) type; - mWearableEntry[type_s32].mWearable = new_wearable; - new_wearable->writeToAvatar( TRUE ); - - // Add a new one in the lost and found folder. - // (We used to overwrite the "not found" one, but that could potentially - // destory content.) JC - LLUUID lost_and_found_id = - gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type_s32, - new_wearable, - addWearableToAgentInventoryCallback::CALL_RECOVERDONE); - addWearableToAgentInventory( cb, new_wearable, lost_and_found_id, TRUE); -} - -void LLAgent::recoverMissingWearableDone() -{ - // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? - mWearablesLoaded = TRUE; - for( S32 i = 0; i < WT_COUNT; i++ ) - { - if( !mWearableEntry[i].mItemID.isNull() && !mWearableEntry[i].mWearable ) - { - mWearablesLoaded = FALSE; - break; - } - } - - if( mWearablesLoaded ) - { - // Make sure that the server's idea of the avatar's wearables actually match the wearables. - sendAgentSetAppearance(); - } - else - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, LLUUID::null ); - gInventory.notifyObservers(); - } -} - -void LLAgent::createStandardWearables(BOOL female) -{ - llwarns << "Creating Standard " << (female ? "female" : "male" ) - << " Wearables" << llendl; - - if (mAvatarObject.isNull()) - { - return; - } - - if(female) mAvatarObject->setSex(SEX_FEMALE); - else mAvatarObject->setSex(SEX_MALE); - - BOOL create[WT_COUNT] = - { - TRUE, //WT_SHAPE - TRUE, //WT_SKIN - TRUE, //WT_HAIR - TRUE, //WT_EYES - TRUE, //WT_SHIRT - TRUE, //WT_PANTS - TRUE, //WT_SHOES - TRUE, //WT_SOCKS - FALSE, //WT_JACKET - FALSE, //WT_GLOVES - TRUE, //WT_UNDERSHIRT - TRUE, //WT_UNDERPANTS - FALSE //WT_SKIRT - }; - - for( S32 i=0; i < WT_COUNT; i++ ) - { - bool once = false; - LLPointer donecb = NULL; - if( create[i] ) - { - if (!once) - { - once = true; - donecb = new createStandardWearablesAllDoneCallback; - } - llassert( mWearableEntry[i].mWearable == NULL ); - LLWearable* wearable = gWearableList.createNewWearable((EWearableType)i); - mWearableEntry[i].mWearable = wearable; - // no need to update here... - LLPointer cb = - new addWearableToAgentInventoryCallback( - donecb, - i, - wearable, - addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); - addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); - } - } -} -void LLAgent::createStandardWearablesDone(S32 index) -{ - LLWearable* wearable = mWearableEntry[index].mWearable; - - if (wearable) - { - wearable->writeToAvatar(TRUE); - } -} - -void LLAgent::createStandardWearablesAllDone() -{ - // ... because sendAgentWearablesUpdate will notify inventory - // observers. - mWearablesLoaded = TRUE; - sendAgentWearablesUpdate(); - sendAgentSetAppearance(); - - // Treat this as the first texture entry message, if none received yet - mAvatarObject->onFirstTEMessageReceived(); -} - -void LLAgent::makeNewOutfit( - const std::string& new_folder_name, - const LLDynamicArray& wearables_to_include, - const LLDynamicArray& attachments_to_include, - BOOL rename_clothing) -{ - if (mAvatarObject.isNull()) - { - return; - } - - // First, make a folder in the Clothes directory. - LLUUID folder_id = gInventory.createNewCategory( - gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING), - LLAssetType::AT_NONE, - new_folder_name); - - bool found_first_item = false; - - /////////////////// - // Wearables - - if( wearables_to_include.count() ) - { - // Then, iterate though each of the wearables and save copies of them in the folder. - S32 i; - S32 count = wearables_to_include.count(); - LLDynamicArray delete_items; - LLPointer cbdone = NULL; - for( i = 0; i < count; ++i ) - { - S32 index = wearables_to_include[i]; - LLWearable* old_wearable = mWearableEntry[ index ].mWearable; - if( old_wearable ) - { - std::string new_name; - LLWearable* new_wearable; - new_wearable = gWearableList.createCopy(old_wearable); - if (rename_clothing) - { - new_name = new_folder_name; - new_name.append(" "); - new_name.append(old_wearable->getTypeLabel()); - LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); - new_wearable->setName(new_name); - } - - LLViewerInventoryItem* item = gInventory.getItem(mWearableEntry[index].mItemID); - S32 todo = addWearableToAgentInventoryCallback::CALL_NONE; - if (!found_first_item) - { - found_first_item = true; - /* set the focus to the first item */ - todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE; - /* send the agent wearables update when done */ - cbdone = new sendAgentWearablesUpdateCallback; - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - cbdone, - index, - new_wearable, - todo); - if (isWearableCopyable((EWearableType)index)) - { - copy_inventory_item( - gAgent.getID(), - item->getPermissions().getOwner(), - item->getUUID(), - folder_id, - new_name, - cb); - } - else - { - move_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - item->getUUID(), - folder_id, - new_name, - cb); - } - } - } - gInventory.notifyObservers(); - } - - - /////////////////// - // Attachments - - if( attachments_to_include.count() ) - { - BOOL msg_started = FALSE; - LLMessageSystem* msg = gMessageSystem; - for( S32 i = 0; i < attachments_to_include.count(); i++ ) - { - S32 attachment_pt = attachments_to_include[i]; - LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL ); - if(!attachment) continue; - LLViewerObject* attached_object = attachment->getObject(); - if(!attached_object) continue; - const LLUUID& item_id = attachment->getItemID(); - if(item_id.isNull()) continue; - LLInventoryItem* item = gInventory.getItem(item_id); - if(!item) continue; - if(!msg_started) - { - msg_started = TRUE; - msg->newMessage("CreateNewOutfitAttachments"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", getID()); - msg->addUUID("SessionID", getSessionID()); - msg->nextBlock("HeaderData"); - msg->addUUID("NewFolderID", folder_id); - } - msg->nextBlock("ObjectData"); - msg->addUUID("OldItemID", item_id); - msg->addUUID("OldFolderID", item->getParentUUID()); - } - - if( msg_started ) - { - sendReliableMessage(); - } - - } -} - -void LLAgent::makeNewOutfitDone(S32 index) -{ - LLUUID first_item_id = mWearableEntry[index].mItemID; - // Open the inventory and select the first item we added. - if( first_item_id.notNull() ) - { - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(view) - { - view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO); - } - } -} - - -void LLAgent::addWearableToAgentInventory( - LLPointer cb, - LLWearable* wearable, - const LLUUID& category_id, - BOOL notify) -{ - create_inventory_item( - gAgent.getID(), - gAgent.getSessionID(), - category_id, - wearable->getTransactionID(), - wearable->getName(), - wearable->getDescription(), - wearable->getAssetType(), - LLInventoryType::IT_WEARABLE, - wearable->getType(), - wearable->getPermissions().getMaskNextOwner(), - cb); -} - //----------------------------------------------------------------------------- // sendAgentSetAppearance() //----------------------------------------------------------------------------- @@ -7182,7 +6300,7 @@ void LLAgent::sendAgentSetAppearance() { if (mAvatarObject.isNull()) return; - if (mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar()) + if (gAgentQueryManager.mNumPendingQueries > 0 && !gAgent.cameraCustomizeAvatar()) { return; } @@ -7212,11 +6330,11 @@ void LLAgent::sendAgentSetAppearance() // is texture data current relative to wearables? // KLW - TAT this will probably need to check the local queue. - BOOL textures_current = !mAvatarObject->hasPendingBakedUploads() && mWearablesLoaded; + BOOL textures_current = mAvatarObject->areTexturesCurrent(); for(U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) { - const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index); + const ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); // if we're not wearing a skirt, we don't need the texture to be baked if (texture_index == TEX_SKIRT_BAKED && !mAvatarObject->isWearingWearableType(WT_SKIRT)) @@ -7238,24 +6356,25 @@ void LLAgent::sendAgentSetAppearance() llinfos << "TAT: Sending cached texture data" << llendl; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index); + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); LLUUID hash; - for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++) + for (U8 i=0; i < baked_dict->mWearables.size(); i++) { // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num]; - const EWearableType wearable_type = wearable_dict->mWearablesVec[i]; - const LLWearable* wearable = getWearable(wearable_type); + const EWearableType wearable_type = baked_dict->mWearables[i]; + // MULTI-WEARABLE: fixed to 0th - extend to everything once messaging works. + const LLWearable* wearable = gAgentWearables.getWearable(wearable_type,0); if (wearable) { - hash ^= wearable->getID(); + hash ^= wearable->getAssetID(); } } if (hash.notNull()) { - hash ^= wearable_dict->mHashID; + hash ^= baked_dict->mWearablesHashID; } - const ETextureIndex texture_index = getTextureIndex((EBakedTextureIndex)baked_index); + const ETextureIndex texture_index = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)baked_index); msg->nextBlockFast(_PREHASH_WearableData); msg->addUUIDFast(_PREHASH_CacheID, hash); @@ -7299,456 +6418,20 @@ void LLAgent::sendAgentDataUpdateRequest() { gMessageSystem->newMessageFast(_PREHASH_AgentDataUpdateRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); sendReliableMessage(); } -void LLAgent::removeWearable( EWearableType type ) +void LLAgent::sendAgentUserInfoRequest() { - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; - - if ( (gAgent.isTeen()) - && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS)) - { - // Can't take off underclothing in simple UI mode or on PG accounts - return; - } - - if( old_wearable ) - { - if( old_wearable->isDirty() ) - { - LLSD payload; - payload["wearable_type"] = (S32)type; - // Bring up view-modal dialog: Save changes? Yes, No, Cancel - LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgent::onRemoveWearableDialog); - return; - } - else - { - removeWearableFinal( type ); - } - } -} - -// static -bool LLAgent::onRemoveWearableDialog(const LLSD& notification, const LLSD& response ) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger(); - switch( option ) - { - case 0: // "Save" - gAgent.saveWearable( type ); - gAgent.removeWearableFinal( type ); - break; - - case 1: // "Don't Save" - gAgent.removeWearableFinal( type ); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - return false; -} - -// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. -void LLAgent::removeWearableFinal( EWearableType type ) -{ - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; - - gInventory.addChangedMask( LLInventoryObserver::LABEL, mWearableEntry[type].mItemID ); - - mWearableEntry[ type ].mWearable = NULL; - mWearableEntry[ type ].mItemID.setNull(); - - queryWearableCache(); - - if( old_wearable ) - { - old_wearable->removeFromAvatar( TRUE ); - } - - // Update the server - sendAgentWearablesUpdate(); - sendAgentSetAppearance(); - gInventory.notifyObservers(); -} - -void LLAgent::copyWearableToInventory( EWearableType type ) -{ - LLWearable* wearable = mWearableEntry[ type ].mWearable; - if( wearable ) - { - // Save the old wearable if it has changed. - if( wearable->isDirty() ) - { - wearable = gWearableList.createCopyFromAvatar( wearable ); - mWearableEntry[ type ].mWearable = wearable; - } - - // Make a new entry in the inventory. (Put it in the same folder as the original item if possible.) - LLUUID category_id; - LLInventoryItem* item = gInventory.getItem( mWearableEntry[ type ].mItemID ); - if( item ) - { - category_id = item->getParentUUID(); - wearable->setPermissions(item->getPermissions()); - } - LLPointer cb = - new addWearableToAgentInventoryCallback( - LLPointer(NULL), - type, - wearable); - addWearableToAgentInventory(cb, wearable, category_id); - } -} - - -// A little struct to let setWearable() communicate more than one value with onSetWearableDialog(). -struct LLSetWearableData -{ - LLSetWearableData( const LLUUID& new_item_id, LLWearable* new_wearable ) : - mNewItemID( new_item_id ), mNewWearable( new_wearable ) {} - LLUUID mNewItemID; - LLWearable* mNewWearable; -}; - -BOOL LLAgent::needsReplacement(EWearableType wearableType, S32 remove) -{ - return TRUE; - /*if (remove) return TRUE; - - return getWearable(wearableType) ? TRUE : FALSE;*/ -} - -// Assumes existing wearables are not dirty. -void LLAgent::setWearableOutfit( - const LLInventoryItem::item_array_t& items, - const LLDynamicArray< LLWearable* >& wearables, - BOOL remove ) -{ - lldebugs << "setWearableOutfit() start" << llendl; - - BOOL wearables_to_remove[WT_COUNT]; - wearables_to_remove[WT_SHAPE] = FALSE; - wearables_to_remove[WT_SKIN] = FALSE; - wearables_to_remove[WT_HAIR] = FALSE; - wearables_to_remove[WT_EYES] = FALSE; - wearables_to_remove[WT_SHIRT] = remove; - wearables_to_remove[WT_PANTS] = remove; - wearables_to_remove[WT_SHOES] = remove; - wearables_to_remove[WT_SOCKS] = remove; - wearables_to_remove[WT_JACKET] = remove; - wearables_to_remove[WT_GLOVES] = remove; - wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove; - wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove; - wearables_to_remove[WT_SKIRT] = remove; - - S32 count = wearables.count(); - llassert( items.count() == count ); - - S32 i; - for( i = 0; i < count; i++ ) - { - LLWearable* new_wearable = wearables[i]; - LLPointer new_item = items[i]; - - EWearableType type = new_wearable->getType(); - wearables_to_remove[type] = FALSE; - - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; - if( old_wearable ) - { - const LLUUID& old_item_id = mWearableEntry[ type ].mItemID; - if( (old_wearable->getID() == new_wearable->getID()) && - (old_item_id == new_item->getUUID()) ) - { - lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl; - continue; - } - - gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); - - // Assumes existing wearables are not dirty. - if( old_wearable->isDirty() ) - { - llassert(0); - continue; - } - } - - mWearableEntry[ type ].mItemID = new_item->getUUID(); - mWearableEntry[ type ].mWearable = new_wearable; - } - - std::vector wearables_being_removed; - - for( i = 0; i < WT_COUNT; i++ ) - { - if( wearables_to_remove[i] ) - { - wearables_being_removed.push_back(mWearableEntry[ i ].mWearable); - mWearableEntry[ i ].mWearable = NULL; - - gInventory.addChangedMask(LLInventoryObserver::LABEL, mWearableEntry[ i ].mItemID); - mWearableEntry[ i ].mItemID.setNull(); - } - } - - gInventory.notifyObservers(); - - queryWearableCache(); - - std::vector::iterator wearable_iter; - - for( wearable_iter = wearables_being_removed.begin(); - wearable_iter != wearables_being_removed.end(); - ++wearable_iter) - { - LLWearable* wearablep = *wearable_iter; - if (wearablep) - { - wearablep->removeFromAvatar( TRUE ); - } - } - - for( i = 0; i < count; i++ ) - { - wearables[i]->writeToAvatar( TRUE ); - } - - // Start rendering & update the server - mWearablesLoaded = TRUE; - sendAgentWearablesUpdate(); - sendAgentSetAppearance(); - - lldebugs << "setWearableOutfit() end" << llendl; -} - - -// User has picked "wear on avatar" from a menu. -void LLAgent::setWearable( LLInventoryItem* new_item, LLWearable* new_wearable ) -{ - EWearableType type = new_wearable->getType(); - - LLWearable* old_wearable = mWearableEntry[ type ].mWearable; - if( old_wearable ) - { - const LLUUID& old_item_id = mWearableEntry[ type ].mItemID; - if( (old_wearable->getID() == new_wearable->getID()) && - (old_item_id == new_item->getUUID()) ) - { - lldebugs << "No change to wearable asset and item: " << LLWearable::typeToTypeName( type ) << llendl; - return; - } - - if( old_wearable->isDirty() ) - { - // Bring up modal dialog: Save changes? Yes, No, Cancel - LLSD payload; - payload["item_id"] = new_item->getUUID(); - LLNotifications::instance().add( "WearableSave", LLSD(), payload, boost::bind(LLAgent::onSetWearableDialog, _1, _2, new_wearable)); - return; - } - } - - setWearableFinal( new_item, new_wearable ); -} - -// static -bool LLAgent::onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable ) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLInventoryItem* new_item = gInventory.getItem( notification["payload"]["item_id"].asUUID()); - if( !new_item ) - { - delete wearable; - return false; - } - - switch( option ) - { - case 0: // "Save" - gAgent.saveWearable( wearable->getType() ); - gAgent.setWearableFinal( new_item, wearable ); - break; - - case 1: // "Don't Save" - gAgent.setWearableFinal( new_item, wearable ); - break; - - case 2: // "Cancel" - break; - - default: - llassert(0); - break; - } - - delete wearable; - return false; -} - -// Called from setWearable() and onSetWearableDialog() to actually set the wearable. -void LLAgent::setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ) -{ - EWearableType type = new_wearable->getType(); - - // Replace the old wearable with a new one. - llassert( new_item->getAssetUUID() == new_wearable->getID() ); - LLUUID old_item_id = mWearableEntry[ type ].mItemID; - mWearableEntry[ type ].mItemID = new_item->getUUID(); - mWearableEntry[ type ].mWearable = new_wearable; - - if (old_item_id.notNull()) - { - gInventory.addChangedMask( LLInventoryObserver::LABEL, old_item_id ); - gInventory.notifyObservers(); - } - - //llinfos << "LLVOAvatar::setWearable()" << llendl; - queryWearableCache(); - new_wearable->writeToAvatar( TRUE ); - - // Update the server - sendAgentWearablesUpdate(); - sendAgentSetAppearance(); -} - -void LLAgent::queryWearableCache() -{ - if (!mWearablesLoaded) - { - return; - } - - // Look up affected baked textures. - // If they exist: - // disallow updates for affected layersets (until dataserver responds with cache request.) - // If cache miss, turn updates back on and invalidate composite. - // If cache hit, modify baked texture entries. - // - // Cache requests contain list of hashes for each baked texture entry. - // Response is list of valid baked texture assets. (same message) - - gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); + if(getID().isNull()) + return; // not logged in + gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); - gMessageSystem->addS32Fast(_PREHASH_SerialNum, mTextureCacheQueryID); - - S32 num_queries = 0; - for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++ ) - { - const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = LLVOAvatarDictionary::getInstance()->getWearable((EBakedTextureIndex)baked_index); - LLUUID hash; - for (U8 i=0; i < wearable_dict->mWearablesVec.size(); i++) - { - // EWearableType wearable_type = gBakedWearableMap[baked_index][wearable_num]; - const EWearableType wearable_type = wearable_dict->mWearablesVec[i]; - const LLWearable* wearable = getWearable(wearable_type); - if (wearable) - { - hash ^= wearable->getID(); - } - } - if (hash.notNull()) - { - hash ^= wearable_dict->mHashID; - num_queries++; - // *NOTE: make sure at least one request gets packed - - //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl; - gMessageSystem->nextBlockFast(_PREHASH_WearableData); - gMessageSystem->addUUIDFast(_PREHASH_ID, hash); - gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index); - } - - mActiveCacheQueries[ baked_index ] = mTextureCacheQueryID; - } - - llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl; - gMessageSystem->sendReliable(getRegion()->getHost()); - mNumPendingQueries++; - mTextureCacheQueryID++; -} - -// User has picked "remove from avatar" from a menu. -// static -void LLAgent::userRemoveWearable( void* userdata ) -{ - EWearableType type = (EWearableType)(intptr_t)userdata; - - if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR ) ) //&& - //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) - { - gAgent.removeWearable( type ); - } -} - -void LLAgent::userRemoveAllClothes( void* userdata ) -{ - // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty. - if( gFloaterCustomize ) - { - gFloaterCustomize->askToSaveIfDirty( LLAgent::userRemoveAllClothesStep2, NULL ); - } - else - { - LLAgent::userRemoveAllClothesStep2( TRUE, NULL ); - } -} - -void LLAgent::userRemoveAllClothesStep2( BOOL proceed, void* userdata ) -{ - if( proceed ) - { - gAgent.removeWearable( WT_SHIRT ); - gAgent.removeWearable( WT_PANTS ); - gAgent.removeWearable( WT_SHOES ); - gAgent.removeWearable( WT_SOCKS ); - gAgent.removeWearable( WT_JACKET ); - gAgent.removeWearable( WT_GLOVES ); - gAgent.removeWearable( WT_UNDERSHIRT ); - gAgent.removeWearable( WT_UNDERPANTS ); - gAgent.removeWearable( WT_SKIRT ); - } -} - -void LLAgent::userRemoveAllAttachments( void* userdata ) -{ - LLVOAvatar* avatarp = gAgent.getAvatarObject(); - if(!avatarp) - { - llwarns << "No avatar found." << llendl; - return; - } - - gMessageSystem->newMessage("ObjectDetach"); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); - iter != avatarp->mAttachmentPoints.end(); ) - { - LLVOAvatar::attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - LLViewerObject* objectp = attachment->getObject(); - if (objectp) - { - gMessageSystem->nextBlockFast(_PREHASH_ObjectData); - gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID()); - } - } - gMessageSystem->sendReliable( gAgent.getRegionHost() ); + sendReliableMessage(); } void LLAgent::observeFriends() @@ -7813,4 +6496,44 @@ void LLAgent::parseTeleportMessages(const std::string& xml_filename) }//end for (all message sets in xml file) } +void LLAgent::sendAgentUpdateUserInfo(bool im_via_email, const std::string& directory_visibility ) +{ + gMessageSystem->newMessageFast(_PREHASH_UpdateUserInfo); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, getSessionID()); + gMessageSystem->nextBlockFast(_PREHASH_UserData); + gMessageSystem->addBOOLFast(_PREHASH_IMViaEMail, im_via_email); + gMessageSystem->addString("DirectoryVisibility", directory_visibility); + gAgent.sendReliableMessage(); +} + +// static +void LLAgent::dumpGroupInfo() +{ + llinfos << "group " << gAgent.mGroupName << llendl; + llinfos << "ID " << gAgent.mGroupID << llendl; + llinfos << "powers " << gAgent.mGroupPowers << llendl; + llinfos << "title " << gAgent.mGroupTitle << llendl; + //llinfos << "insig " << gAgent.mGroupInsigniaID << llendl; +} + +/********************************************************************************/ +LLAgentQueryManager gAgentQueryManager; + +LLAgentQueryManager::LLAgentQueryManager() : + mWearablesCacheQueryID(0), + mNumPendingQueries(0), + mUpdateSerialNum(0) +{ + for (U32 i = 0; i < BAKED_NUM_INDICES; i++) + { + mActiveCacheQueries[i] = 0; + } +} + +LLAgentQueryManager::~LLAgentQueryManager() +{ +} + // EOF diff --git a/indra/newview/llagent.h b/indra/newview/llagent.h index 27fcb07fd5..5ca630f8d1 100644 --- a/indra/newview/llagent.h +++ b/indra/newview/llagent.h @@ -33,63 +33,26 @@ #ifndef LL_LLAGENT_H #define LL_LLAGENT_H -#include - #include "indra_constants.h" -#include "llmath.h" -#include "llcontrol.h" -#include "llcoordframe.h" -#include "llevent.h" +#include "llevent.h" // LLObservable base class +#include "llagentaccess.h" #include "llagentaccess.h" #include "llagentconstants.h" -#include "llanimationstates.h" -#include "lldbstrings.h" -#include "llhudeffectlookat.h" -#include "llhudeffectpointat.h" -#include "llmemory.h" -#include "llstring.h" -#include "lluuid.h" -#include "m3math.h" -#include "m4math.h" -#include "llquaternion.h" -#include "lltimer.h" -#include "v3dmath.h" -#include "v3math.h" -#include "v4color.h" -#include "v4math.h" -//#include "vmath.h" -#include "stdenums.h" -#include "llwearable.h" -#include "llcharacter.h" -#include "llinventory.h" -#include "llviewerinventory.h" -#include "llagentdata.h" +#include "llhudeffectpointat.h" // ELookAtType +#include "llhudeffectlookat.h" // EPointAtType +#include "llpointer.h" +#include "llcharacter.h" // LLAnimPauseRequest +#include "llfollowcam.h" // Ventrella +#include "llagentdata.h" // gAgentID, gAgentSessionID +#include "lluicolor.h" +#include "llvoavatardefines.h" -// Ventrella -#include "llfollowcam.h" -// end Ventrella - -const U8 AGENT_STATE_TYPING = 0x04; // Typing indication -const U8 AGENT_STATE_EDITING = 0x10; // Set when agent has objects selected - -const BOOL ANIMATE = TRUE; - -typedef enum e_camera_modes -{ - CAMERA_MODE_THIRD_PERSON, - CAMERA_MODE_MOUSELOOK, - CAMERA_MODE_CUSTOMIZE_AVATAR, - CAMERA_MODE_FOLLOW -} ECameraMode; - -typedef enum e_anim_request -{ - ANIM_REQUEST_START, - ANIM_REQUEST_STOP -} EAnimRequest; +extern const BOOL ANIMATE; +extern const U8 AGENT_STATE_TYPING; // Typing indication +extern const U8 AGENT_STATE_EDITING; // Set when agent has objects selected class LLChat; -class LLVOAvatar; +class LLVOAvatarSelf; class LLViewerRegion; class LLMotion; class LLToolset; @@ -98,6 +61,38 @@ class LLPermissions; class LLHost; class LLFriendObserver; class LLPickInfo; +class LLViewerObject; +class LLAgentDropGroupViewerNode; + +//-------------------------------------------------------------------- +// Types +//-------------------------------------------------------------------- +enum ECameraMode +{ + CAMERA_MODE_THIRD_PERSON, + CAMERA_MODE_MOUSELOOK, + CAMERA_MODE_CUSTOMIZE_AVATAR, + CAMERA_MODE_FOLLOW +}; + +/** Camera Presets for CAMERA_MODE_THIRD_PERSON */ +enum ECameraPreset +{ + /** Default preset, what the Third Person Mode actually was */ + CAMERA_PRESET_REAR_VIEW, + + /** "Looking at the Avatar from the front" */ + CAMERA_PRESET_FRONT_VIEW, + + /** "Above and to the left, over the shoulder, pulled back a little on the zoom" */ + CAMERA_PRESET_GROUP_VIEW +}; + +enum EAnimRequest +{ + ANIM_REQUEST_START, + ANIM_REQUEST_STOP +}; struct LLGroupData { @@ -110,273 +105,429 @@ struct LLGroupData std::string mName; }; -inline bool operator==(const LLGroupData &a, const LLGroupData &b) -{ - return (a.mID == b.mID); -} - -// forward declarations - -// - +//------------------------------------------------------------------------ +// LLAgent +//------------------------------------------------------------------------ class LLAgent : public LLOldEvents::LLObservable { LOG_CLASS(LLAgent); + +public: + friend class LLAgentDropGroupViewerNode; + +/******************************************************************************** + ** ** + ** INITIALIZATION + **/ + + //-------------------------------------------------------------------- + // Constructors / Destructors + //-------------------------------------------------------------------- +public: + LLAgent(); + virtual ~LLAgent(); + void init(); + void cleanup(); + void setAvatarObject(LLVOAvatarSelf *avatar); + + //-------------------------------------------------------------------- + // Login + //-------------------------------------------------------------------- +public: + void onAppFocusGained(); + void setFirstLogin(BOOL b) { mFirstLogin = b; } + // Return TRUE if the database reported this login as the first for this particular user. + BOOL isFirstLogin() const { return mFirstLogin; } +public: + BOOL mInitialized; + BOOL mFirstLogin; + std::string mMOTD; // Message of the day + + //-------------------------------------------------------------------- + // Session + //-------------------------------------------------------------------- +public: + const LLUUID& getID() const { return gAgentID; } + const LLUUID& getSessionID() const { return gAgentSessionID; } + // Note: NEVER send this value in the clear or over any weakly + // encrypted channel (such as simple XOR masking). If you are unsure + // ask Aaron or MarkL. + const LLUUID& getSecureSessionID() const { return mSecureSessionID; } +public: + LLUUID mSecureSessionID; // Secure token for this login session +/** Initialization + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** IDENTITY + **/ + + //-------------------------------------------------------------------- + // Name + //-------------------------------------------------------------------- +public: + //*TODO remove, is not used as of August 20, 2009 + void buildFullnameAndTitle(std::string &name) const; + + //-------------------------------------------------------------------- + // Gender + //-------------------------------------------------------------------- +public: + // On the very first login, gender isn't chosen until the user clicks + // in a dialog. We don't render the avatar until they choose. + BOOL isGenderChosen() const { return mGenderChosen; } + void setGenderChosen(BOOL b) { mGenderChosen = b; } +private: + BOOL mGenderChosen; + +/** Identity + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** GENERAL ACCESSORS + **/ + +public: + LLVOAvatarSelf* getAvatarObject() const { return mAvatarObject; } +private: + LLPointer mAvatarObject; // NULL until avatar object sent down from simulator + +/** General Accessors + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** POSITION + **/ + + //-------------------------------------------------------------------- + // Position + //-------------------------------------------------------------------- +public: + LLVector3 getPosAgentFromGlobal(const LLVector3d &pos_global) const; + LLVector3d getPosGlobalFromAgent(const LLVector3 &pos_agent) const; + const LLVector3d &getPositionGlobal() const; + const LLVector3 &getPositionAgent(); + // Call once per frame to update position, angles (radians). + void updateAgentPosition(const F32 dt, const F32 yaw, const S32 mouse_x, const S32 mouse_y); + void setPositionAgent(const LLVector3 ¢er); +protected: + void propagate(const F32 dt); // ! BUG ! Should roll into updateAgentPosition +private: + mutable LLVector3d mPositionGlobal; + + //-------------------------------------------------------------------- + // Velocity + //-------------------------------------------------------------------- +public: + LLVector3 getVelocity() const; + F32 getVelocityZ() const { return getVelocity().mV[VZ]; } // ! HACK ! + + //-------------------------------------------------------------------- + // Coordinate System + //-------------------------------------------------------------------- +public: + LLCoordFrame getFrameAgent() const { return mFrameAgent; } + void initOriginGlobal(const LLVector3d &origin_global); // Only to be used in ONE place + void resetAxes(); + void resetAxes(const LLVector3 &look_at); // Makes reasonable left and up + // The following three get*Axis functions return direction avatar is looking, not camera. + const LLVector3& getAtAxis() const { return mFrameAgent.getAtAxis(); } + const LLVector3& getUpAxis() const { return mFrameAgent.getUpAxis(); } + const LLVector3& getLeftAxis() const { return mFrameAgent.getLeftAxis(); } + LLQuaternion getQuat() const; // Returns the quat that represents the rotation of the agent in the absolute frame +private: + LLVector3d mAgentOriginGlobal; // Origin of agent coords from global coords + LLCoordFrame mFrameAgent; // Agent position and view, agent-region coordinates + + + //-------------------------------------------------------------------- + // Home + //-------------------------------------------------------------------- +public: + void setStartPosition(U32 location_id); // Marks current location as start, sends information to servers + void setHomePosRegion(const U64& region_handle, const LLVector3& pos_region); + BOOL getHomePosGlobal(LLVector3d* pos_global); +private: + BOOL mHaveHomePosition; + U64 mHomeRegionHandle; + LLVector3 mHomePosRegion; + + //-------------------------------------------------------------------- + // Region + //-------------------------------------------------------------------- +public: + void setRegion(LLViewerRegion *regionp); + LLViewerRegion *getRegion() const; + LLHost getRegionHost() const; + BOOL inPrelude(); +private: + LLViewerRegion *mRegionp; + + //-------------------------------------------------------------------- + // History + //-------------------------------------------------------------------- +public: + S32 getRegionsVisited() const; + F64 getDistanceTraveled() const; +private: + std::set mRegionsVisited; // Stat - what distinct regions has the avatar been to? + F64 mDistanceTraveled; // Stat - how far has the avatar moved? + LLVector3d mLastPositionGlobal; // Used to calculate travel distance + +/** Position + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** ACTIONS + **/ + + //-------------------------------------------------------------------- + // Fidget + //-------------------------------------------------------------------- + // Trigger random fidget animations +public: + void fidget(); + static void stopFidget(); +private: + LLFrameTimer mFidgetTimer; + LLFrameTimer mFocusObjectFadeTimer; + F32 mNextFidgetTime; + S32 mCurrentFidget; + + //-------------------------------------------------------------------- + // Fly + //-------------------------------------------------------------------- +public: + BOOL getFlying() const { return mControlFlags & AGENT_CONTROL_FLY; } + void setFlying(BOOL fly); + static void toggleFlying(); + static bool enableFlying(); + BOOL canFly(); // Does this parcel allow you to fly? + + //-------------------------------------------------------------------- + // Chat + //-------------------------------------------------------------------- +public: + void heardChat(const LLUUID& id); + void lookAtLastChat(); + F32 getTypingTime() { return mTypingTimer.getElapsedTimeF32(); } + LLUUID getLastChatter() const { return mLastChatterID; } + F32 getNearChatRadius() { return mNearChatRadius; } +protected: + void ageChat(); // Helper function to prematurely age chat when agent is moving +private: + LLFrameTimer mChatTimer; + LLUUID mLastChatterID; + F32 mNearChatRadius; + + //-------------------------------------------------------------------- + // Typing + //-------------------------------------------------------------------- +public: + void startTyping(); + void stopTyping(); public: // When the agent hasn't typed anything for this duration, it leaves the // typing state (for both chat and IM). static const F32 TYPING_TIMEOUT_SECS; +private: + LLFrameTimer mTypingTimer; - LLAgent(); - ~LLAgent(); - - void init(); - void cleanup(); - - // - // MANIPULATORS - // - // TODO: Put all non-const functions here. - - // Called whenever the agent moves. Puts camera back in default position, - // deselects items, etc. - void resetView(BOOL reset_camera = TRUE, BOOL change_camera = FALSE); - - // Called on camera movement, to allow the camera to be unlocked from the - // default position behind the avatar. - void unlockView(); - - void onAppFocusGained(); - - void sendMessage(); // Send message to this agent's region. - void sendReliableMessage(); - - LLVector3d calcCameraPositionTargetGlobal(BOOL *hit_limit = NULL); // Calculate the camera position target - LLVector3d calcFocusPositionTargetGlobal(); - LLVector3d calcThirdPersonFocusOffset(); - // target for this mode - LLVector3d getCameraPositionGlobal() const; - const LLVector3 &getCameraPositionAgent() const; - F32 calcCameraFOVZoomFactor(); - F32 getCameraMinOffGround(); // minimum height off ground for this mode, meters - void endAnimationUpdateUI(); - void setKey(const S32 direction, S32 &key); // sets key to +1 for +direction, -1 for -direction - void handleScrollWheel(S32 clicks); // mousewheel driven zoom - - void setAvatarObject(LLVOAvatar *avatar); - - // rendering state bitmask helpers - void startTyping(); - void stopTyping(); - void setRenderState(U8 newstate); - void clearRenderState(U8 clearstate); - U8 getRenderState(); - - // Set the home data - void setRegion(LLViewerRegion *regionp); - LLViewerRegion *getRegion() const; - LLHost getRegionHost() const; - std::string getSLURL() const; - - void updateAgentPosition(const F32 dt, const F32 yaw, const S32 mouse_x, const S32 mouse_y); // call once per frame to update position, angles radians - void updateLookAt(const S32 mouse_x, const S32 mouse_y); - - - void updateCamera(); // call once per frame to update camera location/orientation - void resetCamera(); // slam camera into its default position - void setupSitCamera(); - void setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; } - - void changeCameraToDefault(); - void changeCameraToMouselook(BOOL animate = TRUE); - void changeCameraToThirdPerson(BOOL animate = TRUE); - void changeCameraToCustomizeAvatar(BOOL avatar_animate = TRUE, BOOL camera_animate = TRUE); // trigger transition animation - // Ventrella - void changeCameraToFollow(BOOL animate = TRUE); - //end Ventrella - - void setFocusGlobal(const LLPickInfo& pick); - void setFocusGlobal(const LLVector3d &focus, const LLUUID &object_id = LLUUID::null); - void setFocusOnAvatar(BOOL focus, BOOL animate); - void setCameraPosAndFocusGlobal(const LLVector3d& pos, const LLVector3d& focus, const LLUUID &object_id); - void setSitCamera(const LLUUID &object_id, const LLVector3 &camera_pos = LLVector3::zero, const LLVector3 &camera_focus = LLVector3::zero); - void clearFocusObject(); - void setFocusObject(LLViewerObject* object); - void setObjectTracking(BOOL track) { mTrackFocusObject = track; } -// void setLookingAtAvatar(BOOL looking); - - void heardChat(const LLUUID& id); - void lookAtLastChat(); - F32 getTypingTime() { return mTypingTimer.getElapsedTimeF32(); } - + //-------------------------------------------------------------------- + // AFK + //-------------------------------------------------------------------- +public: void setAFK(); void clearAFK(); BOOL getAFK() const; - void setAlwaysRun() { mbAlwaysRun = true; } - void clearAlwaysRun() { mbAlwaysRun = false; } + //-------------------------------------------------------------------- + // Run + //-------------------------------------------------------------------- +public: + enum EDoubleTapRunMode + { + DOUBLETAP_NONE, + DOUBLETAP_FORWARD, + DOUBLETAP_BACKWARD, + DOUBLETAP_SLIDELEFT, + DOUBLETAP_SLIDERIGHT + }; - void setRunning() { mbRunning = true; } - void clearRunning() { mbRunning = false; } + void setAlwaysRun() { mbAlwaysRun = true; } + void clearAlwaysRun() { mbAlwaysRun = false; } + void setRunning() { mbRunning = true; } + void clearRunning() { mbRunning = false; } + void sendWalkRun(bool running); + bool getAlwaysRun() const { return mbAlwaysRun; } + bool getRunning() const { return mbRunning; } +public: + LLFrameTimer mDoubleTapRunTimer; + EDoubleTapRunMode mDoubleTapRunMode; +private: + bool mbAlwaysRun; // Should the avatar run by default rather than walk? + bool mbRunning; // Is the avatar trying to run right now? + //-------------------------------------------------------------------- + // Sit and stand + //-------------------------------------------------------------------- +public: + void standUp(); + + //-------------------------------------------------------------------- + // Busy + //-------------------------------------------------------------------- +public: void setBusy(); void clearBusy(); BOOL getBusy() const; +private: + BOOL mIsBusy; - void setAdminOverride(BOOL b); - void setGodLevel(U8 god_level); - void setFirstLogin(BOOL b) { mFirstLogin = b; } - void setGenderChosen(BOOL b) { mGenderChosen = b; } + //-------------------------------------------------------------------- + // Jump + //-------------------------------------------------------------------- +public: + BOOL getJump() const { return mbJump; } +private: + BOOL mbJump; - // update internal datastructures and update the server with the - // new contribution level. Returns true if the group id was found - // and contribution could be set. - BOOL setGroupContribution(const LLUUID& group_id, S32 contribution); - BOOL setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile); - void setHideGroupTitle(BOOL hide) { mHideGroupTitle = hide; } + //-------------------------------------------------------------------- + // Grab + //-------------------------------------------------------------------- +public: + BOOL leftButtonGrabbed() const; + BOOL rotateGrabbed() const; + BOOL forwardGrabbed() const; + BOOL backwardGrabbed() const; + BOOL upGrabbed() const; + BOOL downGrabbed() const; - // - // ACCESSORS - // - // TODO: Put all read functions here, make them const - - const LLUUID& getID() const { return gAgentID; } - const LLUUID& getSessionID() const { return gAgentSessionID; } + //-------------------------------------------------------------------- + // Controls + //-------------------------------------------------------------------- +public: + U32 getControlFlags(); + void setControlFlags(U32 mask); // Performs bitwise mControlFlags |= mask + void clearControlFlags(U32 mask); // Performs bitwise mControlFlags &= ~mask + BOOL controlFlagsDirty() const; + void enableControlFlagReset(); + void resetControlFlags(); + BOOL anyControlGrabbed() const; // True iff a script has taken over a control + BOOL isControlGrabbed(S32 control_index) const; + // Send message to simulator to force grabbed controls to be + // released, in case of a poorly written script. + void forceReleaseControls(); +private: + S32 mControlsTakenCount[TOTAL_CONTROLS]; + S32 mControlsTakenPassedOnCount[TOTAL_CONTROLS]; + U32 mControlFlags; // Replacement for the mFooKey's + BOOL mbFlagsDirty; + BOOL mbFlagsNeedReset; // ! HACK ! For preventing incorrect flags sent when crossing region boundaries - const LLUUID& getSecureSessionID() const { return mSecureSessionID; } - // Note: NEVER send this value in the clear or over any weakly - // encrypted channel (such as simple XOR masking). If you are unsure - // ask Aaron or MarkL. - - BOOL isGodlike() const; - U8 getGodLevel() const; - // note: this is a prime candidate for pulling out into a Maturity class - // rather than just expose the preference setting, we're going to actually - // expose what the client code cares about -- what the user should see - // based on a combination of the is* and prefers* flags, combined with God bit. - bool wantsPGOnly() const; - bool canAccessMature() const; - bool canAccessAdult() const; - bool canAccessMaturityInRegion( U64 region_handle ) const; - bool canAccessMaturityAtGlobal( LLVector3d pos_global ) const; - bool prefersPG() const; - bool prefersMature() const; - bool prefersAdult() const; - bool isTeen() const; - bool isMature() const; - bool isAdult() const; - void setTeen(bool teen); - void setMaturity(char text); - static int convertTextToMaturity(char text); - bool sendMaturityPreferenceToServer(int preferredMaturity); + //-------------------------------------------------------------------- + // Animations + //-------------------------------------------------------------------- +public: + void stopCurrentAnimations(); + void requestStopMotion(LLMotion* motion); + void onAnimStop(const LLUUID& id); + void sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request); + void sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request); + void endAnimationUpdateUI(); +private: + LLFrameTimer mAnimationTimer; // Seconds that transition animation has been active + F32 mAnimationDuration; // In seconds + BOOL mCustomAnim; // Current animation is ANIM_AGENT_CUSTOMIZE ? + LLAnimPauseRequest mPauseRequest; + BOOL mViewsPushed; // Keep track of whether or not we have pushed views - const LLAgentAccess& getAgentAccess(); +/** Animation + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** MOVEMENT + **/ - // This function can go away after the AO transition (see llstartup.cpp) - void setAOTransition(); + //-------------------------------------------------------------------- + // Keys + //-------------------------------------------------------------------- +public: + void setKey(const S32 direction, S32 &key); // Sets key to +1 for +direction, -1 for -direction +private: + S32 mAtKey; // Either 1, 0, or -1. Indicates that movement key is pressed + S32 mWalkKey; // Like AtKey, but causes less forward thrust + S32 mLeftKey; + S32 mUpKey; + F32 mYawKey; + S32 mPitchKey; + + //-------------------------------------------------------------------- + // Movement from user input + //-------------------------------------------------------------------- + // All set the appropriate animation flags. + // All turn off autopilot and make sure the camera is behind the avatar. + // Direction is either positive, zero, or negative +public: + void moveAt(S32 direction, bool reset_view = true); + void moveAtNudge(S32 direction); + void moveLeft(S32 direction); + void moveLeftNudge(S32 direction); + void moveUp(S32 direction); + void moveYaw(F32 mag, bool reset_view = true); + void movePitch(S32 direction); + + //-------------------------------------------------------------------- + // Orbit + //-------------------------------------------------------------------- +public: + void setOrbitLeftKey(F32 mag) { mOrbitLeftKey = mag; } + void setOrbitRightKey(F32 mag) { mOrbitRightKey = mag; } + void setOrbitUpKey(F32 mag) { mOrbitUpKey = mag; } + void setOrbitDownKey(F32 mag) { mOrbitDownKey = mag; } + void setOrbitInKey(F32 mag) { mOrbitInKey = mag; } + void setOrbitOutKey(F32 mag) { mOrbitOutKey = mag; } +private: + F32 mOrbitLeftKey; + F32 mOrbitRightKey; + F32 mOrbitUpKey; + F32 mOrbitDownKey; + F32 mOrbitInKey; + F32 mOrbitOutKey; - BOOL isGroupTitleHidden() const { return mHideGroupTitle; } - BOOL isGroupMember() const { return !mGroupID.isNull(); } // This is only used for building titles! - const LLUUID &getGroupID() const { return mGroupID; } - ECameraMode getCameraMode() const { return mCameraMode; } - BOOL getFocusOnAvatar() const { return mFocusOnAvatar; } - LLPointer& getFocusObject() { return mFocusObject; } - F32 getFocusObjectDist() const { return mFocusObjectDist; } - BOOL inPrelude(); - BOOL canManageEstate() const; - BOOL getAdminOverride() const; + //-------------------------------------------------------------------- + // Pan + //-------------------------------------------------------------------- +public: + void setPanLeftKey(F32 mag) { mPanLeftKey = mag; } + void setPanRightKey(F32 mag) { mPanRightKey = mag; } + void setPanUpKey(F32 mag) { mPanUpKey = mag; } + void setPanDownKey(F32 mag) { mPanDownKey = mag; } + void setPanInKey(F32 mag) { mPanInKey = mag; } + void setPanOutKey(F32 mag) { mPanOutKey = mag; } +private: + F32 mPanUpKey; + F32 mPanDownKey; + F32 mPanLeftKey; + F32 mPanRightKey; + F32 mPanInKey; + F32 mPanOutKey; - LLUUID getLastChatter() const { return mLastChatterID; } - bool getAlwaysRun() const { return mbAlwaysRun; } - bool getRunning() const { return mbRunning; } - - const LLUUID& getInventoryRootID() const { return mInventoryRootID; } - - void buildFullname(std::string &name) const; - void buildFullnameAndTitle(std::string &name) const; - - // Check against all groups in the entire agent group list. - BOOL isInGroup(const LLUUID& group_id) const; - BOOL hasPowerInGroup(const LLUUID& group_id, U64 power) const; - // Check for power in just the active group. - BOOL hasPowerInActiveGroup(const U64 power) const; - U64 getPowerInGroup(const LLUUID& group_id) const; - - // Get group information by group_id. if not in group, data is - // left unchanged and method returns FALSE. otherwise, values are - // copied and returns TRUE. - BOOL getGroupData(const LLUUID& group_id, LLGroupData& data) const; - // Get just the agent's contribution to the given group. - S32 getGroupContribution(const LLUUID& group_id) const; - - // return TRUE if the database reported this login as the first - // for this particular user. - BOOL isFirstLogin() const { return mFirstLogin; } - - // On the very first login, gender isn't chosen until the user clicks - // in a dialog. We don't render the avatar until they choose. - BOOL isGenderChosen() const { return mGenderChosen; } - - // utility to build a location string - void buildLocationString(std::string& str); - - LLQuaternion getHeadRotation(); - LLVOAvatar *getAvatarObject() const { return mAvatarObject; } - - BOOL needsRenderAvatar(); // TRUE when camera mode is such that your own avatar should draw - // Not const because timers can't be accessed in const-fashion. - BOOL needsRenderHead(); - BOOL cameraThirdPerson() const { return (mCameraMode == CAMERA_MODE_THIRD_PERSON && mLastCameraMode == CAMERA_MODE_THIRD_PERSON); } - BOOL cameraMouselook() const { return (mCameraMode == CAMERA_MODE_MOUSELOOK && mLastCameraMode == CAMERA_MODE_MOUSELOOK); } - BOOL cameraCustomizeAvatar() const { return (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR /*&& !mCameraAnimating*/); } - BOOL cameraFollow() const { return (mCameraMode == CAMERA_MODE_FOLLOW && mLastCameraMode == CAMERA_MODE_FOLLOW); } - - LLVector3 getPosAgentFromGlobal(const LLVector3d &pos_global) const; - LLVector3d getPosGlobalFromAgent(const LLVector3 &pos_agent) const; - - // Get the data members - const LLVector3& getAtAxis() const { return mFrameAgent.getAtAxis(); } // direction avatar is looking, not camera - const LLVector3& getUpAxis() const { return mFrameAgent.getUpAxis(); } // direction avatar is looking, not camera - const LLVector3& getLeftAxis() const { return mFrameAgent.getLeftAxis(); } // direction avatar is looking, not camera - - LLCoordFrame getFrameAgent() const { return mFrameAgent; } - LLVector3 getVelocity() const; - F32 getVelocityZ() const { return getVelocity().mV[VZ]; } // a hack - - const LLVector3d &getPositionGlobal() const; - const LLVector3 &getPositionAgent(); - S32 getRegionsVisited() const; - F64 getDistanceTraveled() const; - - const LLVector3d &getFocusGlobal() const { return mFocusGlobal; } - const LLVector3d &getFocusTargetGlobal() const { return mFocusTargetGlobal; } - - BOOL getJump() const { return mbJump; } - BOOL getAutoPilot() const { return mAutoPilot; } - LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; } - - LLQuaternion getQuat() const; // returns the quat that represents the rotation - // of the agent in the absolute frame -// BOOL getLookingAtAvatar() const; - - void getName(std::string& name); - - const LLColor4 &getEffectColor(); - void setEffectColor(const LLColor4 &color); - // - // UTILITIES - // - - // Set the physics data - void slamLookAt(const LLVector3 &look_at); - - void setPositionAgent(const LLVector3 ¢er); - - void resetAxes(); - void resetAxes(const LLVector3 &look_at); // makes reasonable left and up - - // Move the avatar's frame + //-------------------------------------------------------------------- + // Move the avatar's frame + //-------------------------------------------------------------------- +public: void rotate(F32 angle, const LLVector3 &axis); void rotate(F32 angle, F32 x, F32 y, F32 z); void rotate(const LLMatrix3 &matrix); @@ -387,483 +538,23 @@ public: LLVector3 getReferenceUpVector(); F32 clampPitchToLimits(F32 angle); - void setThirdPersonHeadOffset(LLVector3 offset) { mThirdPersonHeadOffset = offset; } - // Flight management - BOOL getFlying() const { return mControlFlags & AGENT_CONTROL_FLY; } - void setFlying(BOOL fly); - void toggleFlying(); - - // Does this parcel allow you to fly? - BOOL canFly(); - - // Animation functions - void stopCurrentAnimations(); - void requestStopMotion( LLMotion* motion ); - void onAnimStop(const LLUUID& id); - - void sendAnimationRequests(LLDynamicArray &anim_ids, EAnimRequest request); - void sendAnimationRequest(const LLUUID &anim_id, EAnimRequest request); - - LLVector3 calcFocusOffset(LLViewerObject *object, LLVector3 pos_agent, S32 x, S32 y); - BOOL calcCameraMinDistance(F32 &obj_min_distance); - - void startCameraAnimation(); - void stopCameraAnimation(); - - void cameraZoomIn(const F32 factor); // zoom in by fraction of current distance - void cameraOrbitAround(const F32 radians); // rotate camera CCW radians about build focus point - void cameraOrbitOver(const F32 radians); // rotate camera forward radians over build focus point - void cameraOrbitIn(const F32 meters); // move camera in toward build focus point - - F32 getCameraZoomFraction(); // get camera zoom as fraction of minimum and maximum zoom - void setCameraZoomFraction(F32 fraction); // set camera zoom as fraction of minimum and maximum zoom - - void cameraPanIn(const F32 meters); - void cameraPanLeft(const F32 meters); - void cameraPanUp(const F32 meters); - - void updateFocusOffset(); - void validateFocusObject(); - - void setUsingFollowCam( bool using_follow_cam); - - F32 calcCustomizeAvatarUIOffset( const LLVector3d& camera_pos_global ); - - // marks current location as start, sends information to servers - void setStartPosition(U32 location_id); - - // Movement from user input. All set the appropriate animation flags. - // All turn off autopilot and make sure the camera is behind the avatar. - // direction is either positive, zero, or negative - void moveAt(S32 direction, bool reset_view = true); - void moveAtNudge(S32 direction); - void moveLeft(S32 direction); - void moveLeftNudge(S32 direction); - void moveUp(S32 direction); - void moveYaw(F32 mag, bool reset_view = true); - void movePitch(S32 direction); - - void setOrbitLeftKey(F32 mag) { mOrbitLeftKey = mag; } - void setOrbitRightKey(F32 mag) { mOrbitRightKey = mag; } - void setOrbitUpKey(F32 mag) { mOrbitUpKey = mag; } - void setOrbitDownKey(F32 mag) { mOrbitDownKey = mag; } - void setOrbitInKey(F32 mag) { mOrbitInKey = mag; } - void setOrbitOutKey(F32 mag) { mOrbitOutKey = mag; } - - void setPanLeftKey(F32 mag) { mPanLeftKey = mag; } - void setPanRightKey(F32 mag) { mPanRightKey = mag; } - void setPanUpKey(F32 mag) { mPanUpKey = mag; } - void setPanDownKey(F32 mag) { mPanDownKey = mag; } - void setPanInKey(F32 mag) { mPanInKey = mag; } - void setPanOutKey(F32 mag) { mPanOutKey = mag; } - - U32 getControlFlags(); - void setControlFlags(U32 mask); // performs bitwise mControlFlags |= mask - void clearControlFlags(U32 mask); // performs bitwise mControlFlags &= ~mask - BOOL controlFlagsDirty() const; - void enableControlFlagReset(); - void resetControlFlags(); - - void propagate(const F32 dt); // BUG: should roll into updateAgentPosition - - void startAutoPilotGlobal(const LLVector3d &pos_global, const std::string& behavior_name = std::string(), const LLQuaternion *target_rotation = NULL, - void (*finish_callback)(BOOL, void *) = NULL, void *callback_data = NULL, F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f); - + //-------------------------------------------------------------------- + // Autopilot + //-------------------------------------------------------------------- +public: + BOOL getAutoPilot() const { return mAutoPilot; } + LLVector3d getAutoPilotTargetGlobal() const { return mAutoPilotTargetGlobal; } + void startAutoPilotGlobal(const LLVector3d &pos_global, + const std::string& behavior_name = std::string(), + const LLQuaternion *target_rotation = NULL, + void (*finish_callback)(BOOL, void *) = NULL, void *callback_data = NULL, + F32 stop_distance = 0.f, F32 rotation_threshold = 0.03f); void startFollowPilot(const LLUUID &leader_id); void stopAutoPilot(BOOL user_cancel = FALSE); void setAutoPilotGlobal(const LLVector3d &pos_global); - void autoPilot(F32 *delta_yaw); // autopilot walking action, angles in radians + void autoPilot(F32 *delta_yaw); // Autopilot walking action, angles in radians void renderAutoPilotTarget(); - - // - // teportation methods - // - - // go to a named location home - void teleportRequest( - const U64& region_handle, - const LLVector3& pos_local); - - // teleport to a landmark - void teleportViaLandmark(const LLUUID& landmark_id); - - // go home - void teleportHome() { teleportViaLandmark(LLUUID::null); } - - // to an invited location - void teleportViaLure(const LLUUID& lure_id, BOOL godlike); - - // to a global location - this will probably need to be - // deprecated. - void teleportViaLocation(const LLVector3d& pos_global); - - // cancel the teleport, may or may not be allowed by server - void teleportCancel(); - - void setTargetVelocity(const LLVector3 &vel); - const LLVector3 &getTargetVelocity() const; - - const std::string getTeleportSourceSLURL() const { return mTeleportSourceSLURL; } - - - // Setting the ability for this avatar to proxy for another avatar. - //static void processAddModifyAbility(LLMessageSystem* msg, void**); - //static void processGrantedProxies(LLMessageSystem* msg, void**); - //static void processRemoveModifyAbility(LLMessageSystem* msg, void**); - //BOOL isProxyFor(const LLUUID& agent_id);// *FIX should be const - - static void processAgentDataUpdate(LLMessageSystem *msg, void **); - static void processAgentGroupDataUpdate(LLMessageSystem *msg, void **); - static void processAgentDropGroup(LLMessageSystem *msg, void **); - static void processScriptControlChange(LLMessageSystem *msg, void **); - static void processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data); - //static void processControlTake(LLMessageSystem *msg, void **); - //static void processControlRelease(LLMessageSystem *msg, void **); - - // This method checks to see if this agent can modify an object - // based on the permissions and the agent's proxy status. - BOOL isGrantedProxy(const LLPermissions& perm); - - BOOL allowOperation(PermissionBit op, - const LLPermissions& perm, - U64 group_proxy_power = 0, - U8 god_minimum = GOD_MAINTENANCE); - - friend std::ostream& operator<<(std::ostream &s, const LLAgent &sphere); - - void initOriginGlobal(const LLVector3d &origin_global); // Only to be used in ONE place! - djs 08/07/02 - - BOOL leftButtonGrabbed() const { return ( (!cameraMouselook() && mControlsTakenCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) - ||(cameraMouselook() && mControlsTakenCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0) - ||(!cameraMouselook() && mControlsTakenPassedOnCount[CONTROL_LBUTTON_DOWN_INDEX] > 0) - ||(cameraMouselook() && mControlsTakenPassedOnCount[CONTROL_ML_LBUTTON_DOWN_INDEX] > 0)); } - BOOL rotateGrabbed() const { return ( (mControlsTakenCount[CONTROL_YAW_POS_INDEX] > 0) - ||(mControlsTakenCount[CONTROL_YAW_NEG_INDEX] > 0)); } - BOOL forwardGrabbed() const { return ( (mControlsTakenCount[CONTROL_AT_POS_INDEX] > 0)); } - BOOL backwardGrabbed() const { return ( (mControlsTakenCount[CONTROL_AT_NEG_INDEX] > 0)); } - BOOL upGrabbed() const { return ( (mControlsTakenCount[CONTROL_UP_POS_INDEX] > 0)); } - BOOL downGrabbed() const { return ( (mControlsTakenCount[CONTROL_UP_NEG_INDEX] > 0)); } - - // True iff a script has taken over a control. - BOOL anyControlGrabbed() const; - - BOOL isControlGrabbed(S32 control_index) const; - - // Send message to simulator to force grabbed controls to be - // released, in case of a poorly written script. - void forceReleaseControls(); - - BOOL sitCameraEnabled() { return mSitCameraEnabled; } - - F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); } - - // look at behavior - BOOL setLookAt(ELookAtType target_type, LLViewerObject *object = NULL, LLVector3 position = LLVector3::zero); - ELookAtType getLookAtType(); - - // point at behavior - BOOL setPointAt(EPointAtType target_type, LLViewerObject *object = NULL, LLVector3 position = LLVector3::zero); - EPointAtType getPointAtType(); - - void setHomePosRegion( const U64& region_handle, const LLVector3& pos_region ); - BOOL getHomePosGlobal( LLVector3d* pos_global ); - void setCameraAnimating( BOOL b ) { mCameraAnimating = b; } - BOOL getCameraAnimating( ) { return mCameraAnimating; } - void setAnimationDuration( F32 seconds ) { mAnimationDuration = seconds; } - - F32 getNearChatRadius() { return mNearChatRadius; } - - enum EDoubleTapRunMode - { - DOUBLETAP_NONE, - DOUBLETAP_FORWARD, - DOUBLETAP_BACKWARD, - DOUBLETAP_SLIDELEFT, - DOUBLETAP_SLIDERIGHT - }; - - enum ETeleportState - { - TELEPORT_NONE = 0, // No teleport in progress - TELEPORT_START = 1, // Transition to REQUESTED. Viewer has sent a TeleportRequest to the source simulator - TELEPORT_REQUESTED = 2, // Waiting for source simulator to respond - TELEPORT_MOVING = 3, // Viewer has received destination location from source simulator - TELEPORT_START_ARRIVAL = 4, // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator - TELEPORT_ARRIVING = 5 // Make the user wait while content "pre-caches" - }; - - ETeleportState getTeleportState() const { return mTeleportState; } - void setTeleportState( ETeleportState state ); - const std::string& getTeleportMessage() const { return mTeleportMessage; } - void setTeleportMessage(const std::string& message) - { - mTeleportMessage = message; - } - - // trigger random fidget animations - void fidget(); - - void requestEnterGodMode(); - void requestLeaveGodMode(); - - void sendAgentSetAppearance(); - - void sendAgentDataUpdateRequest(); - - // Ventrella - LLFollowCam mFollowCam; - // end Ventrella - - //-------------------------------------------------------------------- - // Wearables - //-------------------------------------------------------------------- - void setWearable( LLInventoryItem* new_item, LLWearable* wearable ); - static bool onSetWearableDialog( const LLSD& notification, const LLSD& response, LLWearable* wearable ); - void setWearableFinal( LLInventoryItem* new_item, LLWearable* new_wearable ); - void setWearableOutfit( const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove ); - void queryWearableCache(); - - BOOL isWearableModifiable(EWearableType type); - BOOL isWearableCopyable(EWearableType type); - BOOL needsReplacement(EWearableType wearableType, S32 remove); - U32 getWearablePermMask(EWearableType type); - - LLInventoryItem* getWearableInventoryItem(EWearableType type); - - LLWearable* getWearable( EWearableType type ) { return (type < WT_COUNT) ? mWearableEntry[ type ].mWearable : NULL; } - BOOL isWearingItem( const LLUUID& item_id ); - LLWearable* getWearableFromWearableItem( const LLUUID& item_id ); - const LLUUID& getWearableItem( EWearableType type ) { return (type < WT_COUNT) ? mWearableEntry[ type ].mItemID : LLUUID::null; } - - static EWearableType getTEWearableType( S32 te ); - static LLUUID getDefaultTEImageID( S32 te ); - - void copyWearableToInventory( EWearableType type ); - - void makeNewOutfit( - const std::string& new_folder_name, - const LLDynamicArray& wearables_to_include, - const LLDynamicArray& attachments_to_include, - BOOL rename_clothing); - void makeNewOutfitDone(S32 index); - - void removeWearable( EWearableType type ); - static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response ); - void removeWearableFinal( EWearableType type ); - - void sendAgentWearablesUpdate(); - - /** - * @brief Only public because of addWearableToAgentInventoryCallback. - * - * NOTE: Do not call this method unless you are the inventory callback. - * NOTE: This can suffer from race conditions when working on the - * same values for index. - * @param index The index in mWearableEntry. - * @param item_id The inventory item id of the new wearable to wear. - * @param wearable The actual wearable data. - */ - void addWearabletoAgentInventoryDone( - S32 index, - const LLUUID& item_id, - LLWearable* wearable); - - void saveWearableAs( EWearableType type, const std::string& new_name, BOOL save_in_lost_and_found ); - void saveWearable( EWearableType type, BOOL send_update = TRUE ); - void saveAllWearables(); - - void revertWearable( EWearableType type ); - void revertAllWearables(); - - void setWearableName( const LLUUID& item_id, const std::string& new_name ); - void createStandardWearables(BOOL female); - void createStandardWearablesDone(S32 index); - void createStandardWearablesAllDone(); - - BOOL areWearablesLoaded() { return mWearablesLoaded; } - - void sendWalkRun(bool running); - - void observeFriends(); - void friendsChanged(); - - // statics - static void stopFidget(); - static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); - static void userRemoveWearable( void* userdata ); // userdata is EWearableType - static void userRemoveAllClothes( void* userdata ); // userdata is NULL - static void userRemoveAllClothesStep2(BOOL proceed, void* userdata ); // userdata is NULL - static void userRemoveAllAttachments( void* userdata); // userdata is NULL - static BOOL selfHasWearable( void* userdata ); // userdata is EWearableType - - //debug methods - static void clearVisualParams(void *); - -protected: - // stuff to do for any sort of teleport. Returns true if the - // teleport can proceed. - bool teleportCore(bool is_local = false); - - // helper function to prematurely age chat when agent is moving - void ageChat(); - - // internal wearable functions - void sendAgentWearablesRequest(); - static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata); - void recoverMissingWearable(EWearableType type); - void recoverMissingWearableDone(); - void addWearableToAgentInventory(LLPointer cb, - LLWearable* wearable, const LLUUID& category_id = LLUUID::null, - BOOL notify = TRUE); -public: - // TODO: Make these private! - LLUUID mSecureSessionID; // secure token for this login session - - F32 mDrawDistance; - - U64 mGroupPowers; - BOOL mHideGroupTitle; - std::string mGroupTitle; // honorific, like "Sir" - std::string mGroupName; - LLUUID mGroupID; - //LLUUID mGroupInsigniaID; - LLUUID mInventoryRootID; - LLUUID mMapID; - F64 mMapOriginX; // Global x coord of mMapID's bottom left corner. - F64 mMapOriginY; // Global y coord of mMapID's bottom left corner. - S32 mMapWidth; // Width of map in meters - S32 mMapHeight; // Height of map in meters - std::string mMOTD; // message of the day - - LLPointer mLookAt; - LLPointer mPointAt; - - LLDynamicArray mGroups; - - F32 mHUDTargetZoom; // target zoom level for HUD objects (used when editing) - F32 mHUDCurZoom; // current animated zoom level for HUD objects - - BOOL mInitialized; - - S32 mNumPendingQueries; - S32* mActiveCacheQueries; - - BOOL mForceMouselook; - - static void parseTeleportMessages(const std::string& xml_filename); - //we should really define ERROR and PROGRESS enums here - //but I don't really feel like doing that, so I am just going - //to expose the mappings....yup - static std::map sTeleportErrorMessages; - static std::map sTeleportProgressMessages; - - LLFrameTimer mDoubleTapRunTimer; - EDoubleTapRunMode mDoubleTapRunMode; - private: - bool mbAlwaysRun; // should the avatar run by default rather than walk - bool mbRunning; // is the avatar trying to run right now - - LLAgentAccess mAgentAccess; - - ETeleportState mTeleportState; - std::string mTeleportMessage; - - S32 mControlsTakenCount[TOTAL_CONTROLS]; - S32 mControlsTakenPassedOnCount[TOTAL_CONTROLS]; - - LLViewerRegion *mRegionp; - LLVector3d mAgentOriginGlobal; // Origin of agent coords from global coords - mutable LLVector3d mPositionGlobal; - - std::string mTeleportSourceSLURL; // SLURL where last TP began. - - std::set mRegionsVisited; // stat - what distinct regions has the avatar been to? - F64 mDistanceTraveled; // stat - how far has the avatar moved? - LLVector3d mLastPositionGlobal; // Used to calculate travel distance - - LLPointer mAvatarObject; // NULL until avatar object sent down from simulator - - U8 mRenderState; // Current behavior state of agent - LLFrameTimer mTypingTimer; - - ECameraMode mCameraMode; // target mode after transition animation is done - ECameraMode mLastCameraMode; - BOOL mViewsPushed; // keep track of whether or not we have pushed views. - - BOOL mCustomAnim ; //current animation is ANIM_AGENT_CUSTOMIZE ? - BOOL mShowAvatar; // should we render the avatar? - BOOL mCameraAnimating; // camera is transitioning from one mode to another - LLVector3d mAnimationCameraStartGlobal; // camera start position, global coords - LLVector3d mAnimationFocusStartGlobal; // camera focus point, global coords - LLFrameTimer mAnimationTimer; // seconds that transition animation has been active - F32 mAnimationDuration; // seconds - F32 mCameraFOVZoomFactor; // amount of fov zoom applied to camera when zeroing in on an object - F32 mCameraCurrentFOVZoomFactor; // interpolated fov zoom - F32 mCameraFOVDefault; // default field of view that is basis for FOV zoom effect - LLVector3d mCameraFocusOffset; // offset from focus point in build mode - LLVector3d mCameraFocusOffsetTarget; // target towards which we are lerping the camera's focus offset - LLVector3 mCameraOffsetDefault; // default third-person camera offset - LLVector4 mCameraCollidePlane; // colliding plane for camera - F32 mCurrentCameraDistance; // current camera offset from avatar - F32 mTargetCameraDistance; // target camera offset from avatar - F32 mCameraZoomFraction; // mousewheel driven fraction of zoom - LLVector3 mCameraLag; // third person camera lag - LLVector3 mThirdPersonHeadOffset; // head offset for third person camera position - LLVector3 mCameraPositionAgent; // camera position in agent coordinates - LLVector3 mCameraVirtualPositionAgent; // camera virtual position (target) before performing FOV zoom - BOOL mSitCameraEnabled; // use provided camera information when sitting? - LLVector3 mSitCameraPos; // root relative camera pos when sitting - LLVector3 mSitCameraFocus; // root relative camera target when sitting - LLVector3d mCameraSmoothingLastPositionGlobal; - LLVector3d mCameraSmoothingLastPositionAgent; - BOOL mCameraSmoothingStop; - - LLVector3 mCameraUpVector; // camera's up direction in world coordinates (determines the 'roll' of the view) - - LLPointer mSitCameraReferenceObject; // object to which camera is related when sitting - - BOOL mFocusOnAvatar; - LLVector3d mFocusGlobal; - LLVector3d mFocusTargetGlobal; - LLPointer mFocusObject; - F32 mFocusObjectDist; - LLVector3 mFocusObjectOffset; - F32 mFocusDotRadius; // meters - BOOL mTrackFocusObject; - F32 mUIOffset; - - LLCoordFrame mFrameAgent; // Agent position and view, agent-region coordinates - - BOOL mIsBusy; - - S32 mAtKey; // Either 1, 0, or -1... indicates that movement-key is pressed - S32 mWalkKey; // like AtKey, but causes less forward thrust - S32 mLeftKey; - S32 mUpKey; - F32 mYawKey; - S32 mPitchKey; - - F32 mOrbitLeftKey; - F32 mOrbitRightKey; - F32 mOrbitUpKey; - F32 mOrbitDownKey; - F32 mOrbitInKey; - F32 mOrbitOutKey; - - F32 mPanUpKey; - F32 mPanDownKey; - F32 mPanLeftKey; - F32 mPanRightKey; - F32 mPanInKey; - F32 mPanOutKey; - - U32 mControlFlags; // replacement for the mFooKey's - BOOL mbFlagsDirty; - BOOL mbFlagsNeedReset; // HACK for preventing incorrect flags sent when crossing region boundaries - - BOOL mbJump; - BOOL mAutoPilot; BOOL mAutoPilotFlyOnStop; LLVector3d mAutoPilotTargetGlobal; @@ -877,91 +568,528 @@ private: void (*mAutoPilotFinishedCallback)(BOOL, void *); void* mAutoPilotCallbackData; LLUUID mLeaderID; + +/** Movement + ** ** + *******************************************************************************/ - std::set mProxyForAgents; +/******************************************************************************** + ** ** + ** TELEPORT + **/ - LLColor4 mEffectColor; +public: + enum ETeleportState + { + TELEPORT_NONE = 0, // No teleport in progress + TELEPORT_START = 1, // Transition to REQUESTED. Viewer has sent a TeleportRequest to the source simulator + TELEPORT_REQUESTED = 2, // Waiting for source simulator to respond + TELEPORT_MOVING = 3, // Viewer has received destination location from source simulator + TELEPORT_START_ARRIVAL = 4, // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator + TELEPORT_ARRIVING = 5 // Make the user wait while content "pre-caches" + }; - BOOL mHaveHomePosition; - U64 mHomeRegionHandle; - LLVector3 mHomePosRegion; - LLFrameTimer mChatTimer; - LLUUID mLastChatterID; - F32 mNearChatRadius; +public: + static void parseTeleportMessages(const std::string& xml_filename); + const std::string getTeleportSourceSLURL() const { return mTeleportSourceSLURL; } +public: + // ! TODO ! Define ERROR and PROGRESS enums here instead of exposing the mappings. + static std::map sTeleportErrorMessages; + static std::map sTeleportProgressMessages; +private: + std::string mTeleportSourceSLURL; // SLURL where last TP began - LLFrameTimer mFidgetTimer; - LLFrameTimer mFocusObjectFadeTimer; - F32 mNextFidgetTime; - S32 mCurrentFidget; - BOOL mFirstLogin; - BOOL mGenderChosen; + //-------------------------------------------------------------------- + // Teleport Actions + //-------------------------------------------------------------------- +public: + void teleportRequest(const U64& region_handle, + const LLVector3& pos_local); // Go to a named location home + void teleportViaLandmark(const LLUUID& landmark_id); // Teleport to a landmark + void teleportHome() { teleportViaLandmark(LLUUID::null); } // Go home + void teleportViaLure(const LLUUID& lure_id, BOOL godlike); // To an invited location + void teleportViaLocation(const LLVector3d& pos_global); // To a global location - this will probably need to be deprecated + void teleportCancel(); // May or may not be allowed by server +protected: + bool teleportCore(bool is_local = false); // Stuff for all teleports; returns true if the teleport can proceed + + //-------------------------------------------------------------------- + // Teleport State + //-------------------------------------------------------------------- +public: + ETeleportState getTeleportState() const { return mTeleportState; } + void setTeleportState(ETeleportState state); +private: + ETeleportState mTeleportState; + + //-------------------------------------------------------------------- + // Teleport Message + //-------------------------------------------------------------------- +public: + const std::string& getTeleportMessage() const { return mTeleportMessage; } + void setTeleportMessage(const std::string& message) { mTeleportMessage = message; } +private: + std::string mTeleportMessage; + +/** Teleport + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** CAMERA + **/ + + //-------------------------------------------------------------------- + // Mode + //-------------------------------------------------------------------- +public: + void changeCameraToDefault(); + void changeCameraToMouselook(BOOL animate = TRUE); + void changeCameraToThirdPerson(BOOL animate = TRUE); + void changeCameraToCustomizeAvatar(BOOL avatar_animate = TRUE, BOOL camera_animate = TRUE); // Trigger transition animation + void changeCameraToFollow(BOOL animate = TRUE); // Ventrella + BOOL cameraThirdPerson() const { return (mCameraMode == CAMERA_MODE_THIRD_PERSON && mLastCameraMode == CAMERA_MODE_THIRD_PERSON); } + BOOL cameraMouselook() const { return (mCameraMode == CAMERA_MODE_MOUSELOOK && mLastCameraMode == CAMERA_MODE_MOUSELOOK); } + BOOL cameraCustomizeAvatar() const { return (mCameraMode == CAMERA_MODE_CUSTOMIZE_AVATAR /*&& !mCameraAnimating*/); } + BOOL cameraFollow() const { return (mCameraMode == CAMERA_MODE_FOLLOW && mLastCameraMode == CAMERA_MODE_FOLLOW); } + ECameraMode getCameraMode() const { return mCameraMode; } + void updateCamera(); // Call once per frame to update camera location/orientation + void resetCamera(); // Slam camera into its default position +private: + ECameraMode mCameraMode; // Target mode after transition animation is done + ECameraMode mLastCameraMode; + + //-------------------------------------------------------------------- + // Preset + //-------------------------------------------------------------------- +public: + void switchCameraPreset(ECameraPreset preset); + +private: + + /** Determines default camera offset depending on the current camera preset */ + LLVector3 getCameraOffsetInitial(); + + /** Camera preset in Third Person Mode */ + ECameraPreset mCameraPreset; + + /** Initial camera offsets */ + std::map mCameraOffsetInitial; + + /** Initial focus offsets */ + std::map mFocusOffsetInitial; + + + //-------------------------------------------------------------------- + // Position + //-------------------------------------------------------------------- +public: + LLVector3d getCameraPositionGlobal() const; + const LLVector3 &getCameraPositionAgent() const; + LLVector3d calcCameraPositionTargetGlobal(BOOL *hit_limit = NULL); // Calculate the camera position target + F32 getCameraMinOffGround(); // Minimum height off ground for this mode, meters + void setCameraCollidePlane(const LLVector4 &plane) { mCameraCollidePlane = plane; } + BOOL calcCameraMinDistance(F32 &obj_min_distance); + F32 calcCustomizeAvatarUIOffset(const LLVector3d& camera_pos_global); + F32 getCurrentCameraBuildOffset() { return (F32)mCameraFocusOffset.length(); } +private: + F32 mCurrentCameraDistance; // Current camera offset from avatar + F32 mTargetCameraDistance; // Target camera offset from avatar + F32 mCameraFOVZoomFactor; // Amount of fov zoom applied to camera when zeroing in on an object + F32 mCameraCurrentFOVZoomFactor; // Interpolated fov zoom + F32 mCameraFOVDefault; // Default field of view that is basis for FOV zoom effect + LLVector4 mCameraCollidePlane; // Colliding plane for camera + F32 mCameraZoomFraction; // Mousewheel driven fraction of zoom + LLVector3 mCameraPositionAgent; // Camera position in agent coordinates + LLVector3 mCameraVirtualPositionAgent; // Camera virtual position (target) before performing FOV zoom + LLVector3d mCameraSmoothingLastPositionGlobal; + LLVector3d mCameraSmoothingLastPositionAgent; + BOOL mCameraSmoothingStop; + LLVector3 mCameraLag; // Third person camera lag + LLVector3 mCameraUpVector; // Camera's up direction in world coordinates (determines the 'roll' of the view) + + //-------------------------------------------------------------------- + // Follow + //-------------------------------------------------------------------- +public: + void setUsingFollowCam(bool using_follow_cam); +private: + LLFollowCam mFollowCam; // Ventrella + + //-------------------------------------------------------------------- + // Sit + //-------------------------------------------------------------------- +public: + void setupSitCamera(); + BOOL sitCameraEnabled() { return mSitCameraEnabled; } + void setSitCamera(const LLUUID &object_id, + const LLVector3 &camera_pos = LLVector3::zero, const LLVector3 &camera_focus = LLVector3::zero); +private: + LLPointer mSitCameraReferenceObject; // Object to which camera is related when sitting + BOOL mSitCameraEnabled; // Use provided camera information when sitting? + LLVector3 mSitCameraPos; // Root relative camera pos when sitting + LLVector3 mSitCameraFocus; // Root relative camera target when sitting + + //-------------------------------------------------------------------- + // Animation + //-------------------------------------------------------------------- +public: + void setCameraAnimating(BOOL b) { mCameraAnimating = b; } + BOOL getCameraAnimating() { return mCameraAnimating; } + void setAnimationDuration(F32 seconds) { mAnimationDuration = seconds; } + void startCameraAnimation(); + void stopCameraAnimation(); +private: + BOOL mCameraAnimating; // Camera is transitioning from one mode to another + LLVector3d mAnimationCameraStartGlobal; // Camera start position, global coords + LLVector3d mAnimationFocusStartGlobal; // Camera focus point, global coords + + //-------------------------------------------------------------------- + // Focus + //-------------------------------------------------------------------- +public: + LLVector3d calcFocusPositionTargetGlobal(); + LLVector3 calcFocusOffset(LLViewerObject *object, LLVector3 pos_agent, S32 x, S32 y); + BOOL getFocusOnAvatar() const { return mFocusOnAvatar; } + LLPointer& getFocusObject() { return mFocusObject; } + F32 getFocusObjectDist() const { return mFocusObjectDist; } + void updateFocusOffset(); + void validateFocusObject(); + void setFocusGlobal(const LLPickInfo& pick); + void setFocusGlobal(const LLVector3d &focus, const LLUUID &object_id = LLUUID::null); + void setFocusOnAvatar(BOOL focus, BOOL animate); + void setCameraPosAndFocusGlobal(const LLVector3d& pos, const LLVector3d& focus, const LLUUID &object_id); + void clearFocusObject(); + void setFocusObject(LLViewerObject* object); + void setObjectTracking(BOOL track) { mTrackFocusObject = track; } + const LLVector3d &getFocusGlobal() const { return mFocusGlobal; } + const LLVector3d &getFocusTargetGlobal() const { return mFocusTargetGlobal; } +private: + LLVector3d mCameraFocusOffset; // Offset from focus point in build mode + LLVector3d mCameraFocusOffsetTarget; // Target towards which we are lerping the camera's focus offset + BOOL mFocusOnAvatar; + LLVector3d mFocusGlobal; + LLVector3d mFocusTargetGlobal; + LLPointer mFocusObject; + F32 mFocusObjectDist; + LLVector3 mFocusObjectOffset; + F32 mFocusDotRadius; // Meters + BOOL mTrackFocusObject; + F32 mUIOffset; //-------------------------------------------------------------------- - // Wearables + // Lookat / Pointat //-------------------------------------------------------------------- - struct LLWearableEntry - { - LLWearableEntry() : mItemID( LLUUID::null ), mWearable( NULL ) {} +public: + void updateLookAt(const S32 mouse_x, const S32 mouse_y); + BOOL setLookAt(ELookAtType target_type, LLViewerObject *object = NULL, LLVector3 position = LLVector3::zero); + ELookAtType getLookAtType(); + void slamLookAt(const LLVector3 &look_at); // Set the physics data + BOOL setPointAt(EPointAtType target_type, LLViewerObject *object = NULL, LLVector3 position = LLVector3::zero); + EPointAtType getPointAtType(); +public: + LLPointer mLookAt; + LLPointer mPointAt; - LLUUID mItemID; // ID of the inventory item in the agent's inventory. - LLWearable* mWearable; - }; - LLWearableEntry mWearableEntry[ WT_COUNT ]; - U32 mAgentWearablesUpdateSerialNum; - BOOL mWearablesLoaded; - S32 mTextureCacheQueryID; + //-------------------------------------------------------------------- + // Third person + //-------------------------------------------------------------------- +public: + LLVector3d calcThirdPersonFocusOffset(); + void setThirdPersonHeadOffset(LLVector3 offset) { mThirdPersonHeadOffset = offset; } +private: + LLVector3 mThirdPersonHeadOffset; // Head offset for third person camera position + + //-------------------------------------------------------------------- + // Orbit + //-------------------------------------------------------------------- +public: + void cameraOrbitAround(const F32 radians); // Rotate camera CCW radians about build focus point + void cameraOrbitOver(const F32 radians); // Rotate camera forward radians over build focus point + void cameraOrbitIn(const F32 meters); // Move camera in toward build focus point + + //-------------------------------------------------------------------- + // Zoom + //-------------------------------------------------------------------- +public: + void handleScrollWheel(S32 clicks); // Mousewheel driven zoom + void cameraZoomIn(const F32 factor); // Zoom in by fraction of current distance + F32 getCameraZoomFraction(); // Get camera zoom as fraction of minimum and maximum zoom + void setCameraZoomFraction(F32 fraction); // Set camera zoom as fraction of minimum and maximum zoom + F32 calcCameraFOVZoomFactor(); + + //-------------------------------------------------------------------- + // Pan + //-------------------------------------------------------------------- +public: + void cameraPanIn(const F32 meters); + void cameraPanLeft(const F32 meters); + void cameraPanUp(const F32 meters); + + //-------------------------------------------------------------------- + // View + //-------------------------------------------------------------------- +public: + // Called whenever the agent moves. Puts camera back in default position, deselects items, etc. + void resetView(BOOL reset_camera = TRUE, BOOL change_camera = FALSE); + // Called on camera movement. Unlocks camera from the default position behind the avatar. + void unlockView(); + + //-------------------------------------------------------------------- + // Mouselook + //-------------------------------------------------------------------- +public: + BOOL getForceMouselook() const { return mForceMouselook; } + void setForceMouselook(BOOL mouselook) { mForceMouselook = mouselook; } +private: + BOOL mForceMouselook; + + //-------------------------------------------------------------------- + // HUD + //-------------------------------------------------------------------- +public: + const LLColor4 &getEffectColor(); + void setEffectColor(const LLColor4 &color); +public: + F32 mHUDTargetZoom; // Target zoom level for HUD objects (used when editing) + F32 mHUDCurZoom; // Current animated zoom level for HUD objects +private: + LLUIColor mEffectColor; + +/** Camera + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** ACCESS + **/ + +public: + // Checks if agent can modify an object based on the permissions and the agent's proxy status. + BOOL isGrantedProxy(const LLPermissions& perm); + BOOL allowOperation(PermissionBit op, + const LLPermissions& perm, + U64 group_proxy_power = 0, + U8 god_minimum = GOD_MAINTENANCE); + const LLAgentAccess& getAgentAccess(); + BOOL canManageEstate() const; + BOOL getAdminOverride() const; + // ! BACKWARDS COMPATIBILITY ! This function can go away after the AO transition (see llstartup.cpp). + void setAOTransition(); +private: + LLAgentAccess mAgentAccess; + + //-------------------------------------------------------------------- + // God + //-------------------------------------------------------------------- +public: + BOOL isGodlike() const; + U8 getGodLevel() const; + void setAdminOverride(BOOL b); + void setGodLevel(U8 god_level); + void requestEnterGodMode(); + void requestLeaveGodMode(); + + //-------------------------------------------------------------------- + // Maturity + //-------------------------------------------------------------------- +public: + // Note: this is a prime candidate for pulling out into a Maturity class. + // Rather than just expose the preference setting, we're going to actually + // expose what the client code cares about -- what the user should see + // based on a combination of the is* and prefers* flags, combined with god bit. + bool wantsPGOnly() const; + bool canAccessMature() const; + bool canAccessAdult() const; + bool canAccessMaturityInRegion( U64 region_handle ) const; + bool canAccessMaturityAtGlobal( LLVector3d pos_global ) const; + bool prefersPG() const; + bool prefersMature() const; + bool prefersAdult() const; + bool isTeen() const; + bool isMature() const; + bool isAdult() const; + void setTeen(bool teen); + void setMaturity(char text); + static int convertTextToMaturity(char text); + bool sendMaturityPreferenceToServer(int preferredMaturity); // ! "U8" instead of "int"? + + // Maturity callbacks for PreferredMaturity control variable + void handleMaturity(const LLSD& newvalue); + bool validateMaturity(const LLSD& newvalue); + + +/** Access + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** RENDERING + **/ + +public: + LLQuaternion getHeadRotation(); + BOOL needsRenderAvatar(); // TRUE when camera mode is such that your own avatar should draw + BOOL needsRenderHead(); +public: + F32 mDrawDistance; +private: + BOOL mShowAvatar; // Should we render the avatar? U32 mAppearanceSerialNum; - LLAnimPauseRequest mPauseRequest; + + //-------------------------------------------------------------------- + // Rendering state bitmap helpers + //-------------------------------------------------------------------- +public: + void setRenderState(U8 newstate); + void clearRenderState(U8 clearstate); + U8 getRenderState(); +private: + U8 mRenderState; // Current behavior state of agent - class createStandardWearablesAllDoneCallback : public LLRefCount - { - protected: - ~createStandardWearablesAllDoneCallback(); - }; - class sendAgentWearablesUpdateCallback : public LLRefCount - { - protected: - ~sendAgentWearablesUpdateCallback(); - }; +/** Rendering + ** ** + *******************************************************************************/ - class addWearableToAgentInventoryCallback : public LLInventoryCallback - { - public: - enum { - CALL_NONE = 0, - CALL_UPDATE = 1, - CALL_RECOVERDONE = 2, - CALL_CREATESTANDARDDONE = 4, - CALL_MAKENEWOUTFITDONE = 8 - } EType; +/******************************************************************************** + ** ** + ** GROUPS + **/ - /** - * @brief Construct a callback for dealing with the wearables. - * - * Would like to pass the agent in here, but we can't safely - * count on it being around later. Just use gAgent directly. - * @param cb callback to execute on completion (??? unused ???) - * @param index Index for the wearable in the agent - * @param wearable The wearable data. - * @param todo Bitmask of actions to take on completion. - */ - addWearableToAgentInventoryCallback( - LLPointer cb, - S32 index, - LLWearable* wearable, - U32 todo = CALL_NONE); - virtual void fire(const LLUUID& inv_item); +public: + const LLUUID &getGroupID() const { return mGroupID; } + // Get group information by group_id, or FALSE if not in group. + BOOL getGroupData(const LLUUID& group_id, LLGroupData& data) const; + // Get just the agent's contribution to the given group. + S32 getGroupContribution(const LLUUID& group_id) const; + // Update internal datastructures and update the server. + BOOL setGroupContribution(const LLUUID& group_id, S32 contribution); + BOOL setUserGroupFlags(const LLUUID& group_id, BOOL accept_notices, BOOL list_in_profile); + const std::string &getGroupName() const { return mGroupName; } +private: + std::string mGroupName; + LLUUID mGroupID; - private: - S32 mIndex; - LLWearable* mWearable; - U32 mTodo; - LLPointer mCB; - }; + //-------------------------------------------------------------------- + // Group Membership + //-------------------------------------------------------------------- +public: + // Checks against all groups in the entire agent group list. + BOOL isInGroup(const LLUUID& group_id) const; +protected: + // Only used for building titles. + BOOL isGroupMember() const { return !mGroupID.isNull(); } +public: + LLDynamicArray mGroups; + //-------------------------------------------------------------------- + // Group Title + //-------------------------------------------------------------------- +public: + void setHideGroupTitle(BOOL hide) { mHideGroupTitle = hide; } + BOOL isGroupTitleHidden() const { return mHideGroupTitle; } +private: + std::string mGroupTitle; // Honorific, like "Sir" + BOOL mHideGroupTitle; + + //-------------------------------------------------------------------- + // Group Powers + //-------------------------------------------------------------------- +public: + BOOL hasPowerInGroup(const LLUUID& group_id, U64 power) const; + BOOL hasPowerInActiveGroup(const U64 power) const; + U64 getPowerInGroup(const LLUUID& group_id) const; + U64 mGroupPowers; + + //-------------------------------------------------------------------- + // Friends + //-------------------------------------------------------------------- +public: + void observeFriends(); + void friendsChanged(); +private: LLFriendObserver* mFriendObserver; + std::set mProxyForAgents; + +/** Groups + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** MESSAGING + **/ + + //-------------------------------------------------------------------- + // Send + //-------------------------------------------------------------------- +public: + void sendMessage(); // Send message to this agent's region + void sendReliableMessage(); + void sendAgentSetAppearance(); + void sendAgentDataUpdateRequest(); + void sendAgentUserInfoRequest(); + // IM to Email and Online visibility + void sendAgentUpdateUserInfo(bool im_to_email, const std::string& directory_visibility); + + //-------------------------------------------------------------------- + // Receive + //-------------------------------------------------------------------- +public: + static void processAgentDataUpdate(LLMessageSystem *msg, void **); + static void processAgentGroupDataUpdate(LLMessageSystem *msg, void **); + static void processAgentDropGroup(LLMessageSystem *msg, void **); + static void processScriptControlChange(LLMessageSystem *msg, void **); + static void processAgentCachedTextureResponse(LLMessageSystem *mesgsys, void **user_data); + +/** Messaging + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** DEBUGGING + **/ + +public: + static void dumpGroupInfo(); + static void clearVisualParams(void *); + friend std::ostream& operator<<(std::ostream &s, const LLAgent &sphere); + +/** Debugging + ** ** + *******************************************************************************/ + }; extern LLAgent gAgent; +inline bool operator==(const LLGroupData &a, const LLGroupData &b) +{ + return (a.mID == b.mID); +} + +class LLAgentQueryManager +{ + friend class LLAgent; + friend class LLAgentWearables; + +public: + LLAgentQueryManager(); + virtual ~LLAgentQueryManager(); + + BOOL hasNoPendingQueries() const { return getNumPendingQueries() == 0; } + S32 getNumPendingQueries() const { return mNumPendingQueries; } +private: + S32 mNumPendingQueries; + S32 mWearablesCacheQueryID; + U32 mUpdateSerialNum; + S32 mActiveCacheQueries[LLVOAvatarDefines::BAKED_NUM_INDICES]; +}; + +extern LLAgentQueryManager gAgentQueryManager; + #endif diff --git a/indra/newview/llagentaccess.cpp b/indra/newview/llagentaccess.cpp index a4fbc04855..eb978eb6c1 100644 --- a/indra/newview/llagentaccess.cpp +++ b/indra/newview/llagentaccess.cpp @@ -3,16 +3,39 @@ * @brief LLAgentAccess class implementation - manages maturity and godmode info * * $LicenseInfo:firstyear=2001&license=viewergpl$ + * * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llagentaccess.h" #include "indra_constants.h" -#include "llcontrolgroupreader.h" +#include "llcontrol.h" -LLAgentAccess::LLAgentAccess(LLControlGroupReader& savedSettings) : +LLAgentAccess::LLAgentAccess(LLControlGroup& savedSettings) : mSavedSettings(savedSettings), mAccess(SIM_ACCESS_PG), mAdminOverride(false), @@ -140,6 +163,20 @@ int LLAgentAccess::convertTextToMaturity(char text) void LLAgentAccess::setMaturity(char text) { mAccess = LLAgentAccess::convertTextToMaturity(text); + U32 preferred_access = mSavedSettings.getU32("PreferredMaturity"); + while (!canSetMaturity(preferred_access)) + { + if (preferred_access == SIM_ACCESS_ADULT) + { + preferred_access = SIM_ACCESS_MATURE; + } + else + { + // Mature or invalid access gets set to PG + preferred_access = SIM_ACCESS_PG; + } + } + mSavedSettings.setU32("PreferredMaturity", preferred_access); } void LLAgentAccess::setTransition() @@ -152,3 +189,14 @@ bool LLAgentAccess::isInTransition() const return mAOTransition; } +bool LLAgentAccess::canSetMaturity(S32 maturity) +{ + if (isGodlike()) // Gods can always set their Maturity level + return true; + if (isAdult()) // Adults can always set their Maturity level + return true; + if (maturity == SIM_ACCESS_PG || (maturity == SIM_ACCESS_MATURE && isMature())) + return true; + else + return false; +} diff --git a/indra/newview/llagentaccess.h b/indra/newview/llagentaccess.h index dec0d76cc9..93d2f0a371 100644 --- a/indra/newview/llagentaccess.h +++ b/indra/newview/llagentaccess.h @@ -3,7 +3,30 @@ * @brief LLAgentAccess class implementation - manages maturity and godmode info * * $LicenseInfo:firstyear=2001&license=viewergpl$ + * * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. * $/LicenseInfo$ */ @@ -13,12 +36,12 @@ #include "stdtypes.h" // forward declaration so that we don't have to include the whole class -class LLControlGroupReader; +class LLControlGroup; class LLAgentAccess { public: - LLAgentAccess(LLControlGroupReader& savedSettings); + LLAgentAccess(LLControlGroup& savedSettings); bool getAdminOverride() const; void setAdminOverride(bool b); @@ -48,6 +71,7 @@ public: void setTransition(); // sets the transition bit, which defaults to false bool isInTransition() const; + bool canSetMaturity(S32 maturity); private: U8 mAccess; // SIM_ACCESS_MATURE etc @@ -61,9 +85,7 @@ private: // all of the code that depends on it. bool mAOTransition; - // we want this to be const but the getters for it aren't, so we're - // overriding it for now - /* const */ LLControlGroupReader& mSavedSettings; + LLControlGroup& mSavedSettings; }; #endif // LL_LLAGENTACCESS_H diff --git a/indra/newview/llagentlanguage.h b/indra/newview/llagentlanguage.h index 596c584232..45348a1e50 100644 --- a/indra/newview/llagentlanguage.h +++ b/indra/newview/llagentlanguage.h @@ -33,7 +33,7 @@ #ifndef LL_LLAGENTLANGUAGE_H #define LL_LLAGENTLANGUAGE_H -#include "llmemory.h" // LLSingleton<> +#include "llsingleton.h" // LLSingleton<> #include "llevent.h" class LLAgentLanguage: public LLSingleton, public LLOldEvents::LLSimpleListener diff --git a/indra/newview/llagentpilot.cpp b/indra/newview/llagentpilot.cpp index 035c9426a1..8ffb97d8fc 100644 --- a/indra/newview/llagentpilot.cpp +++ b/indra/newview/llagentpilot.cpp @@ -38,13 +38,13 @@ #include "llagentpilot.h" #include "llagent.h" -#include "llframestats.h" #include "llappviewer.h" #include "llviewercontrol.h" LLAgentPilot gAgentPilot; BOOL LLAgentPilot::sLoop = TRUE; +BOOL LLAgentPilot::sReplaySession = FALSE; LLAgentPilot::LLAgentPilot() : mNumRuns(-1), @@ -177,6 +177,11 @@ void LLAgentPilot::stopPlayback() mTimer.reset(); gAgent.stopAutoPilot(); } + + if (sReplaySession) + { + LLAppViewer::instance()->forceQuit(); + } } void LLAgentPilot::updateTarget() @@ -198,7 +203,6 @@ void LLAgentPilot::updateTarget() { llinfos << "At start, beginning playback" << llendl; mTimer.reset(); - LLFrameStats::startLogging(NULL); mStarted = TRUE; } } @@ -215,7 +219,6 @@ void LLAgentPilot::updateTarget() else { stopPlayback(); - LLFrameStats::stopLogging(NULL); mNumRuns--; if (sLoop) { diff --git a/indra/newview/llagentpilot.h b/indra/newview/llagentpilot.h index 0ad4772f68..dc034398a7 100644 --- a/indra/newview/llagentpilot.h +++ b/indra/newview/llagentpilot.h @@ -70,6 +70,7 @@ public: static void startPlayback(void *); static void stopPlayback(void *); static BOOL sLoop; + static BOOL sReplaySession; S32 mNumRuns; BOOL mQuitAfterRuns; diff --git a/indra/newview/llagentui.cpp b/indra/newview/llagentui.cpp new file mode 100644 index 0000000000..1a69f1d975 --- /dev/null +++ b/indra/newview/llagentui.cpp @@ -0,0 +1,179 @@ +/** + * @file llagentui.cpp + * @brief Utility methods to process agent's data as slurl's etc. before displaying + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagentui.h" + +// Library includes +#include "llparcel.h" + +// Viewer includes +#include "llagent.h" +#include "llviewercontrol.h" +#include "llviewerregion.h" +#include "llviewerparcelmgr.h" +#include "llvoavatarself.h" +#include "llslurl.h" + +//static +void LLAgentUI::buildName(std::string& name) +{ + name.clear(); + + LLVOAvatarSelf* avatar_object = gAgent.getAvatarObject(); + if (avatar_object) + { + LLNameValue *first_nv = avatar_object->getNVPair("FirstName"); + LLNameValue *last_nv = avatar_object->getNVPair("LastName"); + if (first_nv && last_nv) + { + name = first_nv->printData() + " " + last_nv->printData(); + } + else + { + llwarns << "Agent is missing FirstName and/or LastName nv pair." << llendl; + } + } + else + { + name = gSavedSettings.getString("FirstName") + " " + gSavedSettings.getString("LastName"); + } +} + +//static +void LLAgentUI::buildFullname(std::string& name) +{ + if (gAgent.getAvatarObject()) name = gAgent.getAvatarObject()->getFullname(); +} + +//static +std::string LLAgentUI::buildSLURL(const bool escaped /*= true*/) +{ + std::string slurl; + LLViewerRegion *regionp = gAgent.getRegion(); + if (regionp) + { + LLVector3d agentPos = gAgent.getPositionGlobal(); + slurl = LLSLURL::buildSLURLfromPosGlobal(regionp->getName(), agentPos, escaped); + } + return slurl; +} + +BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region) +{ + LLViewerRegion* region = gAgent.getRegion(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + + if (!region || !parcel) return FALSE; + + S32 pos_x = S32(agent_pos_region.mV[VX]); + S32 pos_y = S32(agent_pos_region.mV[VY]); + S32 pos_z = S32(agent_pos_region.mV[VZ]); + + // Round the numbers based on the velocity + F32 velocity_mag_sq = gAgent.getVelocity().magVecSquared(); + + const F32 FLY_CUTOFF = 6.f; // meters/sec + const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF; + const F32 WALK_CUTOFF = 1.5f; // meters/sec + const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF; + + if (velocity_mag_sq > FLY_CUTOFF_SQ) + { + pos_x -= pos_x % 4; + pos_y -= pos_y % 4; + } + else if (velocity_mag_sq > WALK_CUTOFF_SQ) + { + pos_x -= pos_x % 2; + pos_y -= pos_y % 2; + } + + // create a default name and description for the landmark + std::string parcel_name = LLViewerParcelMgr::getInstance()->getAgentParcelName(); + std::string region_name = region->getName(); + std::string buffer; + if( parcel_name.empty() ) + { + // the parcel doesn't have a name + switch (fmt) + { + case LOCATION_FORMAT_LANDMARK: + buffer = llformat("%.100s", region_name.c_str()); + break; + case LOCATION_FORMAT_NORMAL: + buffer = llformat("%s", region_name.c_str()); + break; + case LOCATION_FORMAT_WITHOUT_SIM: + case LOCATION_FORMAT_FULL: + buffer = llformat("%s (%d, %d, %d)", + region_name.c_str(), + pos_x, pos_y, pos_z); + break; + } + } + else + { + // the parcel has a name, so include it in the landmark name + switch (fmt) + { + case LOCATION_FORMAT_LANDMARK: + buffer = llformat("%.100s", parcel_name.c_str()); + break; + case LOCATION_FORMAT_NORMAL: + buffer = llformat("%s, %s", region_name.c_str(), parcel_name.c_str()); + break; + case LOCATION_FORMAT_WITHOUT_SIM: + buffer = llformat("%s, %s (%d, %d, %d)", + region_name.c_str(), + parcel_name.c_str(), + pos_x, pos_y, pos_z); + break; + case LOCATION_FORMAT_FULL: + std::string sim_access_string = region->getSimAccessString(); + buffer = llformat("%s, %s (%d, %d, %d)%s%s", + region_name.c_str(), + parcel_name.c_str(), + pos_x, pos_y, pos_z, + sim_access_string.empty() ? "" : " - ", + sim_access_string.c_str()); + break; + } + } + str = buffer; + return TRUE; +} +BOOL LLAgentUI::buildLocationString(std::string& str, ELocationFormat fmt) +{ + return buildLocationString(str,fmt, gAgent.getPositionAgent()); +} diff --git a/indra/newview/llagentui.h b/indra/newview/llagentui.h new file mode 100644 index 0000000000..47ecb04547 --- /dev/null +++ b/indra/newview/llagentui.h @@ -0,0 +1,57 @@ +/** + * @file llagentui.h + * @brief Utility methods to process agent's data as slurl's etc. before displaying + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLAGENTUI_H +#define LLAGENTUI_H + +class LLAgentUI +{ +public: + enum ELocationFormat + { + LOCATION_FORMAT_NORMAL, + LOCATION_FORMAT_LANDMARK, + LOCATION_FORMAT_WITHOUT_SIM, + LOCATION_FORMAT_FULL, + }; + + static void buildName(std::string& name); + static void buildFullname(std::string &name); + + static std::string buildSLURL(const bool escaped = true); + //build location string using the current position of gAgent. + static BOOL buildLocationString(std::string& str, ELocationFormat fmt = LOCATION_FORMAT_LANDMARK); + //build location string using a region position of the avatar. + static BOOL buildLocationString(std::string& str, ELocationFormat fmt,const LLVector3& agent_pos_region); +}; + +#endif //LLAGENTUI_H diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp new file mode 100644 index 0000000000..0f735282cb --- /dev/null +++ b/indra/newview/llagentwearables.cpp @@ -0,0 +1,1910 @@ +/** + * @file llagentwearables.cpp + * @brief LLAgentWearables class implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llagentwearables.h" + +#include "llfloatercustomize.h" +#include "llfloaterinventory.h" +#include "llinventorybridge.h" +#include "llinventorymodel.h" +#include "llnotify.h" +#include "llviewerregion.h" +#include "llvoavatarself.h" +#include "llwearable.h" +#include "llwearablelist.h" +#include "llgesturemgr.h" + +#include + +#define USE_CURRENT_OUTFIT_FOLDER + +//-------------------------------------------------------------------- +// Classes for fetching initial wearables data +//-------------------------------------------------------------------- +// Outfit folder fetching callback structure. +class LLInitialWearablesFetch : public LLInventoryFetchDescendentsObserver +{ +public: + LLInitialWearablesFetch() {} + ~LLInitialWearablesFetch() {} + virtual void done(); + + struct InitialWearableData + { + EWearableType mType; + U32 mIndex; + LLUUID mItemID; + LLUUID mAssetID; + InitialWearableData(EWearableType type, U32 index, LLUUID itemID, LLUUID assetID) : + mType(type), mIndex(index), mItemID(itemID), mAssetID(assetID) { } + }; + + typedef std::vector initial_wearable_data_vec_t; + initial_wearable_data_vec_t mCOFInitialWearables; // Wearables from the Current Outfit Folder + initial_wearable_data_vec_t mAgentInitialWearables; // Wearables from the old agent wearables msg + +protected: + void processInitialWearables(); +}; + + + +LLAgentWearables gAgentWearables; + +BOOL LLAgentWearables::mInitialWearablesUpdateReceived = FALSE; + +using namespace LLVOAvatarDefines; + +void LLAgentWearables::dump() +{ + llinfos << "LLAgentWearablesDump" << llendl; + for (S32 i = 0; i < WT_COUNT; i++) + { + U32 count = getWearableCount((EWearableType)i); + llinfos << "Type: " << i << " count " << count << llendl; + for (U32 j=0; jgetName() + << " description " << wearable->getDescription() << llendl; + + } + } + llinfos << "Total items awaiting wearable update " << mItemsAwaitingWearableUpdate.size() << llendl; + for (std::set::iterator it = mItemsAwaitingWearableUpdate.begin(); + it != mItemsAwaitingWearableUpdate.end(); + ++it) + { + llinfos << (*it).asString() << llendl; + } +} + +// MULTI-WEARABLE: debugging +struct LLAgentDumper +{ + LLAgentDumper(std::string name): + mName(name) + { + llinfos << llendl; + llinfos << "LLAgentDumper " << mName << llendl; + gAgentWearables.dump(); + } + + ~LLAgentDumper() + { + llinfos << llendl; + llinfos << "~LLAgentDumper " << mName << llendl; + gAgentWearables.dump(); + } + + std::string mName; +}; + +LLAgentWearables::LLAgentWearables() : + mWearablesLoaded(FALSE), + mAvatarObject(NULL) +{ + // MULTI-WEARABLE: TODO remove null entries. + for (U32 i = 0; i < WT_COUNT; i++) + { + mWearableDatas[(EWearableType)i].push_back(NULL); + } +} + +LLAgentWearables::~LLAgentWearables() +{ + cleanup(); +} + +void LLAgentWearables::cleanup() +{ + mAvatarObject = NULL; +} + +void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar) +{ + mAvatarObject = avatar; + if (avatar) + { + sendAgentWearablesRequest(); + } +} + +// wearables +LLAgentWearables::createStandardWearablesAllDoneCallback::~createStandardWearablesAllDoneCallback() +{ + gAgentWearables.createStandardWearablesAllDone(); +} + +LLAgentWearables::sendAgentWearablesUpdateCallback::~sendAgentWearablesUpdateCallback() +{ + gAgentWearables.sendAgentWearablesUpdate(); +} + +/** + * @brief Construct a callback for dealing with the wearables. + * + * Would like to pass the agent in here, but we can't safely + * count on it being around later. Just use gAgent directly. + * @param cb callback to execute on completion (??? unused ???) + * @param type Type for the wearable in the agent + * @param wearable The wearable data. + * @param todo Bitmask of actions to take on completion. + */ +LLAgentWearables::addWearableToAgentInventoryCallback::addWearableToAgentInventoryCallback( + LLPointer cb, S32 type, U32 index, LLWearable* wearable, U32 todo) : + mType(type), + mIndex(index), + mWearable(wearable), + mTodo(todo), + mCB(cb) +{ +} + +void LLAgentWearables::addWearableToAgentInventoryCallback::fire(const LLUUID& inv_item) +{ + if (inv_item.isNull()) + return; + + gAgentWearables.addWearabletoAgentInventoryDone(mType, mIndex, inv_item, mWearable); + + if (mTodo & CALL_UPDATE) + { + gAgentWearables.sendAgentWearablesUpdate(); + } + if (mTodo & CALL_RECOVERDONE) + { + gAgentWearables.recoverMissingWearableDone(); + } + /* + * Do this for every one in the loop + */ + if (mTodo & CALL_CREATESTANDARDDONE) + { + gAgentWearables.createStandardWearablesDone(mType, mIndex); + } + if (mTodo & CALL_MAKENEWOUTFITDONE) + { + gAgentWearables.makeNewOutfitDone(mType, mIndex); + } +} + +void LLAgentWearables::addWearabletoAgentInventoryDone(const S32 type, + const U32 index, + const LLUUID& item_id, + LLWearable* wearable) +{ + if (item_id.isNull()) + return; + + LLUUID old_item_id = getWearableItemID((EWearableType)type,index); + if (wearable) + { + wearable->setItemID(item_id); + } + setWearable((EWearableType)type,index,wearable); + + if (old_item_id.notNull()) + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if (item && wearable) + { + // We're changing the asset id, so we both need to set it + // locally via setAssetUUID() and via setTransactionID() which + // will be decoded on the server. JC + item->setAssetUUID(wearable->getAssetID()); + item->setTransactionID(wearable->getTransactionID()); + gInventory.addChangedMask(LLInventoryObserver::INTERNAL, item_id); + item->updateServer(FALSE); + } + gInventory.notifyObservers(); +} + +void LLAgentWearables::sendAgentWearablesUpdate() +{ + // MULTI-WEARABLE: call i "type" or something. + // First make sure that we have inventory items for each wearable + for (S32 i=0; i < WT_COUNT; ++i) + { + for (U32 j=0; j < getWearableCount((EWearableType)i); j++) + { + LLWearable* wearable = getWearable((EWearableType)i,j); + if (wearable) + { + if (wearable->getItemID().isNull()) + { + LLPointer cb = + new addWearableToAgentInventoryCallback( + LLPointer(NULL), + i, + j, + wearable, + addWearableToAgentInventoryCallback::CALL_NONE); + addWearableToAgentInventory(cb, wearable); + } + else + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, + wearable->getItemID()); + } + } + } + } + + // Then make sure the inventory is in sync with the avatar. + gInventory.notifyObservers(); + + // Send the AgentIsNowWearing + gMessageSystem->newMessageFast(_PREHASH_AgentIsNowWearing); + + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + lldebugs << "sendAgentWearablesUpdate()" << llendl; + // MULTI-WEARABLE: update for multi-wearables after server-side support is in. + for (S32 i=0; i < WT_COUNT; ++i) + { + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + + U8 type_u8 = (U8)i; + gMessageSystem->addU8Fast(_PREHASH_WearableType, type_u8); + + // MULTI-WEARABLE: TODO: hacked index to 0, needs to loop over all once messages support this. + LLWearable* wearable = getWearable((EWearableType)i, 0); + if (wearable) + { + //llinfos << "Sending wearable " << wearable->getName() << llendl; + gMessageSystem->addUUIDFast(_PREHASH_ItemID, wearable->getItemID()); + } + else + { + //llinfos << "Not wearing wearable type " << LLWearableDictionary::getInstance()->getWearable((EWearableType)i) << llendl; + gMessageSystem->addUUIDFast(_PREHASH_ItemID, LLUUID::null); + } + + lldebugs << " " << LLWearableDictionary::getTypeLabel((EWearableType)i) << ": " << (wearable ? wearable->getAssetID() : LLUUID::null) << llendl; + } + gAgent.sendReliableMessage(); +} + +// MULTI-WEARABLE: add index. +void LLAgentWearables::saveWearable(const EWearableType type, const U32 index, BOOL send_update) +{ + LLWearable* old_wearable = getWearable(type, index); + if (old_wearable && (old_wearable->isDirty() || old_wearable->isOldVersion())) + { + LLUUID old_item_id = old_wearable->getItemID(); + LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar(old_wearable); + new_wearable->setItemID(old_item_id); // should this be in LLWearable::copyDataFrom()? + setWearable(type,index,new_wearable); + + LLInventoryItem* item = gInventory.getItem(old_item_id); + if (item) + { + // Update existing inventory item + LLPointer template_item = + new LLViewerInventoryItem(item->getUUID(), + item->getParentUUID(), + item->getPermissions(), + new_wearable->getAssetID(), + new_wearable->getAssetType(), + item->getInventoryType(), + item->getName(), + item->getDescription(), + item->getSaleInfo(), + item->getFlags(), + item->getCreationDate()); + template_item->setTransactionID(new_wearable->getTransactionID()); + template_item->updateServer(FALSE); + gInventory.updateItem(template_item); + } + else + { + // Add a new inventory item (shouldn't ever happen here) + U32 todo = addWearableToAgentInventoryCallback::CALL_NONE; + if (send_update) + { + todo |= addWearableToAgentInventoryCallback::CALL_UPDATE; + } + LLPointer cb = + new addWearableToAgentInventoryCallback( + LLPointer(NULL), + (S32)type, + index, + new_wearable, + todo); + addWearableToAgentInventory(cb, new_wearable); + return; + } + + gAgent.getAvatarObject()->wearableUpdated( type ); + + if (send_update) + { + sendAgentWearablesUpdate(); + } + } +} + +// MULTI-WEARABLE: add index +void LLAgentWearables::saveWearableAs(const EWearableType type, + const U32 index, + const std::string& new_name, + BOOL save_in_lost_and_found) +{ + if (!isWearableCopyable(type, index)) + { + llwarns << "LLAgent::saveWearableAs() not copyable." << llendl; + return; + } + LLWearable* old_wearable = getWearable(type, index); + if (!old_wearable) + { + llwarns << "LLAgent::saveWearableAs() no old wearable." << llendl; + return; + } + + LLInventoryItem* item = gInventory.getItem(getWearableItemID(type,index)); + if (!item) + { + llwarns << "LLAgent::saveWearableAs() no inventory item." << llendl; + return; + } + std::string trunc_name(new_name); + LLStringUtil::truncate(trunc_name, DB_INV_ITEM_NAME_STR_LEN); + LLWearable* new_wearable = LLWearableList::instance().createCopyFromAvatar( + old_wearable, + trunc_name); + LLPointer cb = + new addWearableToAgentInventoryCallback( + LLPointer(NULL), + type, + index, + new_wearable, + addWearableToAgentInventoryCallback::CALL_UPDATE); + LLUUID category_id; + if (save_in_lost_and_found) + { + category_id = gInventory.findCategoryUUIDForType( + LLAssetType::AT_LOST_AND_FOUND); + } + else + { + // put in same folder as original + category_id = item->getParentUUID(); + } + + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + category_id, + new_name, + cb); +} + +void LLAgentWearables::revertWearable(const EWearableType type, const U32 index) +{ + LLWearable* wearable = getWearable(type, index); + if (wearable) + { + wearable->writeToAvatar(TRUE); + } + gAgent.sendAgentSetAppearance(); +} + +void LLAgentWearables::saveAllWearables() +{ + //if (!gInventory.isLoaded()) + //{ + // return; + //} + + for (S32 i=0; i < WT_COUNT; i++) + { + for (U32 j=0; j < getWearableCount((EWearableType)i); j++) + saveWearable((EWearableType)i, j, FALSE); + } + sendAgentWearablesUpdate(); +} + +// Called when the user changes the name of a wearable inventory item that is currently being worn. +void LLAgentWearables::setWearableName(const LLUUID& item_id, const std::string& new_name) +{ + for (S32 i=0; i < WT_COUNT; i++) + { + for (U32 j=0; j < getWearableCount((EWearableType)i); j++) + { + LLUUID curr_item_id = getWearableItemID((EWearableType)i,j); + if (curr_item_id == item_id) + { + LLWearable* old_wearable = getWearable((EWearableType)i,j); + llassert(old_wearable); + + std::string old_name = old_wearable->getName(); + old_wearable->setName(new_name); + LLWearable* new_wearable = LLWearableList::instance().createCopy(old_wearable); + new_wearable->setItemID(item_id); + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + new_wearable->setPermissions(item->getPermissions()); + } + old_wearable->setName(old_name); + + setWearable((EWearableType)i,j,new_wearable); + sendAgentWearablesUpdate(); + break; + } + } + } +} + + +BOOL LLAgentWearables::isWearableModifiable(EWearableType type, U32 index) const +{ + LLUUID item_id = getWearableItemID(type, index); + if (!item_id.isNull()) + { + LLInventoryItem* item = gInventory.getItem(item_id); + if (item && item->getPermissions().allowModifyBy(gAgent.getID(), + gAgent.getGroupID())) + { + return TRUE; + } + } + return FALSE; +} + +BOOL LLAgentWearables::isWearableCopyable(EWearableType type, U32 index) const +{ + LLUUID item_id = getWearableItemID(type, index); + if (!item_id.isNull()) + { + LLInventoryItem* item = gInventory.getItem(item_id); + if (item && item->getPermissions().allowCopyBy(gAgent.getID(), + gAgent.getGroupID())) + { + return TRUE; + } + } + return FALSE; +} + +/* + U32 LLAgentWearables::getWearablePermMask(EWearableType type) + { + LLUUID item_id = getWearableItemID(type); + if (!item_id.isNull()) + { + LLInventoryItem* item = gInventory.getItem(item_id); + if (item) + { + return item->getPermissions().getMaskOwner(); + } + } + return PERM_NONE; + } +*/ + +LLInventoryItem* LLAgentWearables::getWearableInventoryItem(EWearableType type, U32 index) +{ + LLUUID item_id = getWearableItemID(type,index); + LLInventoryItem* item = NULL; + if (item_id.notNull()) + { + item = gInventory.getItem(item_id); + } + return item; +} + +const LLWearable* LLAgentWearables::getWearableFromWearableItem(const LLUUID& item_id) const +{ + for (S32 i=0; i < WT_COUNT; i++) + { + for (U32 j=0; j < getWearableCount((EWearableType)i); j++) + { + LLUUID curr_item_id = getWearableItemID((EWearableType)i, j); + if (curr_item_id == item_id) + { + return getWearable((EWearableType)i, j); + } + } + } + return NULL; +} + +void LLAgentWearables::sendAgentWearablesRequest() +{ + gMessageSystem->newMessageFast(_PREHASH_AgentWearablesRequest); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); +} + +// MULTI-WEARABLE: update for multiple items per type. +// Used to enable/disable menu items. +// static +BOOL LLAgentWearables::selfHasWearable(EWearableType type) +{ + // MULTI-WEARABLE: TODO could be getWearableCount > 0, once null entries have been eliminated. + return gAgentWearables.getWearable(type,0) != NULL; +} + +LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) +{ + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +void LLAgentWearables::setWearable(const EWearableType type, U32 index, LLWearable *wearable) +{ + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + llwarns << "invalid type, type " << type << " index " << index << llendl; + return; + } + wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + llwarns << "invalid index, type " << type << " index " << index << llendl; + } + else + { + wearable_vec[index] = wearable; + } +} + +const LLWearable* LLAgentWearables::getWearable(const EWearableType type, U32 index) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return NULL; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + if (index>=wearable_vec.size()) + { + return NULL; + } + else + { + return wearable_vec[index]; + } +} + +//MULTI-WEARABLE: this will give wrong values until we get rid of the "always one empty object" scheme. +U32 LLAgentWearables::getWearableCount(const EWearableType type) const +{ + wearableentry_map_t::const_iterator wearable_iter = mWearableDatas.find(type); + if (wearable_iter == mWearableDatas.end()) + { + return 0; + } + const wearableentry_vec_t& wearable_vec = wearable_iter->second; + return wearable_vec.size(); +} + +BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const +{ + return mItemsAwaitingWearableUpdate.find(item_id) != mItemsAwaitingWearableUpdate.end(); +} + +U32 LLAgentWearables::itemUpdatePendingCount() const +{ + return mItemsAwaitingWearableUpdate.size(); +} + +const LLUUID LLAgentWearables::getWearableItemID(EWearableType type, U32 index) const +{ + const LLWearable *wearable = getWearable(type,index); + if (wearable) + return wearable->getItemID(); + else + return LLUUID(); +} + +// Warning: include_linked_items = TRUE makes this operation expensive. +BOOL LLAgentWearables::isWearingItem(const LLUUID& item_id, BOOL include_linked_items) const +{ + if (getWearableFromWearableItem(item_id) != NULL) return TRUE; + if (include_linked_items) + { + LLInventoryModel::item_array_t item_array; + gInventory.collectLinkedItems(item_id, item_array); + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + if (getWearableFromWearableItem(item_id) != NULL) return TRUE; + } + } + return FALSE; +} + +// MULTI-WEARABLE: update for multiple +// static +// ! BACKWARDS COMPATIBILITY ! When we stop supporting viewer1.23, we can assume +// that viewers have a Current Outfit Folder and won't need this message, and thus +// we can remove/ignore this whole function. +void LLAgentWearables::processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data) +{ + // We should only receive this message a single time. Ignore subsequent AgentWearablesUpdates + // that may result from AgentWearablesRequest having been sent more than once. + if (mInitialWearablesUpdateReceived) + return; + mInitialWearablesUpdateReceived = true; + + LLUUID agent_id; + gMessageSystem->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); + + LLVOAvatar* avatar = gAgent.getAvatarObject(); + if (avatar && (agent_id == avatar->getID())) + { + gMessageSystem->getU32Fast(_PREHASH_AgentData, _PREHASH_SerialNum, gAgentQueryManager.mUpdateSerialNum); + + S32 num_wearables = gMessageSystem->getNumberOfBlocksFast(_PREHASH_WearableData); + if (num_wearables < 4) + { + // Transitional state. Avatars should always have at least their body parts (hair, eyes, shape and skin). + // The fact that they don't have any here (only a dummy is sent) implies that this account existed + // before we had wearables, or that the database has gotten messed up. + return; + } + + // Get the UUID of the current outfit folder (will be created if it doesn't exist) + LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + + LLInitialWearablesFetch* outfit = new LLInitialWearablesFetch(); + + //lldebugs << "processAgentInitialWearablesUpdate()" << llendl; + // Add wearables + // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element. + gAgentWearables.mItemsAwaitingWearableUpdate.clear(); + for (S32 i=0; i < num_wearables; i++) + { + // Parse initial werables data from message system + U8 type_u8 = 0; + gMessageSystem->getU8Fast(_PREHASH_WearableData, _PREHASH_WearableType, type_u8, i); + if (type_u8 >= WT_COUNT) + { + continue; + } + const EWearableType type = (EWearableType) type_u8; + + LLUUID item_id; + gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_ItemID, item_id, i); + + LLUUID asset_id; + gMessageSystem->getUUIDFast(_PREHASH_WearableData, _PREHASH_AssetID, asset_id, i); + if (asset_id.isNull()) + { + LLWearable::removeFromAvatar(type, FALSE); + } + else + { + LLAssetType::EType asset_type = LLWearableDictionary::getAssetType(type); + if (asset_type == LLAssetType::AT_NONE) + { + continue; + } + + // MULTI-WEARABLE: TODO: update once messages change. Currently use results to populate the zeroth element. + + // Store initial wearables data until we know whether we have the current outfit folder or need to use the data. + LLInitialWearablesFetch::InitialWearableData wearable_data(type, 0, item_id, asset_id); // MULTI-WEARABLE: update + outfit->mAgentInitialWearables.push_back(wearable_data); + + } + + lldebugs << " " << LLWearableDictionary::getTypeLabel(type) << llendl; + } + + // What we do here is get the complete information on the items in + // the inventory, and set up an observer that will wait for that to + // happen. + LLInventoryFetchDescendentsObserver::folder_ref_t folders; + folders.push_back(current_outfit_id); + outfit->fetchDescendents(folders); + if(outfit->isEverythingComplete()) + { + // everything is already here - call done. + outfit->done(); + } + else + { + // it's all on it's way - add an observer, and the inventory + // will call done for us when everything is here. + gInventory.addObserver(outfit); + } + } +} + +// A single wearable that the avatar was wearing on start-up has arrived from the database. +// static +void LLAgentWearables::onInitialWearableAssetArrived(LLWearable* wearable, void* userdata) +{ + boost::scoped_ptr wear_data((LLInitialWearablesFetch::InitialWearableData*)userdata); + const EWearableType type = wear_data->mType; + const U32 index = wear_data->mIndex; + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); + if (!avatar) + { + return; + } + + if (wearable) + { + llassert(type == wearable->getType()); + // MULTI-WEARABLE: is this always zeroth element? Change sometime. + wearable->setItemID(wear_data->mItemID); + gAgentWearables.setWearable(type, index, wearable); + gAgentWearables.mItemsAwaitingWearableUpdate.erase(wear_data->mItemID); + + // disable composites if initial textures are baked + avatar->setupComposites(); + + wearable->writeToAvatar(FALSE); + avatar->setCompositeUpdatesEnabled(TRUE); + gInventory.addChangedMask(LLInventoryObserver::LABEL, wearable->getItemID()); + } + else + { + // Somehow the asset doesn't exist in the database. + // MULTI-WEARABLE: assuming zeroth elt + gAgentWearables.recoverMissingWearable(type,index); + } + + gInventory.notifyObservers(); + + // Have all the wearables that the avatar was wearing at log-in arrived? + // MULTI-WEARABLE: update when multiple wearables can arrive per type. + + gAgentWearables.updateWearablesLoaded(); + if (gAgentWearables.areWearablesLoaded()) + { + + // Can't query cache until all wearables have arrived, so calling this earlier is a no-op. + gAgentWearables.queryWearableCache(); + + // Make sure that the server's idea of the avatar's wearables actually match the wearables. + gAgent.sendAgentSetAppearance(); + + // Check to see if there are any baked textures that we hadn't uploaded before we logged off last time. + // If there are any, schedule them to be uploaded as soon as the layer textures they depend on arrive. + if (gAgent.cameraCustomizeAvatar()) + { + avatar->requestLayerSetUploads(); + } + } +} + +// Normally, all wearables referred to "AgentWearablesUpdate" will correspond to actual assets in the +// database. If for some reason, we can't load one of those assets, we can try to reconstruct it so that +// the user isn't left without a shape, for example. (We can do that only after the inventory has loaded.) +void LLAgentWearables::recoverMissingWearable(const EWearableType type, U32 index) +{ + // Try to recover by replacing missing wearable with a new one. + LLNotifications::instance().add("ReplacedMissingWearable"); + lldebugs << "Wearable " << LLWearableDictionary::getTypeLabel(type) << " could not be downloaded. Replaced inventory item with default wearable." << llendl; + LLWearable* new_wearable = LLWearableList::instance().createNewWearable(type); + + S32 type_s32 = (S32) type; + setWearable(type,index,new_wearable); + new_wearable->writeToAvatar(TRUE); + + // Add a new one in the lost and found folder. + // (We used to overwrite the "not found" one, but that could potentially + // destory content.) JC + LLUUID lost_and_found_id = + gInventory.findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); + LLPointer cb = + new addWearableToAgentInventoryCallback( + LLPointer(NULL), + type_s32, + index, + new_wearable, + addWearableToAgentInventoryCallback::CALL_RECOVERDONE); + addWearableToAgentInventory(cb, new_wearable, lost_and_found_id, TRUE); +} + +void LLAgentWearables::recoverMissingWearableDone() +{ + // Have all the wearables that the avatar was wearing at log-in arrived or been fabricated? + updateWearablesLoaded(); + if (areWearablesLoaded()) + { + // Make sure that the server's idea of the avatar's wearables actually match the wearables. + gAgent.sendAgentSetAppearance(); + } + else + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, LLUUID::null); + gInventory.notifyObservers(); + } +} + +void LLAgentWearables::addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index) +{ + LLWearable* wearable = getWearable((EWearableType)wearable_type, wearable_index); + if (!wearable) + { + llerrs << "Tried to add local texture object to invalid wearable with type " << wearable_type << " and index " << wearable_index << llendl; + } + + wearable->setLocalTextureObject(texture_type, new LLLocalTextureObject()); +} + +void LLAgentWearables::createStandardWearables(BOOL female) +{ + llwarns << "Creating Standard " << (female ? "female" : "male") + << " Wearables" << llendl; + + if (mAvatarObject.isNull()) + { + return; + } + + mAvatarObject->setSex(female ? SEX_FEMALE : SEX_MALE); + + const BOOL create[WT_COUNT] = + { + TRUE, //WT_SHAPE + TRUE, //WT_SKIN + TRUE, //WT_HAIR + TRUE, //WT_EYES + TRUE, //WT_SHIRT + TRUE, //WT_PANTS + TRUE, //WT_SHOES + TRUE, //WT_SOCKS + FALSE, //WT_JACKET + FALSE, //WT_GLOVES + TRUE, //WT_UNDERSHIRT + TRUE, //WT_UNDERPANTS + FALSE //WT_SKIRT + }; + + for (S32 i=0; i < WT_COUNT; i++) + { + bool once = false; + LLPointer donecb = NULL; + if (create[i]) + { + if (!once) + { + once = true; + donecb = new createStandardWearablesAllDoneCallback; + } + // MULTI_WEARABLE: only elt 0, may be the right thing? + llassert(getWearable((EWearableType)i,0) == NULL); + LLWearable* wearable = LLWearableList::instance().createNewWearable((EWearableType)i); + setWearable((EWearableType)i,0,wearable); + // no need to update here... + // MULTI_WEARABLE: hardwired index = 0 here. + LLPointer cb = + new addWearableToAgentInventoryCallback( + donecb, + i, + 0, + wearable, + addWearableToAgentInventoryCallback::CALL_CREATESTANDARDDONE); + addWearableToAgentInventory(cb, wearable, LLUUID::null, FALSE); + } + } +} + +void LLAgentWearables::createStandardWearablesDone(S32 type, U32 index) +{ + LLWearable* wearable = getWearable((EWearableType)type, index); + + if (wearable) + { + wearable->writeToAvatar(TRUE); + } +} + +void LLAgentWearables::createStandardWearablesAllDone() +{ + // ... because sendAgentWearablesUpdate will notify inventory + // observers. + mWearablesLoaded = TRUE; + checkWearablesLoaded(); + + updateServer(); + + // Treat this as the first texture entry message, if none received yet + mAvatarObject->onFirstTEMessageReceived(); +} + +void LLAgentWearables::getAllWearablesArray(LLDynamicArray& wearables) +{ + for( S32 i = 0; i < WT_COUNT; ++i ) + { + // MULTI-WEARABLE: Properly handle multiwearables later. + if (getWearable( (EWearableType) i, 0 ) != NULL) + { + wearables.push_back(i); + } + } +} + +// Note: wearables_to_include should be a list of EWearableType types +// attachments_to_include should be a list of attachment points +void LLAgentWearables::makeNewOutfit(const std::string& new_folder_name, + const LLDynamicArray& wearables_to_include, + const LLDynamicArray& attachments_to_include, + BOOL rename_clothing) +{ + if (mAvatarObject.isNull()) + { + return; + } + + // First, make a folder in the Clothes directory. + LLUUID folder_id = gInventory.createNewCategory( + gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING), + LLAssetType::AT_NONE, + new_folder_name); + + bool found_first_item = false; + + /////////////////// + // Wearables + + if (wearables_to_include.count()) + { + // Then, iterate though each of the wearables and save copies of them in the folder. + S32 i; + S32 count = wearables_to_include.count(); + LLDynamicArray delete_items; + LLPointer cbdone = NULL; + for (i = 0; i < count; ++i) + { + const S32 type = wearables_to_include[i]; + for (U32 j=0; jgetTypeLabel()); + LLStringUtil::truncate(new_name, DB_INV_ITEM_NAME_STR_LEN); + new_wearable->setName(new_name); + } + + LLViewerInventoryItem* item = gInventory.getItem(getWearableItemID((EWearableType)type,j)); + S32 todo = addWearableToAgentInventoryCallback::CALL_NONE; + if (!found_first_item) + { + found_first_item = true; + /* set the focus to the first item */ + todo |= addWearableToAgentInventoryCallback::CALL_MAKENEWOUTFITDONE; + /* send the agent wearables update when done */ + cbdone = new sendAgentWearablesUpdateCallback; + } + LLPointer cb = + new addWearableToAgentInventoryCallback( + cbdone, + type, + j, + new_wearable, + todo); + if (isWearableCopyable((EWearableType)type, j)) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + folder_id, + new_name, + cb); + } + else + { + move_inventory_item( + gAgent.getID(), + gAgent.getSessionID(), + item->getUUID(), + folder_id, + new_name, + cb); + } + } + } + } + gInventory.notifyObservers(); + } + + + /////////////////// + // Attachments + + if (attachments_to_include.count()) + { + BOOL msg_started = FALSE; + LLMessageSystem* msg = gMessageSystem; + for (S32 i = 0; i < attachments_to_include.count(); i++) + { + S32 attachment_pt = attachments_to_include[i]; + LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL); + if (!attachment) continue; + LLViewerObject* attached_object = attachment->getObject(); + if (!attached_object) continue; + const LLUUID& item_id = attachment->getItemID(); + if (item_id.isNull()) continue; + LLInventoryItem* item = gInventory.getItem(item_id); + if (!item) continue; + if (!msg_started) + { + msg_started = TRUE; + msg->newMessage("CreateNewOutfitAttachments"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("HeaderData"); + msg->addUUID("NewFolderID", folder_id); + } + msg->nextBlock("ObjectData"); + msg->addUUID("OldItemID", item_id); + msg->addUUID("OldFolderID", item->getParentUUID()); + } + + if (msg_started) + { + gAgent.sendReliableMessage(); + } + + } +} + +LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name) +{ + if (mAvatarObject.isNull()) + { + return LLUUID::null; + } + + LLDynamicArray wearables_to_include; + getAllWearablesArray(wearables_to_include); + + LLDynamicArray attachments_to_include; + mAvatarObject->getAllAttachmentsArray(attachments_to_include); + + return makeNewOutfitLinks(new_folder_name, wearables_to_include, attachments_to_include); +} + +// Note: wearables_to_include should be a list of EWearableType types +// attachments_to_include should be a list of attachment points +LLUUID LLAgentWearables::makeNewOutfitLinks(const std::string& new_folder_name, + const LLDynamicArray& wearables_to_include, + const LLDynamicArray& attachments_to_include) +{ + if (mAvatarObject.isNull()) + { + return LLUUID::null; + } + + // First, make a folder in the Clothes directory. + LLUUID folder_id = gInventory.createNewCategory( + gInventory.findCategoryUUIDForType(LLAssetType::AT_MY_OUTFITS), + LLAssetType::AT_OUTFIT, + new_folder_name); + +// bool found_first_item = false; + + /////////////////// + // Wearables + + if (wearables_to_include.count()) + { + // Then, iterate though each of the wearables and save links to them in the folder. + S32 i; + S32 count = wearables_to_include.count(); + LLDynamicArray delete_items; + LLPointer cbdone = NULL; + for (i = 0; i < count; ++i) + { + const S32 type = wearables_to_include[i]; + for (U32 j=0; j cb = NULL; + link_inventory_item(gAgent.getID(), + item->getUUID(), + folder_id, + item->getName(), + LLAssetType::AT_LINK, + cb); + } + } + } + gInventory.notifyObservers(); + } + + + /////////////////// + // Attachments + + if (attachments_to_include.count()) + { + for (S32 i = 0; i < attachments_to_include.count(); i++) + { + S32 attachment_pt = attachments_to_include[i]; + LLViewerJointAttachment* attachment = get_if_there(mAvatarObject->mAttachmentPoints, attachment_pt, (LLViewerJointAttachment*)NULL); + if (!attachment) continue; + LLViewerObject* attached_object = attachment->getObject(); + if (!attached_object) continue; + const LLUUID& item_id = attachment->getItemID(); + if (item_id.isNull()) continue; + LLInventoryItem* item = gInventory.getItem(item_id); + if (!item) continue; + + LLPointer cb = NULL; + link_inventory_item(gAgent.getID(), + item->getUUID(), + folder_id, + item->getName(), + LLAssetType::AT_LINK, + cb); + } + } + + /////////////////// + // Gestures + + /* Disabling this for now, otherwise this adds all your default gestures and all previous + active gestures. Need to rethink the intended behavior. + for (LLGestureManager::item_map_t::iterator iter = LLGestureManager::instance().mActive.begin(); + iter != LLGestureManager::instance().mActive.end(); + ++iter) + { + const LLUUID &gesture_id = (*iter).first; + LLViewerInventoryItem* item = gInventory.getItem(gesture_id); + if (item) + { + LLPointer cb = NULL; + link_inventory_item(gAgent.getID(), + item->getUUID(), + folder_id, + item->getName(), + LLAssetType::AT_LINK, + cb); + } + } + */ + + return folder_id; +} + +void LLAgentWearables::makeNewOutfitDone(S32 type, U32 index) +{ + LLUUID first_item_id = getWearableItemID((EWearableType)type, index); + // Open the inventory and select the first item we added. + if (first_item_id.notNull()) + { + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); + if (view) + { + view->getPanel()->setSelection(first_item_id, TAKE_FOCUS_NO); + } + } +} + + +void LLAgentWearables::addWearableToAgentInventory(LLPointer cb, + LLWearable* wearable, + const LLUUID& category_id, + BOOL notify) +{ + create_inventory_item(gAgent.getID(), + gAgent.getSessionID(), + category_id, + wearable->getTransactionID(), + wearable->getName(), + wearable->getDescription(), + wearable->getAssetType(), + LLInventoryType::IT_WEARABLE, + wearable->getType(), + wearable->getPermissions().getMaskNextOwner(), + cb); +} + +void LLAgentWearables::removeWearable(const EWearableType type, bool do_remove_all, U32 index) +{ + + if (do_remove_all) + { + removeWearableFinal(type, do_remove_all, index); + } + else + { +// MULTI_WEARABLE: handle vector changes from arbitrary removal. + LLWearable* old_wearable = getWearable(type,index); + + if ((gAgent.isTeen()) + && (type == WT_UNDERSHIRT || type == WT_UNDERPANTS)) + { + // Can't take off underclothing in simple UI mode or on PG accounts + return; + } + + if (old_wearable) + { + if (old_wearable->isDirty()) + { + LLSD payload; + payload["wearable_type"] = (S32)type; + // Bring up view-modal dialog: Save changes? Yes, No, Cancel + LLNotifications::instance().add("WearableSave", LLSD(), payload, &LLAgentWearables::onRemoveWearableDialog); + return; + } + else + { + removeWearableFinal(type, do_remove_all, index); + } + } + } +} + + +// MULTI_WEARABLE: assuming one wearable per type. +// MULTI_WEARABLE: hardwiring 0th elt for now - notification needs to change. +// static +bool LLAgentWearables::onRemoveWearableDialog(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + EWearableType type = (EWearableType)notification["payload"]["wearable_type"].asInteger(); + switch(option) + { + case 0: // "Save" + gAgentWearables.saveWearable(type, 0); + gAgentWearables.removeWearableFinal(type, false, 0); + break; + + case 1: // "Don't Save" + gAgentWearables.removeWearableFinal(type, false, 0); + break; + + case 2: // "Cancel" + break; + + default: + llassert(0); + break; + } + return false; +} + +// Called by removeWearable() and onRemoveWearableDialog() to actually do the removal. +void LLAgentWearables::removeWearableFinal(const EWearableType type, bool do_remove_all, U32 index) +{ + //LLAgentDumper dumper("removeWearable"); + if (do_remove_all) + { + S32 max_entry = mWearableDatas[type].size()-1; + for (S32 i=max_entry; i>=0; i--) + { + LLWearable* old_wearable = getWearable(type,i); + gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,i)); + setWearable(type,i,NULL); + + //queryWearableCache(); // moved below + // MULTI_WEARABLE: FIXME - currently we keep a null entry, so can't delete the last one. + if (i>0) + { + mWearableDatas[type].pop_back(); + } + if (old_wearable) + { + old_wearable->removeFromAvatar(TRUE); + } + } + } + else + { + LLWearable* old_wearable = getWearable(type, index); + + gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID(type,index)); + setWearable(type,index,NULL); + + //queryWearableCache(); // moved below + + if (old_wearable) + { + old_wearable->removeFromAvatar(TRUE); + } + + // MULTI_WEARABLE: logic changes if null entries go away + if (getWearableCount(type)>1) + { + // Have to shrink the vector and clean up the item. + wearableentry_map_t::iterator wearable_iter = mWearableDatas.find(type); + llassert_always(wearable_iter != mWearableDatas.end()); + wearableentry_vec_t& wearable_vec = wearable_iter->second; + wearable_vec.erase( wearable_vec.begin() + index ); + } + } + + queryWearableCache(); + + // Update the server + updateServer(); + gInventory.notifyObservers(); +} + +// Assumes existing wearables are not dirty. +// MULTI_WEARABLE: assumes one wearable per type. +void LLAgentWearables::setWearableOutfit(const LLInventoryItem::item_array_t& items, + const LLDynamicArray< LLWearable* >& wearables, + BOOL remove) +{ + lldebugs << "setWearableOutfit() start" << llendl; + + BOOL wearables_to_remove[WT_COUNT]; + wearables_to_remove[WT_SHAPE] = FALSE; + wearables_to_remove[WT_SKIN] = FALSE; + wearables_to_remove[WT_HAIR] = FALSE; + wearables_to_remove[WT_EYES] = FALSE; + wearables_to_remove[WT_SHIRT] = remove; + wearables_to_remove[WT_PANTS] = remove; + wearables_to_remove[WT_SHOES] = remove; + wearables_to_remove[WT_SOCKS] = remove; + wearables_to_remove[WT_JACKET] = remove; + wearables_to_remove[WT_GLOVES] = remove; + wearables_to_remove[WT_UNDERSHIRT] = (!gAgent.isTeen()) & remove; + wearables_to_remove[WT_UNDERPANTS] = (!gAgent.isTeen()) & remove; + wearables_to_remove[WT_SKIRT] = remove; + + S32 count = wearables.count(); + llassert(items.count() == count); + + S32 i; + for (i = 0; i < count; i++) + { + LLWearable* new_wearable = wearables[i]; + LLPointer new_item = items[i]; + + const EWearableType type = new_wearable->getType(); + wearables_to_remove[type] = FALSE; + + // MULTI_WEARABLE: using 0th + LLWearable* old_wearable = getWearable(type, 0); + if (old_wearable) + { + const LLUUID& old_item_id = getWearableItemID(type, 0); + if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && + (old_item_id == new_item->getUUID())) + { + lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl; + continue; + } + + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + + // Assumes existing wearables are not dirty. + if (old_wearable->isDirty()) + { + llassert(0); + continue; + } + } + + setWearable(type,0,new_wearable); + if (new_wearable) + new_wearable->setItemID(new_item->getUUID()); + } + + std::vector wearables_being_removed; + + for (i = 0; i < WT_COUNT; i++) + { + if (wearables_to_remove[i]) + { + // MULTI_WEARABLE: assuming 0th + LLWearable* wearable = getWearable((EWearableType)i, 0); + gInventory.addChangedMask(LLInventoryObserver::LABEL, getWearableItemID((EWearableType)i,0)); + if (wearable) + { + wearables_being_removed.push_back(wearable); + } + setWearable((EWearableType)i,0,NULL); + } + } + + gInventory.notifyObservers(); + + queryWearableCache(); + + std::vector::iterator wearable_iter; + + for (wearable_iter = wearables_being_removed.begin(); + wearable_iter != wearables_being_removed.end(); + ++wearable_iter) + { + LLWearable* wearablep = *wearable_iter; + if (wearablep) + { + wearablep->removeFromAvatar(TRUE); + } + } + + for (i = 0; i < count; i++) + { + wearables[i]->writeToAvatar(TRUE); + } + + // Start rendering & update the server + mWearablesLoaded = TRUE; + checkWearablesLoaded(); + updateServer(); + + lldebugs << "setWearableOutfit() end" << llendl; +} + + +// User has picked "wear on avatar" from a menu. +void LLAgentWearables::setWearableItem(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append) +{ + //LLAgentDumper dumper("setWearableItem"); + if (isWearingItem(new_item->getUUID())) + { + llwarns << "wearable " << new_item->getUUID() << " is already worn" << llendl; + return; + } + + const EWearableType type = new_wearable->getType(); + + if (!do_append) + { + // Remove old wearable, if any + // MULTI_WEARABLE: hardwired to 0 + LLWearable* old_wearable = getWearable(type,0); + if (old_wearable) + { + const LLUUID& old_item_id = old_wearable->getItemID(); + if ((old_wearable->getAssetID() == new_wearable->getAssetID()) && + (old_item_id == new_item->getUUID())) + { + lldebugs << "No change to wearable asset and item: " << LLWearableDictionary::getInstance()->getWearableEntry(type) << llendl; + return; + } + + if (old_wearable->isDirty()) + { + // Bring up modal dialog: Save changes? Yes, No, Cancel + LLSD payload; + payload["item_id"] = new_item->getUUID(); + LLNotifications::instance().add("WearableSave", LLSD(), payload, boost::bind(onSetWearableDialog, _1, _2, new_wearable)); + return; + } + } + } + + setWearableFinal(new_item, new_wearable, do_append); +} + +// static +bool LLAgentWearables::onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLInventoryItem* new_item = gInventory.getItem(notification["payload"]["item_id"].asUUID()); + if (!new_item) + { + delete wearable; + return false; + } + + switch(option) + { + case 0: // "Save" +// MULTI_WEARABLE: assuming 0th + gAgentWearables.saveWearable(wearable->getType(),0); + gAgentWearables.setWearableFinal(new_item, wearable); + break; + + case 1: // "Don't Save" + gAgentWearables.setWearableFinal(new_item, wearable); + break; + + case 2: // "Cancel" + break; + + default: + llassert(0); + break; + } + + delete wearable; + return false; +} + +// Called from setWearableItem() and onSetWearableDialog() to actually set the wearable. +// MULTI_WEARABLE: unify code after null objects are gone. +void LLAgentWearables::setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append) +{ + const EWearableType type = new_wearable->getType(); + + if (do_append && getWearableItemID(type,0).notNull()) + { + new_wearable->setItemID(new_item->getUUID()); + mWearableDatas[type].push_back(new_wearable); + llinfos << "Added additional wearable for type " << type + << " size is now " << mWearableDatas[type].size() << llendl; + } + else + { + // Replace the old wearable with a new one. + llassert(new_item->getAssetUUID() == new_wearable->getAssetID()); + + LLWearable *old_wearable = getWearable(type,0); + LLUUID old_item_id; + if (old_wearable) + { + old_item_id = old_wearable->getItemID(); + } + new_wearable->setItemID(new_item->getUUID()); + setWearable(type,0,new_wearable); + + if (old_item_id.notNull()) + { + gInventory.addChangedMask(LLInventoryObserver::LABEL, old_item_id); + gInventory.notifyObservers(); + } + llinfos << "Replaced current element 0 for type " << type + << " size is now " << mWearableDatas[type].size() << llendl; + } + + //llinfos << "LLVOAvatar::setWearableItem()" << llendl; + queryWearableCache(); + new_wearable->writeToAvatar(TRUE); + + updateServer(); +} + +void LLAgentWearables::queryWearableCache() +{ + if (!areWearablesLoaded()) + { + return; + } + + // Look up affected baked textures. + // If they exist: + // disallow updates for affected layersets (until dataserver responds with cache request.) + // If cache miss, turn updates back on and invalidate composite. + // If cache hit, modify baked texture entries. + // + // Cache requests contain list of hashes for each baked texture entry. + // Response is list of valid baked texture assets. (same message) + + gMessageSystem->newMessageFast(_PREHASH_AgentCachedTexture); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gMessageSystem->addS32Fast(_PREHASH_SerialNum, gAgentQueryManager.mWearablesCacheQueryID); + + S32 num_queries = 0; + for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + LLUUID hash; + for (U8 i=0; i < baked_dict->mWearables.size(); i++) + { + // EWearableType baked_type = gBakedWearableMap[baked_index][baked_num]; + const EWearableType baked_type = baked_dict->mWearables[i]; + // MULTI_WEARABLE: assuming 0th + const LLWearable* wearable = getWearable(baked_type,0); + if (wearable) + { + hash ^= wearable->getAssetID(); + } + } + if (hash.notNull()) + { + hash ^= baked_dict->mWearablesHashID; + num_queries++; + // *NOTE: make sure at least one request gets packed + + //llinfos << "Requesting texture for hash " << hash << " in baked texture slot " << baked_index << llendl; + gMessageSystem->nextBlockFast(_PREHASH_WearableData); + gMessageSystem->addUUIDFast(_PREHASH_ID, hash); + gMessageSystem->addU8Fast(_PREHASH_TextureIndex, (U8)baked_index); + } + + gAgentQueryManager.mActiveCacheQueries[baked_index] = gAgentQueryManager.mWearablesCacheQueryID; + } + + llinfos << "Requesting texture cache entry for " << num_queries << " baked textures" << llendl; + gMessageSystem->sendReliable(gAgent.getRegion()->getHost()); + gAgentQueryManager.mNumPendingQueries++; + gAgentQueryManager.mWearablesCacheQueryID++; +} + +// MULTI_WEARABLE: need a way to specify by wearable rather than by type. +// User has picked "remove from avatar" from a menu. +// static +void LLAgentWearables::userRemoveWearable(void* userdata) +{ + EWearableType type = (EWearableType)(intptr_t)userdata; + + if (!(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR)) //&& + //!((!gAgent.isTeen()) && (type==WT_UNDERPANTS || type==WT_UNDERSHIRT))) + { + // MULTI_WEARABLE: fixed to 0th for now. + gAgentWearables.removeWearable(type,false,0); + } +} + +// static +void LLAgentWearables::userRemoveAllClothes(void* userdata) +{ + // We have to do this up front to avoid having to deal with the case of multiple wearables being dirty. + if (gFloaterCustomize) + { + gFloaterCustomize->askToSaveIfDirty(userRemoveAllClothesStep2); + } + else + { + userRemoveAllClothesStep2(TRUE); + } +} + +// static +// MULTI_WEARABLE: removing all here. +void LLAgentWearables::userRemoveAllClothesStep2(BOOL proceed) +{ + if (proceed) + { + gAgentWearables.removeWearable(WT_SHIRT,true,0); + gAgentWearables.removeWearable(WT_PANTS,true,0); + gAgentWearables.removeWearable(WT_SHOES,true,0); + gAgentWearables.removeWearable(WT_SOCKS,true,0); + gAgentWearables.removeWearable(WT_JACKET,true,0); + gAgentWearables.removeWearable(WT_GLOVES,true,0); + gAgentWearables.removeWearable(WT_UNDERSHIRT,true,0); + gAgentWearables.removeWearable(WT_UNDERPANTS,true,0); + gAgentWearables.removeWearable(WT_SKIRT,true,0); + } +} + +void LLAgentWearables::userRemoveAllAttachments(void* userdata) +{ + LLVOAvatar* avatarp = gAgent.getAvatarObject(); + if (!avatarp) + { + llwarns << "No avatar found." << llendl; + return; + } + + gMessageSystem->newMessage("ObjectDetach"); + gMessageSystem->nextBlockFast(_PREHASH_AgentData); + gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end();) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + LLViewerObject* objectp = attachment->getObject(); + if (objectp) + { + gMessageSystem->nextBlockFast(_PREHASH_ObjectData); + gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, objectp->getLocalID()); + } + } + gMessageSystem->sendReliable(gAgent.getRegionHost()); +} + +void LLAgentWearables::checkWearablesLoaded() const +{ +#ifdef SHOW_ASSERT + U32 item_pend_count = itemUpdatePendingCount(); + if (mWearablesLoaded) + { + llassert(item_pend_count==0); + } +#endif +} + +BOOL LLAgentWearables::areWearablesLoaded() const +{ + checkWearablesLoaded(); + return mWearablesLoaded; +} + +// MULTI-WEARABLE: update for multiple indices. +void LLAgentWearables::updateWearablesLoaded() +{ + mWearablesLoaded = (itemUpdatePendingCount()==0); +} + +void LLAgentWearables::updateServer() +{ + sendAgentWearablesUpdate(); + gAgent.sendAgentSetAppearance(); +} + +void LLInitialWearablesFetch::done() +{ + // Get the complete information on the items in the library, + // and set up an observer that will wait for that to happen. + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + + LLFindWearables is_wearable; + gInventory.collectDescendentsIf(mCompleteFolders.front(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_wearable); + S32 count = item_array.count(); + mCOFInitialWearables.reserve(count); + + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *item = (*iter).get(); + // We're only concerned with linked items in the COF. Ignore + // any non-link items or links to folders. + if (item->getActualType() != LLAssetType::AT_LINK) + { + continue; + } + EWearableType type = (EWearableType) (item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); + // MULTI-WEARABLE: update + InitialWearableData wearable_data(type, 0, item->getUUID(), item->getAssetUUID()); + mCOFInitialWearables.push_back(wearable_data); + } + + gInventory.removeObserver(this); + processInitialWearables(); + delete this; +} + +// This will either grab the contents of the Current Outfit Folder if they exist, +// or use the old-style initial agent wearables message. +void LLInitialWearablesFetch::processInitialWearables() +{ +#ifdef USE_CURRENT_OUTFIT_FOLDER + if (!mCOFInitialWearables.empty()) + { + for (U8 i = 0; i < mCOFInitialWearables.size(); ++i) + { + // Fetch the wearables in the current outfit folder + InitialWearableData *wearable_data = new InitialWearableData(mCOFInitialWearables[i]); // This will be deleted in the callback. + if (wearable_data->mAssetID.notNull()) + { + LLWearableList::instance().getAsset(wearable_data->mAssetID, + LLStringUtil::null, + LLWearableDictionary::getAssetType(wearable_data->mType), + LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); + } + else + { + llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " + << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; + } + } + } + else +#endif + if (!mAgentInitialWearables.empty()) // We have an empty current outfit folder, use the message data instead. + { + LLUUID current_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + for (U8 i = 0; i < mAgentInitialWearables.size(); ++i) + { + // Populate the current outfit folder with links to the wearables passed in the message + InitialWearableData *wearable_data = new InitialWearableData(mAgentInitialWearables[i]); // This will be deleted in the callback. + + if (wearable_data->mAssetID.notNull()) + { +#ifdef USE_CURRENT_OUTFIT_FOLDER + const std::string link_name = "WearableLink"; // Unimportant what this is named, it isn't exposed. + link_inventory_item(gAgent.getID(), wearable_data->mItemID, current_outfit_id, link_name, + LLAssetType::AT_LINK, LLPointer(NULL)); +#endif + // Fetch the wearables + LLWearableList::instance().getAsset(wearable_data->mAssetID, + LLStringUtil::null, + LLWearableDictionary::getAssetType(wearable_data->mType), + LLAgentWearables::onInitialWearableAssetArrived, (void*)(wearable_data)); + } + else + { + llinfos << "Invalid wearable, type " << wearable_data->mType << " itemID " + << wearable_data->mItemID << " assetID " << wearable_data->mAssetID << llendl; + } + } + } + else + { + LL_WARNS("Wearables") << "No current outfit folder items found and no initial wearables fallback message received." << LL_ENDL; + } +} diff --git a/indra/newview/llagentwearables.h b/indra/newview/llagentwearables.h new file mode 100644 index 0000000000..b415ef9eb3 --- /dev/null +++ b/indra/newview/llagentwearables.h @@ -0,0 +1,253 @@ +/** + * @file llagentwearables.h + * @brief LLAgentWearables class header file + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAGENTWEARABLES_H +#define LL_LLAGENTWEARABLES_H + +#include "llmemory.h" +#include "lluuid.h" +#include "llinventory.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" +#include "llvoavatardefines.h" + +class LLInventoryItem; +class LLVOAvatarSelf; +class LLWearable; +class LLInitialWearablesFetch; + +class LLAgentWearables +{ + //-------------------------------------------------------------------- + // Constructors / destructors / Initializers + //-------------------------------------------------------------------- +public: + friend class LLInitialWearablesFetch; + + LLAgentWearables(); + virtual ~LLAgentWearables(); + void setAvatarObject(LLVOAvatarSelf *avatar); + void createStandardWearables(BOOL female); + void cleanup(); + void dump(); +protected: + // MULTI-WEARABLE: assuming one per type. Type is called index - rename. + void createStandardWearablesDone(S32 type, U32 index/* = 0*/); + void createStandardWearablesAllDone(); + + //-------------------------------------------------------------------- + // Queries + //-------------------------------------------------------------------- +public: + BOOL isWearingItem(const LLUUID& item_id, const BOOL include_linked_items = FALSE) const; + BOOL isWearableModifiable(EWearableType type, U32 index /*= 0*/) const; + BOOL isWearableCopyable(EWearableType type, U32 index /*= 0*/) const; + BOOL areWearablesLoaded() const; + void updateWearablesLoaded(); + void checkWearablesLoaded() const; + + + //-------------------------------------------------------------------- + // Accessors + //-------------------------------------------------------------------- +public: + const LLUUID getWearableItemID(EWearableType type, U32 index /*= 0*/) const; + const LLWearable* getWearableFromWearableItem(const LLUUID& item_id) const; + LLInventoryItem* getWearableInventoryItem(EWearableType type, U32 index /*= 0*/); + // MULTI-WEARABLE: assuming one per type. + static BOOL selfHasWearable(EWearableType type); + LLWearable* getWearable(const EWearableType type, U32 index /*= 0*/); + const LLWearable* getWearable(const EWearableType type, U32 index /*= 0*/) const; + U32 getWearableCount(const EWearableType type) const; + + + //-------------------------------------------------------------------- + // Setters + //-------------------------------------------------------------------- + +private: + // Low-level data structure setter - public access is via setWearableItem, etc. + void setWearable(const EWearableType type, U32 index, LLWearable *wearable); + +public: + void setWearableItem(LLInventoryItem* new_item, LLWearable* wearable, bool do_append = false); + void setWearableOutfit(const LLInventoryItem::item_array_t& items, const LLDynamicArray< LLWearable* >& wearables, BOOL remove); + void setWearableName(const LLUUID& item_id, const std::string& new_name); + void addLocalTextureObject(const EWearableType wearable_type, const LLVOAvatarDefines::ETextureIndex texture_type, U32 wearable_index); +protected: + void setWearableFinal(LLInventoryItem* new_item, LLWearable* new_wearable, bool do_append = false); + static bool onSetWearableDialog(const LLSD& notification, const LLSD& response, LLWearable* wearable); + + void addWearableToAgentInventory(LLPointer cb, + LLWearable* wearable, + const LLUUID& category_id = LLUUID::null, + BOOL notify = TRUE); + void addWearabletoAgentInventoryDone(const S32 type, + const U32 index, + const LLUUID& item_id, + LLWearable* wearable); + void recoverMissingWearable(const EWearableType type, U32 index /*= 0*/); + void recoverMissingWearableDone(); + + //-------------------------------------------------------------------- + // Removing wearables + //-------------------------------------------------------------------- +public: + void removeWearable(const EWearableType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +private: + void removeWearableFinal(const EWearableType type, bool do_remove_all /*= false*/, U32 index /*= 0*/); +protected: + static bool onRemoveWearableDialog(const LLSD& notification, const LLSD& response); + static void userRemoveAllClothesStep2(BOOL proceed); // userdata is NULL + + //-------------------------------------------------------------------- + // Server Communication + //-------------------------------------------------------------------- +public: + // Processes the initial wearables update message (if necessary, since the outfit folder makes it redundant) + static void processAgentInitialWearablesUpdate(LLMessageSystem* mesgsys, void** user_data); +protected: + void sendAgentWearablesUpdate(); + void sendAgentWearablesRequest(); + void queryWearableCache(); + void updateServer(); + static void onInitialWearableAssetArrived(LLWearable* wearable, void* userdata); + + //-------------------------------------------------------------------- + // Outfits + //-------------------------------------------------------------------- +public: + void getAllWearablesArray(LLDynamicArray& wearables); + + // Note: wearables_to_include should be a list of EWearableType types + // attachments_to_include should be a list of attachment points + void makeNewOutfit(const std::string& new_folder_name, + const LLDynamicArray& wearables_to_include, + const LLDynamicArray& attachments_to_include, + BOOL rename_clothing); + + // Note: wearables_to_include should be a list of EWearableType types + // attachments_to_include should be a list of attachment points + LLUUID makeNewOutfitLinks(const std::string& new_folder_name); + LLUUID makeNewOutfitLinks(const std::string& new_folder_name, + const LLDynamicArray& wearables_to_include, + const LLDynamicArray& attachments_to_include); +private: + void makeNewOutfitDone(S32 type, U32 index); + + //-------------------------------------------------------------------- + // Save Wearables + //-------------------------------------------------------------------- +public: + // MULTI-WEARABLE: assumes one per type. + void saveWearableAs(const EWearableType type, const U32 index, const std::string& new_name, BOOL save_in_lost_and_found); + void saveWearable(const EWearableType type, const U32 index, BOOL send_update = TRUE); + void saveAllWearables(); + void revertWearable(const EWearableType type, const U32 index); + + //-------------------------------------------------------------------- + // Static UI hooks + //-------------------------------------------------------------------- +public: + // MULTI-WEARABLE: assuming one wearable per type. Need upstream changes. + static void userRemoveWearable(void* userdata); // userdata is EWearableType + static void userRemoveAllClothes(void* userdata); // userdata is NULL + static void userRemoveAllAttachments(void* userdata); // userdata is NULL + + BOOL itemUpdatePending(const LLUUID& item_id) const; + U32 itemUpdatePendingCount() const; + + //-------------------------------------------------------------------- + // Member variables + //-------------------------------------------------------------------- +private: + typedef std::vector wearableentry_vec_t; // all wearables of a certain type (EG all shirts) + typedef std::map wearableentry_map_t; // wearable "categories" arranged by wearable type + wearableentry_map_t mWearableDatas; + + static BOOL mInitialWearablesUpdateReceived; + BOOL mWearablesLoaded; + std::set mItemsAwaitingWearableUpdate; + LLPointer mAvatarObject; // NULL until avatar object sent down from simulator + + //-------------------------------------------------------------------------------- + // Support classes + //-------------------------------------------------------------------------------- +private: + class createStandardWearablesAllDoneCallback : public LLRefCount + { + protected: + ~createStandardWearablesAllDoneCallback(); + }; + class sendAgentWearablesUpdateCallback : public LLRefCount + { + protected: + ~sendAgentWearablesUpdateCallback(); + }; + + class addWearableToAgentInventoryCallback : public LLInventoryCallback + { + public: + enum EType + { + CALL_NONE = 0, + CALL_UPDATE = 1, + CALL_RECOVERDONE = 2, + CALL_CREATESTANDARDDONE = 4, + CALL_MAKENEWOUTFITDONE = 8 + }; + + // MULTI-WEARABLE: index is an EWearableType - more confusing usage. + // MULTI-WEARABLE: need to have type and index args both? + addWearableToAgentInventoryCallback(LLPointer cb, + S32 type, + U32 index, + LLWearable* wearable, + U32 todo = CALL_NONE); + virtual void fire(const LLUUID& inv_item); + private: + S32 mType; + U32 mIndex; + LLWearable* mWearable; + U32 mTodo; + LLPointer mCB; + }; + +}; // LLAgentWearables + +extern LLAgentWearables gAgentWearables; + +//-------------------------------------------------------------------- +// Types +//-------------------------------------------------------------------- + +#endif // LL_AGENTWEARABLES_H diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 584ab5e50f..de4f7ab091 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -30,9 +30,10 @@ * $/LicenseInfo$ */ - #include "llviewerprecompiledheaders.h" + #include "llappviewer.h" + #include "llprimitive.h" #include "llversionviewer.h" @@ -41,37 +42,46 @@ #include "lltexteditor.h" #include "llalertdialog.h" #include "llerrorcontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llgroupmgr.h" #include "llagent.h" +#include "llagentwearables.h" #include "llwindow.h" #include "llviewerstats.h" #include "llmd5.h" #include "llpumpio.h" #include "llimpanel.h" #include "llmimetypes.h" +#include "llslurl.h" #include "llstartup.h" #include "llfocusmgr.h" #include "llviewerjoystick.h" -#include "llfloaterjoystick.h" +#include "llallocator.h" #include "llares.h" #include "llcurl.h" -#include "llfloatersnapshot.h" #include "llviewerwindow.h" #include "llviewerdisplay.h" #include "llviewermedia.h" +#include "llviewerparcelmedia.h" +#include "llviewermediafocus.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" #include "llworldmap.h" #include "llmutelist.h" +#include "lluicolortable.h" #include "llurldispatcher.h" #include "llurlhistory.h" #include "llfirstuse.h" #include "llrender.h" - +#include "lllocationhistory.h" +#include "llfasttimerview.h" #include "llweb.h" #include "llsecondlifeurls.h" +// Linden library includes +#include "llmemory.h" + +// Third party library includes #include #if LL_WINDOWS @@ -101,11 +111,12 @@ #include "llassetstorage.h" #include "llpolymesh.h" #include "llcachename.h" -#include "audioengine.h" +#include "llaudioengine.h" +#include "llstreamingaudio.h" #include "llviewermenu.h" #include "llselectmgr.h" #include "lltrans.h" -#include "lluitrans.h" +#include "lltransutil.h" #include "lltracker.h" #include "llviewerparcelmgr.h" #include "llworldmapview.h" @@ -116,9 +127,7 @@ #include "lldebugview.h" #include "llconsole.h" #include "llcontainerview.h" -#include "llfloaterstats.h" #include "llhoverview.h" -#include "llfloatermemleak.h" #include "llsdserialize.h" @@ -139,12 +148,17 @@ #include "llvoavatar.h" #include "llfolderview.h" #include "lltoolbar.h" -#include "llframestats.h" #include "llagentpilot.h" #include "llsrv.h" #include "llvovolume.h" #include "llflexibleobject.h" #include "llvosurfacepatch.h" +#include "llviewerfloaterreg.h" +#include "llcommandlineparser.h" +#include "llfloatermemleak.h" +#include "llfloaterreg.h" +#include "llfloatersnapshot.h" +#include "llfloaterinventory.h" // includes for idle() idleShutdown() #include "llviewercontrol.h" @@ -161,11 +175,6 @@ #include "llviewerthrottle.h" #include "llparcel.h" - -#include "llinventoryview.h" - -#include "llcommandlineparser.h" - // *FIX: These extern globals should be cleaned up. // The globals either represent state/config/resource-storage of either // this app, or another 'component' of the viewer. App globals should be @@ -181,10 +190,6 @@ ////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor // -#if LL_WINDOWS && LL_LCD_COMPILE - #include "lllcd.h" -#endif - //---------------------------------------------------------------------------- // viewer.cpp - these are only used in viewer, should be easily moved. @@ -235,9 +240,6 @@ LLTimer gLogoutTimer; static const F32 LOGOUT_REQUEST_TIME = 6.f; // this will be cut short by the LogoutReply msg. F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME; -LLUUID gInventoryLibraryOwner; -LLUUID gInventoryLibraryRoot; - BOOL gDisconnected = FALSE; // Map scale in pixels per region @@ -284,12 +286,23 @@ static std::string gLaunchFileOnQuit; // Used on Win32 for other apps to identify our window (eg, win_setup) const char* const VIEWER_WINDOW_CLASSNAME = "Second Life"; +//---------------------------------------------------------------------------- + +// List of entries from strings.xml to always replace +static std::set default_trans_args; +void init_default_trans_args() +{ + default_trans_args.insert("SECOND_LIFE"); // World + default_trans_args.insert("APP_NAME"); + default_trans_args.insert("SECOND_LIFE_GRID"); + default_trans_args.insert("SUPPORT_SITE"); +} + //---------------------------------------------------------------------------- // File scope definitons const char *VFS_DATA_FILE_BASE = "data.db2.x."; const char *VFS_INDEX_FILE_BASE = "index.db2.x."; -static std::string gSecondLife; static std::string gWindowTitle; std::string gLoginPage; @@ -366,7 +379,6 @@ static void settings_to_globals() MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight"); MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth"); - STATUS_BAR_HEIGHT = gSavedSettings.getS32("StatusBarHeight"); LLCOMBOBOX_HEIGHT = BTN_HEIGHT - 2; LLCOMBOBOX_WIDTH = 128; @@ -388,10 +400,9 @@ static void settings_to_globals() LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections"); LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); - gFrameStats.setTrackStats(gSavedSettings.getBOOL("StatsSessionTrackFrameStats")); gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns"); gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns"); - gAgent.mHideGroupTitle = gSavedSettings.getBOOL("RenderHideGroupTitle"); + gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle")); gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc"); gAllowTapTapHoldRun = gSavedSettings.getBOOL("AllowTapTapHoldRun"); @@ -408,7 +419,7 @@ static void settings_modify() LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors"); LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor"); LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4] - gDebugGL = gSavedSettings.getBOOL("RenderDebugGL"); + gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession; gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline"); #if LL_VECTORIZE @@ -446,6 +457,38 @@ static void settings_modify() #endif } +class LLFastTimerLogThread : public LLThread +{ +public: + std::string mFile; + + LLFastTimerLogThread() : LLThread("fast timer log") + { + if(LLFastTimer::sLog) + { + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"); + } + if(LLFastTimer::sMetricLog) + { + mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"); + } + } + + void run() + { + std::ofstream os(mFile.c_str()); + + while (!LLAppViewer::instance()->isQuitting()) + { + LLFastTimer::writeLog(os); + os.flush(); + ms_sleep(32); + } + + os.close(); + } +}; + void LLAppViewer::initGridChoice() { // Load up the initial grid choice from: @@ -497,8 +540,6 @@ bool LLAppViewer::sendURLToOtherInstance(const std::string& url) LLAppViewer* LLAppViewer::sInstance = NULL; const std::string LLAppViewer::sGlobalSettingsName = "Global"; -const std::string LLAppViewer::sPerAccountSettingsName = "PerAccount"; -const std::string LLAppViewer::sCrashSettingsName = "CrashSettings"; LLTextureCache* LLAppViewer::sTextureCache = NULL; LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL; @@ -513,11 +554,15 @@ LLAppViewer::LLAppViewer() : mPurgeOnExit(false), mSecondInstance(false), mSavedFinalSnapshot(false), + mForceGraphicsDetail(false), mQuitRequested(false), mLogoutRequestSent(false), mYieldTime(-1), mMainloopTimeout(NULL), - mAgentRegionLastAlive(false) + mAgentRegionLastAlive(false), + mFastTimerLogThread(NULL), + mRandomizeFramerate(LLCachedControl(gSavedSettings,"Randomize Framerate", FALSE)), + mPeriodicSlowFrame(LLCachedControl(gSavedSettings,"Periodic Slow Frame", FALSE)) { if(NULL != sInstance) { @@ -558,8 +603,13 @@ bool LLAppViewer::init() // // OK to write stuff to logs now, we've now crash reported if necessary // - if (!initConfiguration()) + + init_default_trans_args(); + + if (!initConfiguration()) return false; + + mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling")); // *NOTE:Mani - LLCurl::initClass is not thread safe. // Called before threads are created. @@ -593,6 +643,11 @@ bool LLAppViewer::init() // Get the single value from the crash settings file, if it exists std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); gCrashSettings.loadFromFile(crash_settings_filename); + if(gSavedSettings.getBOOL("IgnoreAllNotifications")) + { + gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ALWAYS_SEND); + gCrashSettings.saveToFile(crash_settings_filename, FALSE); + } ///////////////////////////////////////////////// // OS-specific login dialogs @@ -612,34 +667,37 @@ bool LLAppViewer::init() LLError::setPrintLocation(true); } - // Load art UUID information, don't require these strings to be declared in code. - std::string colors_base_filename = gDirUtilp->findSkinnedFilename("colors_base.xml"); - LL_DEBUGS("InitInfo") << "Loading base colors from " << colors_base_filename << LL_ENDL; - gColors.loadFromFileLegacy(colors_base_filename, FALSE, TYPE_COL4U); - - // Load overrides from user colors file - std::string user_colors_filename = gDirUtilp->findSkinnedFilename("colors.xml"); - LL_DEBUGS("InitInfo") << "Loading user colors from " << user_colors_filename << LL_ENDL; - if (gColors.loadFromFileLegacy(user_colors_filename, FALSE, TYPE_COL4U) == 0) - { - LL_DEBUGS("InitInfo") << "Cannot load user colors from " << user_colors_filename << LL_ENDL; - } - // Widget construction depends on LLUI being initialized - LLUI::initClass(&gSavedSettings, - &gSavedSettings, - &gColors, + LLUI::settings_map_t settings_map; + settings_map["config"] = &gSavedSettings; + settings_map["ignores"] = &gWarningSettings; + settings_map["floater"] = &gSavedSettings; // *TODO: New settings file + settings_map["account"] = &gSavedPerAccountSettings; + + LLUI::initClass(settings_map, LLUIImageList::getInstance(), ui_audio_callback, &LLUI::sGLScaleFactor); + + // Setup paths and LLTrans after LLUI::initClass has been called + LLUI::setupPaths(); + LLTransUtil::parseStrings("strings.xml", default_trans_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); LLWeb::initClass(); // do this after LLUI LLTextEditor::setURLCallbacks(&LLWeb::loadURL, &LLURLDispatcher::dispatchFromTextEditor, &LLURLDispatcher::dispatchFromTextEditor); - - LLUICtrlFactory::getInstance()->setupPaths(); // update paths with correct language set + // Load translations for tooltips + LLFloater::initClass(); + + ///////////////////////////////////////////////// + + LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated + + LLViewerFloaterReg::registerFloaters(); + ///////////////////////////////////////////////// // // Load settings files @@ -692,18 +750,8 @@ bool LLAppViewer::init() if (!initCache()) { std::ostringstream msg; - msg << - gSecondLife << " is unable to access a file that it needs.\n" - "\n" - "This can be because you somehow have multiple copies running, " - "or your system incorrectly thinks a file is open. " - "If this message persists, restart your computer and try again. " - "If it continues to persist, you may need to completely uninstall " << - gSecondLife << " and reinstall it."; - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); + msg << LLTrans::getString("MBUnableToAccessFile"); + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); return 1; } @@ -818,8 +866,14 @@ bool LLAppViewer::init() return true; } +static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages"); +static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep"); +static LLFastTimer::DeclareTimer FTM_IDLE("Idle"); +static LLFastTimer::DeclareTimer FTM_PUMP("Pump"); + bool LLAppViewer::mainLoop() { + LLMemType mt1(LLMemType::MTYPE_MAIN); mMainloopTimeout = new LLWatchdogTimeout(); // *FIX:Mani - Make this a setting, once new settings exist in this branch. @@ -837,7 +891,6 @@ bool LLAppViewer::mainLoop() LLVoiceChannel::initClass(); LLVoiceClient::init(gServicePump); - LLMemType mt1(LLMemType::MTYPE_MAIN); LLTimer frameTimer,idleTimer; LLTimer debugTime; LLViewerJoystick* joystick(LLViewerJoystick::getInstance()); @@ -853,21 +906,22 @@ bool LLAppViewer::mainLoop() // Handle messages while (!LLApp::isExiting()) { - LLFastTimer::reset(); // Should be outside of any timer instances + LLFastTimer::nextFrame(); // Should be outside of any timer instances try { - LLFastTimer t(LLFastTimer::FTM_FRAME); pingMainloopTimeout("Main:MiscNativeWindowEvents"); - + + if (gViewerWindow) { - LLFastTimer t2(LLFastTimer::FTM_MESSAGES); + LLFastTimer t2(FTM_MESSAGES); gViewerWindow->mWindow->processMiscNativeEvents(); } pingMainloopTimeout("Main:GatherInput"); + if (gViewerWindow) { - LLFastTimer t2(LLFastTimer::FTM_MESSAGES); + LLFastTimer t2(FTM_MESSAGES); if (!restoreErrorTrap()) { llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl; @@ -885,9 +939,10 @@ bool LLAppViewer::mainLoop() #endif //memory leaking simulation - if(LLFloaterMemLeak::getInstance()) + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::getTypedInstance("mem_leaking"); + if(mem_leak_instance) { - LLFloaterMemLeak::getInstance()->idle() ; + mem_leak_instance->idle() ; } // canonical per-frame event @@ -907,6 +962,7 @@ bool LLAppViewer::mainLoop() && !gViewerWindow->getShowProgress() && !gFocusMgr.focusLocked()) { + LLMemType mjk(LLMemType::MTYPE_JOY_KEY); joystick->scanJoystick(); gKeyboard->scanKeyboard(); } @@ -915,13 +971,14 @@ bool LLAppViewer::mainLoop() { pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds! - LLFastTimer t3(LLFastTimer::FTM_IDLE); + LLFastTimer t3(FTM_IDLE); idle(); if (gAres != NULL && gAres->isInitialized()) { + LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP); pingMainloopTimeout("Main:ServicePump"); - LLFastTimer t4(LLFastTimer::FTM_PUMP); + LLFastTimer t4(FTM_PUMP); gAres->process(); // this pump is necessary to make the login screen show up gServicePump->pump(); @@ -947,12 +1004,6 @@ bool LLAppViewer::mainLoop() pingMainloopTimeout("Main:Snapshot"); LLFloaterSnapshot::update(); // take snapshots - -#if LL_LCD_COMPILE - // update LCD Screen - pingMainloopTimeout("Main:LCD"); - gLcdScreen->UpdateDisplay(); -#endif } } @@ -963,7 +1014,8 @@ bool LLAppViewer::mainLoop() // Sleep and run background threads { - LLFastTimer t2(LLFastTimer::FTM_SLEEP); + LLMemType mt_sleep(LLMemType::MTYPE_SLEEP); + LLFastTimer t2(FTM_SLEEP); bool run_multiple_threads = gSavedSettings.getBOOL("RunMultipleThreads"); // yield some time to the os based on command line option @@ -974,7 +1026,7 @@ bool LLAppViewer::mainLoop() // yield cooperatively when not running as foreground window if ( gNoRender - || !gViewerWindow->mWindow->getVisible() + || (gViewerWindow && !gViewerWindow->mWindow->getVisible()) || !gFocusMgr.getAppHasFocus()) { // Sleep if we're not rendering, or the window is minimized. @@ -990,12 +1042,12 @@ bool LLAppViewer::mainLoop() } } - if (gRandomizeFramerate) + if (mRandomizeFramerate) { ms_sleep(rand() % 200); } - if (gPeriodicSlowFrame + if (mPeriodicSlowFrame && (gFrameCount % 10 == 0)) { llinfos << "Periodic slow frame - sleeping 500 ms" << llendl; @@ -1057,9 +1109,10 @@ bool LLAppViewer::mainLoop() catch(std::bad_alloc) { //stop memory leaking simulation - if(LLFloaterMemLeak::getInstance()) + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::getTypedInstance("mem_leaking"); + if(mem_leak_instance) { - LLFloaterMemLeak::getInstance()->stop() ; + mem_leak_instance->stop() ; llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ; } else @@ -1084,9 +1137,10 @@ bool LLAppViewer::mainLoop() llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ; //stop memory leaking simulation - if(LLFloaterMemLeak::getInstance()) + LLFloaterMemLeak* mem_leak_instance = LLFloaterReg::getTypedInstance("mem_leaking"); + if(mem_leak_instance) { - LLFloaterMemLeak::getInstance()->stop() ; + mem_leak_instance->stop() ; } } } @@ -1166,6 +1220,14 @@ bool LLAppViewer::cleanup() if (gAudiop) { + // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. + + LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); + delete sai; + gAudiop->setStreamingAudioImpl(NULL); + + // shut down the audio subsystem + bool want_longname = false; if (gAudiop->getDriverName(want_longname) == "FMOD") { @@ -1221,22 +1283,26 @@ bool LLAppViewer::cleanup() llinfos << "Shutting down." << llendflush; // Destroy the UI - gViewerWindow->shutdownViews(); + if( gViewerWindow) + gViewerWindow->shutdownViews(); // Clean up selection managers after UI is destroyed, as UI may be observing them. // Clean up before GL is shut down because we might be holding on to objects with texture references LLSelectMgr::cleanupGlobals(); // Shut down OpenGL - gViewerWindow->shutdownGL(); + if( gViewerWindow) + { + gViewerWindow->shutdownGL(); + + // Destroy window, and make sure we're not fullscreen + // This may generate window reshape and activation events. + // Therefore must do this before destroying the message system. + delete gViewerWindow; + gViewerWindow = NULL; + llinfos << "ViewerWindow deleted" << llendflush; + } - // Destroy window, and make sure we're not fullscreen - // This may generate window reshape and activation events. - // Therefore must do this before destroying the message system. - delete gViewerWindow; - gViewerWindow = NULL; - llinfos << "ViewerWindow deleted" << llendflush; - // viewer UI relies on keyboard so keep it aound until viewer UI isa gone delete gKeyboard; gKeyboard = NULL; @@ -1256,12 +1322,6 @@ bool LLAppViewer::cleanup() // gDXHardware.cleanup(); //#endif // LL_WINDOWS -#if LL_LCD_COMPILE - // shut down the LCD window on a logitech keyboard, if there is one - delete gLcdScreen; - gLcdScreen = NULL; -#endif - LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager(); if (!volume_manager->cleanup()) { @@ -1303,7 +1363,9 @@ bool LLAppViewer::cleanup() // Must do this after all panels have been deleted because panels that have persistent rects // save their rects on delete. - gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + + LLUIColorTable::instance().saveUserSettings(); // PerAccountSettingsFile should be empty if no use has been logged on. // *FIX:Mani This should get really saved in a "logoff" mode. @@ -1314,9 +1376,8 @@ bool LLAppViewer::cleanup() // save all settings, even if equals defaults gCrashSettings.saveToFile(crash_settings_filename, FALSE); - gSavedSettings.cleanup(); - gColors.cleanup(); - gCrashSettings.cleanup(); + std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings")); + gWarningSettings.saveToFile(warnings_settings_filename, TRUE); // Save URL history file LLURLHistory::saveFile("url_history.xml"); @@ -1360,6 +1421,7 @@ bool LLAppViewer::cleanup() sTextureCache->shutdown(); sTextureFetch->shutdown(); sImageDecodeThread->shutdown(); + delete sTextureCache; sTextureCache = NULL; delete sTextureFetch; @@ -1367,11 +1429,38 @@ bool LLAppViewer::cleanup() delete sImageDecodeThread; sImageDecodeThread = NULL; + LLLocationHistory::getInstance()->save(); + delete mFastTimerLogThread; + mFastTimerLogThread = NULL; + + if (LLFastTimerView::sAnalyzePerformance) + { + llinfos << "Analyzing performance" << llendl; + + if(LLFastTimer::sLog) + { + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_baseline.slp"), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance.slp"), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "performance_report.csv")); + } + if(LLFastTimer::sMetricLog) + { + LLFastTimerView::doAnalysis( + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_baseline.slp"), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric.slp"), + gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "metric_report.csv")); + } + } + LLMetricPerformanceTester::cleanClass() ; + //Note: - //LLViewerMedia::cleanupClass() has to be put before gImageList.shutdown() + //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown() //because some new image might be generated during cleaning up media. --bao + LLViewerMediaFocus::cleanupClass(); LLViewerMedia::cleanupClass(); - gImageList.shutdown(); // shutdown again in case a callback added something + LLViewerParcelMedia::cleanupClass(); + gTextureList.shutdown(); // shutdown again in case a callback added something LLUIImageList::getInstance()->cleanUp(); // This should eventually be done in LLAppViewer @@ -1392,6 +1481,10 @@ bool LLAppViewer::cleanup() gStaticVFS = NULL; delete gVFS; gVFS = NULL; + + gSavedSettings.cleanup(); + LLUIColorTable::instance().clear(); + gCrashSettings.cleanup(); LLWatchdog::getInstance()->cleanup(); @@ -1419,6 +1512,8 @@ bool LLAppViewer::cleanup() llinfos << "File launched." << llendflush; } + ll_close_fail_log(); + llinfos << "Goodbye" << llendflush; // return 0; @@ -1469,6 +1564,13 @@ bool LLAppViewer::initThreads() LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), enable_threads && false); LLImage::initClass(LLAppViewer::getImageDecodeThread()); + if (LLFastTimer::sLog || LLFastTimer::sMetricLog) + { + LLFastTimer::sLogLock = new LLMutex(NULL); + mFastTimerLogThread = new LLFastTimerLogThread(); + mFastTimerLogThread->start(); + } + // *FIX: no error handling here! return true; } @@ -1476,7 +1578,7 @@ bool LLAppViewer::initThreads() void errorCallback(const std::string &error_string) { #ifndef LL_RELEASE_FOR_DOWNLOAD - OSMessageBox(error_string, "Fatal Error", OSMB_OK); + OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK); #endif //Set the ErrorActivated global so we know to create a marker file @@ -1544,7 +1646,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, llinfos << "Attempting to load settings for the group " << settings_group << " - from location " << location_key << llendl; - if(gSettings.find(settings_group) == gSettings.end()) + if(!LLControlGroup::getInstance(settings_group)) { llwarns << "No matching settings group for name " << settings_group << llendl; continue; @@ -1558,10 +1660,10 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, std::string custom_name_setting = file.get("NameFromSetting"); // *NOTE: Regardless of the group currently being lodaed, // this setting is always read from the Global settings. - if(gSettings[sGlobalSettingsName]->controlExists(custom_name_setting)) + if(LLControlGroup::getInstance(sGlobalSettingsName)->controlExists(custom_name_setting)) { std::string file_name = - gSettings[sGlobalSettingsName]->getString(custom_name_setting); + LLControlGroup::getInstance(sGlobalSettingsName)->getString(custom_name_setting); full_settings_path = file_name; } } @@ -1578,7 +1680,7 @@ bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key, requirement = file.get("Requirement").asInteger(); } - if(!gSettings[settings_group]->loadFromFile(full_settings_path, set_defaults)) + if(!LLControlGroup::getInstance(settings_group)->loadFromFile(full_settings_path, set_defaults)) { if(requirement == 1) { @@ -1618,17 +1720,17 @@ std::string LLAppViewer::getSettingsFilename(const std::string& location_key, return std::string(); } +void LLAppViewer::loadColorSettings() +{ + LLUIColorTable::instance().loadFromSettings(); +} + bool LLAppViewer::initConfiguration() { - //Set up internal pointers - gSettings[sGlobalSettingsName] = &gSavedSettings; - gSettings[sPerAccountSettingsName] = &gSavedPerAccountSettings; - gSettings[sCrashSettingsName] = &gCrashSettings; - //Load settings files list std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml"); - LLControlGroup settings_control; - llinfos << "Loading settings file list" << settings_file_list << llendl; + LLControlGroup settings_control("SettingsFiles"); + llinfos << "Loading settings file list " << settings_file_list << llendl; if (0 == settings_control.loadFromFile(settings_file_list)) { llerrs << "Cannot load default configuration file " << settings_file_list << llendl; @@ -1651,18 +1753,16 @@ bool LLAppViewer::initConfiguration() if(!loadSettingsFromDirectory("Default", set_defaults)) { std::ostringstream msg; - msg << "Second Life could not load its default settings file. \n" - << "The installation may be corrupted. \n"; - - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - + msg << "Unable to load default settings file. The installation may be corrupted."; + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); return false; } - - // - set procedural settings + + LLUI::setupPaths(); // setup paths for LLTrans based on settings files only + LLTransUtil::parseStrings("strings.xml", default_trans_args); + LLTransUtil::parseLanguageStrings("language_settings.xml"); + // - set procedural settings + // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet gSavedSettings.setString("ClientSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global"))); @@ -1685,7 +1785,7 @@ bool LLAppViewer::initConfiguration() gSavedSettings.setBOOL("WatchdogEnabled", FALSE); #endif - gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _1)); + gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2)); // These are warnings that appear on the first experience of that condition. // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse @@ -1696,7 +1796,7 @@ bool LLAppViewer::initConfiguration() LLFirstUse::addConfigVariable("FirstMap"); LLFirstUse::addConfigVariable("FirstGoTo"); LLFirstUse::addConfigVariable("FirstBuild"); - LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); +// LLFirstUse::addConfigVariable("FirstLeftClickNoHit"); LLFirstUse::addConfigVariable("FirstTeleport"); LLFirstUse::addConfigVariable("FirstOverrideKeys"); LLFirstUse::addConfigVariable("FirstAttach"); @@ -1715,26 +1815,18 @@ bool LLAppViewer::initConfiguration() LLControlGroupCLP clp; std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "cmd_line.xml"); + clp.configure(cmd_line_config, &gSavedSettings); if(!initParseCommandLine(clp)) { - llwarns - << "Error parsing command line options. Command Line options ignored." - << llendl; - + llwarns << "Error parsing command line options. Command Line options ignored." << llendl; + llinfos << "Command line usage:\n" << clp << llendl; std::ostringstream msg; - msg << "Second Life found an error parsing the command line. \n" - << "Please see: http://wiki.secondlife.com/wiki/Client_parameters \n" - << "Error: " << clp.getErrorMessage(); - - OSMessageBox( - msg.str(), - LLStringUtil::null, - OSMB_OK); - + msg << LLTrans::getString("MBCmdLineError") << clp.getErrorMessage(); + OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK); return false; } @@ -1754,7 +1846,6 @@ bool LLAppViewer::initConfiguration() // - load overrides from user_settings loadSettingsFromDirectory("User"); - // - apply command line settings clp.notify(); @@ -1768,7 +1859,7 @@ bool LLAppViewer::initConfiguration() if(clp.hasOption("help")) { std::ostringstream msg; - msg << "Command line usage:\n" << clp; + msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp; llinfos << msg.str() << llendl; OSMessageBox( @@ -1779,36 +1870,6 @@ bool LLAppViewer::initConfiguration() return false; } - ////////////////////////// - // Apply settings... - if(clp.hasOption("setdefault")) - { - //const LLCommandLineParser::token_vector_t& setdefault = clp.getOption("setdefault"); - //if(0x1 & setdefault.size()) - //{ - // llwarns << "Invalid '--setdefault' parameter count." << llendl; - //} - //else - //{ - // LLCommandLineParser::token_vector_t::const_iterator itr = setdefault.begin(); - // for(; itr != setdefault.end(); ++itr) - // { - // const std::string& name = *itr; - // const std::string& value = *(++itr); - // LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name); - // if(c) - // { - // c->setDefault(value); - // } - // else - // { - // llwarns << "'--setdefault' specified with unknown setting: '" - // << name << "'." << llendl; - // } - // } - //} - } - if(clp.hasOption("set")) { const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set"); @@ -1823,7 +1884,7 @@ bool LLAppViewer::initConfiguration() { const std::string& name = *itr; const std::string& value = *(++itr); - LLControlVariable* c = gSettings[sGlobalSettingsName]->getControl(name); + LLControlVariable* c = LLControlGroup::getInstance(sGlobalSettingsName)->getControl(name); if(c) { c->setValue(value, false); @@ -1845,6 +1906,73 @@ bool LLAppViewer::initConfiguration() gCrashOnStartup = TRUE; } + if (clp.hasOption("logperformance")) + { + LLFastTimer::sLog = TRUE; + } + + if(clp.hasOption("logmetrics")) + { + LLFastTimer::sMetricLog = TRUE ; + } + + if (clp.hasOption("graphicslevel")) + { + const LLCommandLineParser::token_vector_t& value = clp.getOption("graphicslevel"); + if(value.size() != 1) + { + llwarns << "Usage: -graphicslevel <0-3>" << llendl; + } + else + { + std::string detail = value.front(); + mForceGraphicsDetail = TRUE; + + switch (detail.c_str()[0]) + { + case '0': + gSavedSettings.setU32("RenderQualityPerformance", 0); + break; + case '1': + gSavedSettings.setU32("RenderQualityPerformance", 1); + break; + case '2': + gSavedSettings.setU32("RenderQualityPerformance", 2); + break; + case '3': + gSavedSettings.setU32("RenderQualityPerformance", 3); + break; + default: + mForceGraphicsDetail = FALSE; + llwarns << "Usage: -graphicslevel <0-3>" << llendl; + break; + } + } + } + + if (clp.hasOption("analyzeperformance")) + { + LLFastTimerView::sAnalyzePerformance = TRUE; + } + + if (clp.hasOption("replaysession")) + { + LLAgentPilot::sReplaySession = TRUE; + } + + if (clp.hasOption("nonotifications")) + { + gSavedSettings.setBOOL("IgnoreAllNotifications", TRUE); + } + + if (clp.hasOption("debugsession")) + { + gDebugSession = TRUE; + gDebugGL = TRUE; + + ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log")); + } + // Handle slurl use. NOTE: Don't let SL-55321 reappear. // *FIX: This init code should be made more robust to prevent @@ -1865,7 +1993,7 @@ bool LLAppViewer::initConfiguration() if(clp.hasOption("url")) { std::string slurl = clp.getOption("url")[0]; - if (LLURLDispatcher::isSLURLCommand(slurl)) + if (LLSLURL::isSLURLCommand(slurl)) { LLStartUp::sSLURLCommand = slurl; } @@ -1877,9 +2005,9 @@ bool LLAppViewer::initConfiguration() else if(clp.hasOption("slurl")) { std::string slurl = clp.getOption("slurl")[0]; - if(LLURLDispatcher::isSLURL(slurl)) + if(LLSLURL::isSLURL(slurl)) { - if (LLURLDispatcher::isSLURLCommand(slurl)) + if (LLSLURL::isSLURLCommand(slurl)) { LLStartUp::sSLURLCommand = slurl; } @@ -1893,13 +2021,12 @@ bool LLAppViewer::initConfiguration() const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent"); if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString()) { - gDirUtilp->setSkinFolder(skinfolder->getValue().asString()); + // hack to force the skin to default. + //gDirUtilp->setSkinFolder(skinfolder->getValue().asString()); + gDirUtilp->setSkinFolder("default"); } mYieldTime = gSavedSettings.getS32("YieldTime"); - - // XUI:translate - gSecondLife = "Second Life"; // Read skin/branding settings if specified. //if (! gDirUtilp->getSkinDir().empty() ) @@ -1916,7 +2043,7 @@ bool LLAppViewer::initConfiguration() #if LL_DARWIN // Initialize apple menubar and various callbacks - init_apple_menu(gSecondLife.c_str()); + init_apple_menu(LLTrans::getString("APP_NAME").c_str()); #if __ppc__ // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further. @@ -1924,7 +2051,7 @@ bool LLAppViewer::initConfiguration() if(!gSysCPU.hasAltivec()) { std::ostringstream msg; - msg << gSecondLife << " requires a processor with AltiVec (G4 or later)."; + msg << LLTrans::getString("MBRequiresAltiVec"); OSMessageBox( msg.str(), LLStringUtil::null, @@ -1939,7 +2066,7 @@ bool LLAppViewer::initConfiguration() // Display splash screen. Must be after above check for previous // crash as this dialog is always frontmost. std::ostringstream splash_msg; - splash_msg << "Loading " << gSecondLife << "..."; + splash_msg << "Loading " << LLTrans::getString("SECOND_LIFE") << "..."; LLSplashScreen::show(); LLSplashScreen::update(splash_msg.str()); @@ -1955,12 +2082,11 @@ bool LLAppViewer::initConfiguration() // // Set the name of the window // -#if LL_RELEASE_FOR_DOWNLOAD - gWindowTitle = gSecondLife; -#elif LL_DEBUG - gWindowTitle = gSecondLife + std::string(" [DEBUG] ") + gArgs; + gWindowTitle = LLTrans::getString("APP_NAME"); +#if LL_DEBUG + gWindowTitle += std::string(" [DEBUG] ") + gArgs; #else - gWindowTitle = gSecondLife + std::string(" ") + gArgs; + gWindowTitle += std::string(" ") + gArgs; #endif LLStringUtil::truncate(gWindowTitle, 255); @@ -1997,11 +2123,7 @@ bool LLAppViewer::initConfiguration() if (mSecondInstance) { std::ostringstream msg; - msg << - gSecondLife << " is already running.\n" - "\n" - "Check your task bar for a minimized copy of the program.\n" - "If this message persists, restart your computer.", + msg << LLTrans::getString("MBAlreadyRunning"); OSMessageBox( msg.str(), LLStringUtil::null, @@ -2046,6 +2168,8 @@ bool LLAppViewer::initConfiguration() gLastRunVersion = gSavedSettings.getString("LastRunVersion"); + loadColorSettings(); + return true; // Config was successful. } @@ -2074,12 +2198,8 @@ void LLAppViewer::checkForCrash(void) if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_ASK) { std::ostringstream msg; - msg << gSecondLife - << " appears to have frozen or crashed on the previous run.\n" - << "Would you like to send a crash report?"; - std::string alert; - alert = gSecondLife; - alert += " Alert"; + msg << LLTrans::getString("MBFrozenCrashed"); + std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert"); choice = OSMessageBox(msg.str(), alert, OSMB_YESNO); @@ -2127,10 +2247,10 @@ bool LLAppViewer::initWindow() gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"), FALSE, ignorePixelDepth); - if (gSavedSettings.getBOOL("FullScreen")) + if (gSavedSettings.getBOOL("WindowFullScreen")) { + // request to go full screen... which will be delayed until login gViewerWindow->toggleFullscreen(FALSE); - // request to go full screen... which will be delayed until login } if (gSavedSettings.getBOOL("WindowMaximized")) @@ -2145,6 +2265,11 @@ bool LLAppViewer::initWindow() // Initialize GL stuff // + if (mForceGraphicsDetail) + { + LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false); + } + // Set this flag in case we crash while initializing GL gSavedSettings.setBOOL("RenderInitError", TRUE); gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); @@ -2165,9 +2290,6 @@ bool LLAppViewer::initWindow() LLUI::sWindow = gViewerWindow->getWindow(); - LLTrans::parseStrings("strings.xml"); - LLUITrans::parseStrings("ui_strings.xml"); - // Show watch cursor gViewerWindow->setCursor(UI_CURSOR_WAIT); @@ -2287,7 +2409,7 @@ void LLAppViewer::writeSystemInfo() gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true; // Dump some debugging info - LL_INFOS("SystemInfo") << gSecondLife + LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME") << " version " << LL_VERSION_MAJOR << "." << LL_VERSION_MINOR << "." << LL_VERSION_PATCH << LL_ENDL; @@ -2365,7 +2487,7 @@ void LLAppViewer::handleViewerCrash() gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath(); gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds()); gDebugInfo["StartupState"] = LLStartUp::getStartupStateString(); - gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) getCurrentRSS() >> 10; + gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10; gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin(); gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall"); @@ -2776,12 +2898,14 @@ bool LLAppViewer::initCache() gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")); purgeCache(); // purge old cache gSavedSettings.setString("CacheLocation", new_cache_location); + gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location)); } if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"))) { LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL; gSavedSettings.setString("CacheLocation", ""); + gSavedSettings.setString("CacheLocationTopFolder", ""); } if (mPurgeCache) @@ -2961,12 +3085,12 @@ void LLAppViewer::purgeCache() gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask); } -const std::string& LLAppViewer::getSecondLifeTitle() const +std::string LLAppViewer::getSecondLifeTitle() const { - return gSecondLife; + return LLTrans::getString("APP_NAME"); } -const std::string& LLAppViewer::getWindowTitle() const +std::string LLAppViewer::getWindowTitle() const { return gWindowTitle; } @@ -3000,7 +3124,7 @@ void LLAppViewer::forceDisconnect(const std::string& mesg) return; } - // Translate the message if possible + // *TODO: Translate the message if possible std::string big_reason = LLAgent::sTeleportErrorMessages[mesg]; if ( big_reason.size() == 0 ) { @@ -3128,6 +3252,15 @@ public: } }; +static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio"); +static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup"); +static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks"); +static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD"); +static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist"); +static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region"); +static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World"); +static LLFastTimer::DeclareTimer FTM_NETWORK("Network"); + /////////////////////////////////////////////////////// // idle() // @@ -3136,6 +3269,7 @@ public: /////////////////////////////////////////////////////// void LLAppViewer::idle() { + LLMemType mt_idle(LLMemType::MTYPE_IDLE); pingMainloopTimeout("Main:Idle"); // Update frame timers @@ -3179,7 +3313,6 @@ void LLAppViewer::idle() // // Special case idle if still starting up // - if (LLStartUp::getStartupState() < STATE_STARTED) { // Skip rest if idle startup returns false (essentially, no world yet) @@ -3194,7 +3327,7 @@ void LLAppViewer::idle() if (!gDisconnected) { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); // Update spaceserver timeinfo LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC)); @@ -3219,7 +3352,7 @@ void LLAppViewer::idle() // When appropriate, update agent location to the simulator. F32 agent_update_time = agent_update_timer.getElapsedTimeF32(); BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags()); - + if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND))) { // Send avatar and camera info @@ -3234,7 +3367,6 @@ void LLAppViewer::idle() // Manage statistics // // - { // Initialize the viewer_stats_timer with an already elapsed time // of SEND_STATS_PERIOD so that the initial stats report will @@ -3272,12 +3404,11 @@ void LLAppViewer::idle() gObjectList.mNumUnknownUpdates = 0; } } - gFrameStats.addFrameData(); } - + if (!gDisconnected) { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); //////////////////////////////////////////////// // @@ -3287,12 +3418,10 @@ void LLAppViewer::idle() // floating throughout the various object lists. // - gFrameStats.start(LLFrameStats::IDLE_NETWORK); stop_glerror(); idleNetwork(); stop_glerror(); - gFrameStats.start(LLFrameStats::AGENT_MISC); // Check for away from keyboard, kick idle agents. idle_afk_check(); @@ -3308,7 +3437,7 @@ void LLAppViewer::idle() // { -// LLFastTimer t(LLFastTimer::FTM_IDLE_CB); +// LLFastTimer t(FTM_IDLE_CB); // Do event notifications if necessary. Yes, we may want to move this elsewhere. gEventNotifier.update(); @@ -3321,7 +3450,7 @@ void LLAppViewer::idle() return; } - gViewerWindow->handlePerFrameHover(); + gViewerWindow->updateUI(); /////////////////////////////////////// // Agent and camera movement @@ -3337,14 +3466,13 @@ void LLAppViewer::idle() { // Handle pending gesture processing - gGestureManager.update(); + LLGestureManager::instance().update(); gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY); } { - LLFastTimer t(LLFastTimer::FTM_OBJECTLIST_UPDATE); // Actually "object update" - gFrameStats.start(LLFrameStats::OBJECT_UPDATE); + LLFastTimer t(FTM_OBJECTLIST_UPDATE); // Actually "object update" if (!(logoutRequestSent() && hasSavedFinalSnapshot())) { @@ -3359,8 +3487,7 @@ void LLAppViewer::idle() // { - LLFastTimer t(LLFastTimer::FTM_CLEANUP); - gFrameStats.start(LLFrameStats::CLEAN_DEAD); + LLFastTimer t(FTM_CLEANUP); gObjectList.cleanDeadObjects(); LLDrawable::cleanupDeadDrawables(); } @@ -3379,7 +3506,6 @@ void LLAppViewer::idle() // { - gFrameStats.start(LLFrameStats::UPDATE_EFFECTS); LLSelectMgr::getInstance()->updateEffects(); LLHUDManager::getInstance()->cleanupEffects(); LLHUDManager::getInstance()->sendEffects(); @@ -3393,7 +3519,7 @@ void LLAppViewer::idle() // { - LLFastTimer t(LLFastTimer::FTM_NETWORK); + LLFastTimer t(FTM_NETWORK); gVLManager.unpackData(); } @@ -3405,7 +3531,7 @@ void LLAppViewer::idle() LLWorld::getInstance()->updateVisibilities(); { const F32 max_region_update_time = .001f; // 1ms - LLFastTimer t(LLFastTimer::FTM_REGION_UPDATE); + LLFastTimer t(FTM_REGION_UPDATE); LLWorld::getInstance()->updateRegions(max_region_update_time); } @@ -3452,11 +3578,9 @@ void LLAppViewer::idle() if (!gNoRender) { - LLFastTimer t(LLFastTimer::FTM_WORLD_UPDATE); - gFrameStats.start(LLFrameStats::UPDATE_MOVE); + LLFastTimer t(FTM_WORLD_UPDATE); gPipeline.updateMove(); - gFrameStats.start(LLFrameStats::UPDATE_PARTICLES); LLWorld::getInstance()->updateParticles(); } stop_glerror(); @@ -3475,15 +3599,17 @@ void LLAppViewer::idle() gAgent.updateCamera(); } + // update media focus + LLViewerMediaFocus::getInstance()->update(); + // objects and camera should be in sync, do LOD calculations now { - LLFastTimer t(LLFastTimer::FTM_LOD_UPDATE); + LLFastTimer t(FTM_LOD_UPDATE); gObjectList.updateApparentAngles(gAgent); } { - gFrameStats.start(LLFrameStats::AUDIO); - LLFastTimer t(LLFastTimer::FTM_AUDIO_UPDATE); + LLFastTimer t(FTM_AUDIO_UPDATE); if (gAudiop) { @@ -3623,8 +3749,11 @@ void LLAppViewer::sendLogoutRequest() static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME; #endif +static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Network"); + void LLAppViewer::idleNetwork() { + LLMemType mt_in(LLMemType::MTYPE_IDLE_NETWORK); pingMainloopTimeout("idleNetwork"); LLError::LLCallStacks::clear() ; llpushcallstacks ; @@ -3634,7 +3763,7 @@ void LLAppViewer::idleNetwork() if (!gSavedSettings.getBOOL("SpeedTest")) { - LLFastTimer t(LLFastTimer::FTM_IDLE_NETWORK); // decode + LLFastTimer t(FTM_IDLE_NETWORK); // decode // deal with any queued name requests and replies. gCacheName->processPending(); @@ -3644,7 +3773,8 @@ void LLAppViewer::idleNetwork() stop_glerror(); const S64 frame_count = gFrameCount; // U32->S64 F32 total_time = 0.0f; - while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) + + while (gMessageSystem->checkAllMessages(frame_count, gServicePump)) { if (gDoDisconnect) { @@ -3673,6 +3803,7 @@ void LLAppViewer::idleNetwork() break; #endif } + // Handle per-frame message system processing. gMessageSystem->processAcks(); @@ -3711,7 +3842,7 @@ void LLAppViewer::idleNetwork() } } llpushcallstacks ; - gObjectList.mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects); + LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects); // Retransmit unacknowledged packets. gXferManager->retransmitUnackedPackets(); @@ -3752,7 +3883,6 @@ void LLAppViewer::disconnectViewer() llinfos << "Disconnecting viewer!" << llendl; // Dump our frame statistics - gFrameStats.dump(); // Remember if we were flying gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() ); @@ -3764,35 +3894,6 @@ void LLAppViewer::disconnectViewer() { gFloaterView->restoreAll(); } - - - std::list floaters_to_close; - for(LLView::child_list_const_iter_t it = gFloaterView->getChildList()->begin(); - it != gFloaterView->getChildList()->end(); - ++it) - { - // The following names are defined in the - // floater_image_preview.xml - // floater_sound_preview.xml - // floater_animation_preview.xml - // files. - LLFloater* fl = static_cast(*it); - if(fl - && (fl->getName() == "Image Preview" - || fl->getName() == "Sound Preview" - || fl->getName() == "Animation Preview" - )) - { - floaters_to_close.push_back(fl); - } - } - - while(!floaters_to_close.empty()) - { - LLFloater* fl = floaters_to_close.front(); - floaters_to_close.pop_front(); - fl->close(); - } } if (LLSelectMgr::getInstance()) @@ -3800,20 +3901,22 @@ void LLAppViewer::disconnectViewer() LLSelectMgr::getInstance()->deselectAll(); } - if (!gNoRender) + // save inventory if appropriate + gInventory.cache(gInventory.getRootFolderID(), gAgent.getID()); + if (gInventory.getLibraryRootFolderID().notNull() + && gInventory.getLibraryOwnerID().notNull()) { - // save inventory if appropriate - gInventory.cache(gAgent.getInventoryRootID(), gAgent.getID()); - if(gInventoryLibraryRoot.notNull() && gInventoryLibraryOwner.notNull()) - { - gInventory.cache(gInventoryLibraryRoot, gInventoryLibraryOwner); - } + gInventory.cache( + gInventory.getLibraryRootFolderID(), + gInventory.getLibraryOwnerID()); } saveNameCache(); // close inventory interface, close all windows - LLInventoryView::cleanup(); + LLFloaterInventory::cleanup(); + + gAgentWearables.cleanup(); // Also writes cached agent settings to gSavedSettings gAgent.cleanup(); @@ -3965,5 +4068,8 @@ void LLAppViewer::handleLoginComplete() { gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState(); } + + mOnLoginCompleted(); + writeDebugInfo(); } diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h index a3b84759f5..646b677264 100644 --- a/indra/newview/llappviewer.h +++ b/indra/newview/llappviewer.h @@ -33,11 +33,20 @@ #ifndef LL_LLAPPVIEWER_H #define LL_LLAPPVIEWER_H -class LLTextureCache; -class LLWorkerThread; -class LLTextureFetch; -class LLWatchdogTimeout; +#include "llallocator.h" +#include "llcontrol.h" +#include "llsys.h" // for LLOSInfo + class LLCommandLineParser; +class LLFrameTimer; +class LLPumpIO; +class LLTextureCache; +class LLTextureFetch; +class LLTimer; +class LLVFS; +class LLWatchdogTimeout; +class LLWorkerThread; + class LLAppViewer : public LLApp { @@ -96,8 +105,8 @@ public: bool getPurgeCache() const { return mPurgeCache; } - const std::string& getSecondLifeTitle() const; // The Second Life title. - const std::string& getWindowTitle() const; // The window display name. + std::string getSecondLifeTitle() const; // The Second Life title. + std::string getWindowTitle() const; // The window display name. void forceDisconnect(const std::string& msg); // Force disconnection, with a message to the user. void badNetworkHandler(); // Cause a crash state due to bad network packet. @@ -119,14 +128,13 @@ public: virtual void forceErrorSoftwareException(); virtual void forceErrorDriverCrash(); - // *NOTE: There are currently 3 settings files: - // "Global", "PerAccount" and "CrashSettings" // The list is found in app_settings/settings_files.xml // but since they are used explicitly in code, // the follow consts should also do the trick. static const std::string sGlobalSettingsName; - static const std::string sPerAccountSettingsName; - static const std::string sCrashSettingsName; + + LLCachedControl mRandomizeFramerate; + LLCachedControl mPeriodicSlowFrame; // Load settings from the location specified by loction_key. // Key availale and rules for loading, are specified in @@ -136,6 +144,7 @@ public: std::string getSettingsFilename(const std::string& location_key, const std::string& file); + void loadColorSettings(); // For thread debugging. // llstartup needs to control init. @@ -150,6 +159,15 @@ public: // *NOTE:Mani Fix this for login abstraction!! void handleLoginComplete(); + LLAllocator & getAllocator() { return mAlloc; } + + // On LoginCompleted callback + typedef boost::signals2::signal login_completed_signal_t; + login_completed_signal_t mOnLoginCompleted; + boost::signals2::connection setOnLoginCompletedCallback( const login_completed_signal_t::slot_type& cb ) { return mOnLoginCompleted.connect(cb); } + + void purgeCache(); // Clear the local cache. + protected: virtual bool initWindow(); // Initialize the viewer's window. virtual bool initLogging(); // Initialize log files, logging system, return false on failure. @@ -171,7 +189,7 @@ private: void initGridChoice(); bool initCache(); // Initialize local client cache. - void purgeCache(); // Clear the local cache. + // We have switched locations of both Mac and Windows cache, make sure // files migrate and old cache is cleared out. @@ -221,6 +239,8 @@ private: bool mSavedFinalSnapshot; + bool mForceGraphicsDetail; + bool mQuitRequested; // User wants to quit, may have modified documents open. bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim. S32 mYieldTime; @@ -228,10 +248,13 @@ private: LLWatchdogTimeout* mMainloopTimeout; + LLThread* mFastTimerLogThread; // for tracking viewer<->region circuit death bool mAgentRegionLastAlive; LLUUID mAgentRegionLastID; + LLAllocator mAlloc; + public: //some information for updater typedef struct @@ -297,9 +320,6 @@ extern LLTimer gLogoutTimer; extern F32 gSimLastTime; extern F32 gSimFrames; -extern LLUUID gInventoryLibraryOwner; -extern LLUUID gInventoryLibraryRoot; - extern BOOL gDisconnected; // Map scale in pixels per region diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index d02e86a557..ed291c16a8 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -451,7 +451,7 @@ gboolean viewer_app_api_GoSLURL(ViewerAppAPI *obj, gchar *slurl, gboolean **succ llinfos << "Was asked to go to slurl: " << slurl << llendl; std::string url = slurl; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; if (LLURLDispatcher::dispatch(url, web, trusted_browser)) { @@ -553,7 +553,7 @@ void LLAppViewerLinux::handleSyncCrashTrace() void LLAppViewerLinux::handleCrashReporting(bool reportFreeze) { - std::string cmd =gDirUtilp->getAppRODataDir(); + std::string cmd =gDirUtilp->getExecutableDir(); cmd += gDirUtilp->getDirDelimiter(); #if LL_LINUX cmd += "linux-crash-logger.bin"; diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index 080bd2edc0..2b3939d92f 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -50,7 +50,7 @@ #include #include "lldir.h" #include -class LLWebBrowserCtrl; // for LLURLDispatcher +class LLMediaCtrl; // for LLURLDispatcher namespace { @@ -188,7 +188,7 @@ bool LLAppViewerMacOSX::initParseCommandLine(LLCommandLineParser& clp) // in the "General" tab, click the "Add Localization" button // create a new localization for the language you're adding // set the contents of the new localization of the file to the string corresponding to our localization - // (i.e. "en-us", "ja", etc. Use the existing ones as a guide.) + // (i.e. "en", "ja", etc. Use the existing ones as a guide.) CFURLRef url = CFBundleCopyResourceURL(CFBundleGetMainBundle(), CFSTR("language"), CFSTR("txt"), NULL); char path[MAX_PATH]; if(CFURLGetFileSystemRepresentation(url, false, (UInt8 *)path, sizeof(path))) @@ -476,7 +476,7 @@ OSErr AEGURLHandler(const AppleEvent *messagein, AppleEvent *reply, long refIn) url.replace(0, prefix.length(), "secondlife:///app/"); } - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(url, web, trusted_browser); } diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 7a8d486b72..98d7ab712b 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -64,6 +64,7 @@ #include "llfindlocale.h" #include "llcommandlineparser.h" +#include "lltrans.h" // *FIX:Mani - This hack is to fix a linker issue with libndofdev.lib // The lib was compiled under VS2005 - in VS2003 we need to remap assert @@ -84,7 +85,7 @@ LONG WINAPI viewer_windows_exception_handler(struct _EXCEPTION_POINTERS *excepti { // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); - // Translate the signals/exceptions into cross-platform stuff + // *TODO: Translate the signals/exceptions into cross-platform stuff // Windows implementation _tprintf( _T("Entering Windows Exception Handler...\n") ); llinfos << "Entering Windows Exception Handler..." << llendl; @@ -444,33 +445,24 @@ bool LLAppViewerWin32::initHardwareTest() // but vram. vram_only = TRUE; - LLSplashScreen::update("Detecting hardware..."); + LLSplashScreen::update(LLTrans::getString("StartupDetectingHardware")); LL_DEBUGS("AppInit") << "Attempting to poll DirectX for hardware info" << LL_ENDL; gDXHardware.setWriteDebugFunc(write_debug_dx); BOOL probe_ok = gDXHardware.getInfo(vram_only); if (!probe_ok - && gSavedSettings.getWarning("AboutDirectX9")) + && gWarningSettings.getBOOL("AboutDirectX9")) { LL_WARNS("AppInit") << "DirectX probe failed, alerting user." << LL_ENDL; // Warn them that runnin without DirectX 9 will // not allow us to tell them about driver issues std::ostringstream msg; - msg << - LLAppViewer::instance()->getSecondLifeTitle() << " is unable to detect DirectX 9.0b or greater.\n" - "\n" << - LLAppViewer::instance()->getSecondLifeTitle() << " uses DirectX to detect hardware and/or\n" - "outdated drivers that can cause stability problems,\n" - "poor performance and crashes. While you can run\n" << - LLAppViewer::instance()->getSecondLifeTitle() << " without it, we highly recommend running\n" - "with DirectX 9.0b\n" - "\n" - "Do you wish to continue?\n"; + msg << LLTrans::getString ("MBNoDirectX"); S32 button = OSMessageBox( msg.str(), - "Warning", + LLTrans::getString("MBWarning"), OSMB_YESNO); if (OSBTN_NO== button) { @@ -478,7 +470,7 @@ bool LLAppViewerWin32::initHardwareTest() LLWeb::loadURLExternal(DIRECTX_9_URL); return false; } - gSavedSettings.setWarning("AboutDirectX9", FALSE); + gWarningSettings.setBOOL("AboutDirectX9", FALSE); } LL_DEBUGS("AppInit") << "Done polling DirectX for hardware info" << LL_ENDL; @@ -487,7 +479,7 @@ bool LLAppViewerWin32::initHardwareTest() // Disable so debugger can work std::ostringstream splash_msg; - splash_msg << "Loading " << LLAppViewer::instance()->getSecondLifeTitle() << "..."; + splash_msg << LLTrans::getString("StartupLoading") << " " << LLAppViewer::instance()->getSecondLifeTitle() << "..."; LLSplashScreen::update(splash_msg.str()); } diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 4fca9b1f19..827ae5855b 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -41,7 +41,7 @@ #include "llfilepicker.h" #include "llnotify.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llpermissionsflags.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" @@ -58,10 +58,13 @@ #include "lltexlayer.h" // library includes +#include "lldir.h" #include "lleconomy.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llscrolllistctrl.h" #include "llsdserialize.h" +#include "llvfs.h" // When uploading multiple files, don't display any of them when uploading more than this number. static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5; @@ -282,19 +285,20 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) // Show the preview panel for textures and sounds to let // user know that the image (or snapshot) arrived intact. - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); if(view) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus = gFocusMgr.getKeyboardFocus(); + view->getPanel()->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO); if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type) && LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD) { view->getPanel()->openSelected(); } - //LLInventoryView::dumpSelectionInformation((void*)view); + //LLFloaterInventory::dumpSelectionInformation((void*)view); // restore keyboard focus - gFocusMgr.setKeyboardFocus(focus_ctrl); + gFocusMgr.setKeyboardFocus(focus); } } else @@ -337,11 +341,11 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content) } LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data, - const LLUUID& vfile_id, - LLAssetType::EType asset_type, - LLBakedUploadData * baked_upload_data) - : LLAssetUploadResponder(post_data, vfile_id, asset_type), - mBakedUploadData(baked_upload_data) + const LLUUID& vfile_id, + LLAssetType::EType asset_type, + LLBakedUploadData * baked_upload_data) : + LLAssetUploadResponder(post_data, vfile_id, asset_type), + mBakedUploadData(baked_upload_data) { } @@ -419,72 +423,68 @@ void LLUpdateAgentInventoryResponder::uploadComplete(const LLSD& content) LLInventoryType::EType inventory_type = new_item->getInventoryType(); switch(inventory_type) { - case LLInventoryType::IT_NOTECARD: - { + case LLInventoryType::IT_NOTECARD: + { + // Update the UI with the new asset. + LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance("preview_notecard", LLSD(item_id)); + if(nc) + { + // *HACK: we have to delete the asset in the VFS so + // that the viewer will redownload it. This is only + // really necessary if the asset had to be modified by + // the uploader, so this can be optimized away in some + // cases. A better design is to have a new uuid if the + // script actually changed the asset. + if(nc->hasEmbeddedInventory()) + { + gVFS->removeFile(content["new_asset"].asUUID(), LLAssetType::AT_NOTECARD); + } + nc->refreshFromInventory(new_item->getUUID()); + } + break; + } + case LLInventoryType::IT_LSL: + { + // Find our window and close it if requested. + LLPreviewLSL* preview = LLFloaterReg::findTypedInstance("preview_script", LLSD(item_id)); + if (preview) + { + // Bytecode save completed + if (content["compiled"]) + { + preview->callbackLSLCompileSucceeded(); + } + else + { + preview->callbackLSLCompileFailed(content["errors"]); + } + } + break; + } - // Update the UI with the new asset. - LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(new_item->getUUID()); - if(nc) - { - // *HACK: we have to delete the asset in the VFS so - // that the viewer will redownload it. This is only - // really necessary if the asset had to be modified by - // the uploader, so this can be optimized away in some - // cases. A better design is to have a new uuid if the - // script actually changed the asset. - if(nc->hasEmbeddedInventory()) - { - gVFS->removeFile( - content["new_asset"].asUUID(), - LLAssetType::AT_NOTECARD); - } - nc->refreshFromInventory(); - } - } - break; - case LLInventoryType::IT_LSL: - { - // Find our window and close it if requested. - LLPreviewLSL* preview = (LLPreviewLSL*)LLPreview::find(item_id); - if (preview) - { - // Bytecode save completed - if (content["compiled"]) - { - preview->callbackLSLCompileSucceeded(); - } - else - { - preview->callbackLSLCompileFailed(content["errors"]); - } - } - } - break; + case LLInventoryType::IT_GESTURE: + { + // If this gesture is active, then we need to update the in-memory + // active map with the new pointer. + if (LLGestureManager::instance().isGestureActive(item_id)) + { + LLUUID asset_id = new_item->getAssetUUID(); + LLGestureManager::instance().replaceGesture(item_id, asset_id); + gInventory.notifyObservers(); + } - case LLInventoryType::IT_GESTURE: - { - // If this gesture is active, then we need to update the in-memory - // active map with the new pointer. - if (gGestureManager.isGestureActive(item_id)) - { - LLUUID asset_id = new_item->getAssetUUID(); - gGestureManager.replaceGesture(item_id, asset_id); - gInventory.notifyObservers(); - } - - //gesture will have a new asset_id - LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id); - if(previewp) - { - previewp->onUpdateSucceeded(); - } + //gesture will have a new asset_id + LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance("preview_gesture", LLSD(item_id)); + if(previewp) + { + previewp->onUpdateSucceeded(); + } - } - break; - case LLInventoryType::IT_WEARABLE: - default: - break; + break; + } + case LLInventoryType::IT_WEARABLE: + default: + break; } } @@ -522,64 +522,57 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content) switch(mAssetType) { - case LLAssetType::AT_NOTECARD: - { + case LLAssetType::AT_NOTECARD: + { + // Update the UI with the new asset. + LLPreviewNotecard* nc = LLFloaterReg::findTypedInstance("preview_notecard", LLSD(item_id)); + if(nc) + { + // *HACK: we have to delete the asset in the VFS so + // that the viewer will redownload it. This is only + // really necessary if the asset had to be modified by + // the uploader, so this can be optimized away in some + // cases. A better design is to have a new uuid if the + // script actually changed the asset. + if(nc->hasEmbeddedInventory()) + { + gVFS->removeFile(content["new_asset"].asUUID(), + LLAssetType::AT_NOTECARD); + } - // Update the UI with the new asset. - LLPreviewNotecard* nc; - nc = (LLPreviewNotecard*)LLPreview::find(item_id); - if(nc) - { - // *HACK: we have to delete the asset in the VFS so - // that the viewer will redownload it. This is only - // really necessary if the asset had to be modified by - // the uploader, so this can be optimized away in some - // cases. A better design is to have a new uuid if the - // script actually changed the asset. - if(nc->hasEmbeddedInventory()) - { - gVFS->removeFile( - content["new_asset"].asUUID(), - LLAssetType::AT_NOTECARD); - } - - nc->refreshFromInventory(); - } - } - break; - case LLAssetType::AT_LSL_TEXT: - { - if(mQueueId.notNull()) - { - LLFloaterCompileQueue* queue = - (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - if(NULL != queue) - { - queue->removeItemByItemID(item_id); - } - } - else - { - LLLiveLSLEditor* preview = LLLiveLSLEditor::find(item_id, task_id); - if (preview) - { - // Bytecode save completed - if (content["compiled"]) - { - preview->callbackLSLCompileSucceeded( - task_id, - item_id, - mPostData["is_script_running"]); - } - else - { - preview->callbackLSLCompileFailed(content["errors"]); - } - } - } - } - break; - default: + nc->refreshFromInventory(); + } + break; + } + case LLAssetType::AT_LSL_TEXT: + { + if(mQueueId.notNull()) + { + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", mQueueId); + if(NULL != queue) + { + queue->removeItemByItemID(item_id); + } + } + else + { + LLLiveLSLEditor* preview = LLFloaterReg::findTypedInstance("preview_scriptedit", LLSD(item_id)); + if (preview) + { + // Bytecode save completed + if (content["compiled"]) + { + preview->callbackLSLCompileSucceeded(task_id, item_id, mPostData["is_script_running"]); + } + else + { + preview->callbackLSLCompileFailed(content["errors"]); + } + } + } + break; + } + default: break; } } diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h index 9ab571ae99..a08d70213c 100644 --- a/indra/newview/llassetuploadresponders.h +++ b/indra/newview/llassetuploadresponders.h @@ -47,6 +47,7 @@ public: const std::string& file_name, LLAssetType::EType asset_type); ~LLAssetUploadResponder(); + virtual void error(U32 statusNum, const std::string& reason); virtual void result(const LLSD& content); virtual void uploadUpload(const LLSD& content); diff --git a/indra/newview/llaudiosourcevo.h b/indra/newview/llaudiosourcevo.h index e7bb2837a4..4b70f8bc20 100644 --- a/indra/newview/llaudiosourcevo.h +++ b/indra/newview/llaudiosourcevo.h @@ -34,7 +34,7 @@ #ifndef LL_LLAUDIOSOURCEVO_H #define LL_LLAUDIOSOURCEVO_H -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewerobject.h" class LLViewerObject; diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp new file mode 100644 index 0000000000..5f71b6e3f6 --- /dev/null +++ b/indra/newview/llavataractions.cpp @@ -0,0 +1,291 @@ +/** + * @file llavataractions.cpp + * @brief Friend-related actions (add, remove, offer teleport, etc) + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llavataractions.h" + +#include "llsd.h" +#include "lldarray.h" +#include "llnotifications.h" + +#include "llagent.h" +#include "llappviewer.h" // for gLastVersionChannel +#include "llcallingcard.h" // for LLAvatarTracker +#include "llinventorymodel.h" // for gInventory.findCategoryUUIDForType +#include "llimview.h" // for gIMMgr +#include "llsidetray.h" +#include "llviewermessage.h" // for handle_lure +#include "llviewerregion.h" + + +// static +void LLAvatarActions::requestFriendshipDialog(const LLUUID& id, const std::string& name) +{ + if(id == gAgentID) + { + LLNotifications::instance().add("AddSelfFriend"); + return; + } + + LLSD args; + args["NAME"] = name; + LLSD payload; + payload["id"] = id; + payload["name"] = name; + // Look for server versions like: Second Life Server 1.24.4.95600 + if (gLastVersionChannel.find(" 1.24.") != std::string::npos) + { + // Old and busted server version, doesn't support friend + // requests with messages. + LLNotifications::instance().add("AddFriend", args, payload, &callbackAddFriend); + } + else + { + LLNotifications::instance().add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage); + } + + // add friend to recent people list + LLRecentPeople::instance().add(id); +} + +// static +void LLAvatarActions::requestFriendshipDialog(const LLUUID& id) +{ + if(id.isNull()) + { + return; + } + + std::string full_name; + gCacheName->getFullName(id, full_name); + requestFriendshipDialog(id, full_name); +} + +// static +void LLAvatarActions::removeFriendDialog(const LLUUID& id) +{ + if (id.isNull()) + return; + + std::vector ids; + ids.push_back(id); + removeFriendsDialog(ids); +} + +// static +void LLAvatarActions::removeFriendsDialog(const std::vector& ids) +{ + if(ids.size() == 0) + return; + + LLSD args; + std::string msgType; + if(ids.size() == 1) + { + LLUUID agent_id = ids[0]; + std::string first, last; + if(gCacheName->getName(agent_id, first, last)) + { + args["FIRST_NAME"] = first; + args["LAST_NAME"] = last; + } + + msgType = "RemoveFromFriends"; + } + else + { + msgType = "RemoveMultipleFromFriends"; + } + + LLSD payload; + for (std::vector::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + payload["ids"].append(*it); + } + + LLNotifications::instance().add(msgType, + args, + payload, + &handleRemove); +} + +// static +void LLAvatarActions::offerTeleport(const LLUUID& invitee) +{ + if (invitee.isNull()) + return; + + LLDynamicArray ids; + ids.push_back(invitee); + offerTeleport(ids); +} + +// static +void LLAvatarActions::offerTeleport(const std::vector& ids) +{ + if (ids.size() > 0) + handle_lure(ids); +} + +// static +void LLAvatarActions::startIM(const LLUUID& id) +{ + if (id.isNull()) + return; + + std::string name; + gCacheName->getFullName(id, name); + gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id); + make_ui_sound("UISndStartIM"); +} + +// static +void LLAvatarActions::startConference(const std::vector& ids) +{ + // *HACK: Copy into dynamic array + LLDynamicArray id_array; + for (std::vector::const_iterator it = ids.begin(); it != ids.end(); ++it) + { + id_array.push_back(*it); + } + gIMMgr->addSession("Friends Conference", IM_SESSION_CONFERENCE_START, ids[0], id_array); + make_ui_sound("UISndStartIM"); +} + +// static +void LLAvatarActions::showProfile(const LLUUID& id) +{ + if (id.notNull()) + { + LLSD params; + params["id"] = id; + params["open_tab_name"] = "panel_profile"; + + //Show own profile + if(gAgent.getID() == id) + { + LLSideTray::getInstance()->showPanel("panel_me_profile", params); + } + //Show other user profile + else + { + LLSideTray::getInstance()->showPanel("panel_profile_view", params); + } + } +} + +//== private methods ======================================================================================== + +// static +bool LLAvatarActions::handleRemove(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + const LLSD& ids = notification["payload"]["ids"]; + for (LLSD::array_const_iterator itr = ids.beginArray(); itr != ids.endArray(); ++itr) + { + LLUUID id = itr->asUUID(); + const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id); + if (ip) + { + switch (option) + { + case 0: // YES + if( ip->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS)) + { + LLAvatarTracker::instance().empower(id, FALSE); + LLAvatarTracker::instance().notifyObservers(); + } + LLAvatarTracker::instance().terminateBuddy(id); + LLAvatarTracker::instance().notifyObservers(); + break; + + case 1: // NO + default: + llinfos << "No removal performed." << llendl; + break; + } + } + } + return false; +} + +// static +bool LLAvatarActions::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + requestFriendship(notification["payload"]["id"].asUUID(), + notification["payload"]["name"].asString(), + response["message"].asString()); + } + return false; +} + +// static +bool LLAvatarActions::callbackAddFriend(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + // Servers older than 1.25 require the text of the message to be the + // calling card folder ID for the offering user. JC + LLUUID calling_card_folder_id = + gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + std::string message = calling_card_folder_id.asString(); + requestFriendship(notification["payload"]["id"].asUUID(), + notification["payload"]["name"].asString(), + message); + } + return false; +} + +// static +void LLAvatarActions::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message) +{ + LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + send_improved_im(target_id, + target_name, + message, + IM_ONLINE, + IM_FRIENDSHIP_OFFERED, + calling_card_folder_id); +} + +//static +bool LLAvatarActions::isFriend(const LLUUID& id) +{ + return ( NULL != LLAvatarTracker::instance().getBuddyInfo(id) ); +} diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h new file mode 100644 index 0000000000..f3c411e033 --- /dev/null +++ b/indra/newview/llavataractions.h @@ -0,0 +1,93 @@ +/** + * @file llavataractions.h + * @brief Friend-related actions (add, remove, offer teleport, etc) + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAVATARACTIONS_H +#define LL_LLAVATARACTIONS_H + +/** + * Friend-related actions (add, remove, offer teleport, etc) + */ +class LLAvatarActions +{ +public: + /** + * Show a dialog explaining what friendship entails, then request friendship. + */ + static void requestFriendshipDialog(const LLUUID& id, const std::string& name); + + /** + * Show a dialog explaining what friendship entails, then request friendship. + */ + static void requestFriendshipDialog(const LLUUID& id); + + /** + * Show a friend removal dialog. + */ + static void removeFriendDialog(const LLUUID& id); + static void removeFriendsDialog(const std::vector& ids); + + /** + * Show teleport offer dialog. + */ + static void offerTeleport(const LLUUID& invitee); + static void offerTeleport(const std::vector& ids); + + /** + * Start instant messaging session. + */ + static void startIM(const LLUUID& id); + + /** + * Start conference chat with the given avatars. + */ + static void startConference(const std::vector& ids); + + /** + * Show avatar profile. + */ + static void showProfile(const LLUUID& id); + + /** + * Return true if avatar with "id" is a friend + */ + static bool isFriend(const LLUUID& id); + +private: + static bool callbackAddFriend(const LLSD& notification, const LLSD& response); + static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response); + static bool handleRemove(const LLSD& notification, const LLSD& response); + + // Just request friendship, no dialog. + static void requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message); +}; + +#endif // LL_LLAVATARACTIONS_H diff --git a/indra/newview/llavatariconctrl.cpp b/indra/newview/llavatariconctrl.cpp new file mode 100644 index 0000000000..05addf3f3a --- /dev/null +++ b/indra/newview/llavatariconctrl.cpp @@ -0,0 +1,294 @@ +/** + * @file llavatariconctrl.cpp + * @brief LLAvatarIconCtrl class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llavatarconstants.h" +#include "llavatariconctrl.h" +#include "llcallingcard.h" // for LLAvatarTracker +#include "llavataractions.h" +#include "llimview.h" +#include "llmenugl.h" +#include "lluictrlfactory.h" + +#include "llcachename.h" +#include "llagentdata.h" + +#define MENU_ITEM_VIEW_PROFILE 0 +#define MENU_ITEM_SEND_IM 1 + +static LLDefaultChildRegistry::Register r("avatar_icon"); + +LLAvatarIconCtrl::avatar_image_map_t LLAvatarIconCtrl::sImagesCache; + + +LLAvatarIconCtrl::Params::Params() +: avatar_id("avatar_id"), + draw_tooltip("draw_tooltip", true) +{ + name = "avatar_icon"; +} + + +LLAvatarIconCtrl::LLAvatarIconCtrl(const LLAvatarIconCtrl::Params& p) +: LLIconCtrl(p), + mDrawTooltip(p.draw_tooltip) +{ + LLRect rect = p.rect; + + static LLUICachedControl llavatariconctrl_symbol_hpad("UIAvatariconctrlSymbolHPad", 2); + static LLUICachedControl llavatariconctrl_symbol_vpad("UIAvatariconctrlSymbolVPad", 2); + static LLUICachedControl llavatariconctrl_symbol_size("UIAvatariconctrlSymbolSize", 5); + static LLUICachedControl llavatariconctrl_symbol_pos("UIAvatariconctrlSymbolPosition", "BottomRight"); + + // BottomRight is the default position + S32 left = rect.getWidth() - llavatariconctrl_symbol_size - llavatariconctrl_symbol_hpad; + S32 bottom = llavatariconctrl_symbol_vpad; + + if ("BottomLeft" == (std::string)llavatariconctrl_symbol_pos) + { + left = llavatariconctrl_symbol_hpad; + bottom = llavatariconctrl_symbol_vpad; + } + else if ("TopLeft" == (std::string)llavatariconctrl_symbol_pos) + { + left = llavatariconctrl_symbol_hpad; + bottom = rect.getHeight() - llavatariconctrl_symbol_size - llavatariconctrl_symbol_vpad; + } + else if ("TopRight" == (std::string)llavatariconctrl_symbol_pos) + { + left = rect.getWidth() - llavatariconctrl_symbol_size - llavatariconctrl_symbol_hpad; + bottom = rect.getHeight() - llavatariconctrl_symbol_size - llavatariconctrl_symbol_vpad; + } + + rect.setOriginAndSize(left, bottom, llavatariconctrl_symbol_size, llavatariconctrl_symbol_size); + + LLIconCtrl::Params icparams; + icparams.name ("Status Symbol"); + icparams.follows.flags (FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + icparams.rect (rect); + mStatusSymbol = LLUICtrlFactory::create (icparams); + mStatusSymbol->setValue("circle.tga"); + mStatusSymbol->setColor(LLColor4::grey); + + addChild(mStatusSymbol); + + if (p.avatar_id.isProvided()) + { + LLSD value(p.avatar_id); + setValue(value); + } + else + { + LLIconCtrl::setValue("default_profile_picture.j2c"); + } + + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("AvatarIcon.Action", boost::bind(&LLAvatarIconCtrl::onAvatarIconContextMenuItemClicked, this, _2)); + + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_avatar_icon.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + + mPopupMenuHandle = menu->getHandle(); +} + +LLAvatarIconCtrl::~LLAvatarIconCtrl() +{ + if (mAvatarId.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId, this); + // Name callbacks will be automatically disconnected since LLUICtrl is trackable + } + + LLView::deleteViewByHandle(mPopupMenuHandle); +} + +//virtual +void LLAvatarIconCtrl::setValue(const LLSD& value) +{ + if (value.isUUID()) + { + if (mAvatarId.notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId, this); + } + + if (mAvatarId != value.asUUID()) + { + LLAvatarPropertiesProcessor::getInstance()->addObserver(value.asUUID(), this); + LLAvatarPropertiesProcessor::getInstance()->sendDataRequest(value.asUUID(),APT_PROPERTIES); + mAvatarId = value.asUUID(); + + // Check if cache already contains image_id for that avatar + avatar_image_map_t::iterator it; + + it = sImagesCache.find(mAvatarId); + if (it != sImagesCache.end()) + { + updateFromCache(it->second); + } + } + + } + else + { + LLIconCtrl::setValue(value); + } + + gCacheName->get(mAvatarId, FALSE, boost::bind(&LLAvatarIconCtrl::nameUpdatedCallback, this, _1, _2, _3, _4)); +} + +void LLAvatarIconCtrl::updateFromCache(LLAvatarIconCtrl::LLImagesCacheItem data) +{ + // Update the avatar + if (data.image_id.notNull()) + { + LLIconCtrl::setValue(data.image_id); + } + else + { + LLIconCtrl::setValue("default_profile_picture.j2c"); + } + + // Update color of status symbol and tool tip + if (data.flags & AVATAR_ONLINE) + { + mStatusSymbol->setColor(LLColor4::green); + if (mDrawTooltip) + { + setToolTip((LLStringExplicit)"Online"); + } + } + else + { + mStatusSymbol->setColor(LLColor4::grey); + if (mDrawTooltip) + { + setToolTip((LLStringExplicit)"Offline"); + } + } +} + +//virtual +void LLAvatarIconCtrl::processProperties(void* data, EAvatarProcessorType type) +{ + if (APT_PROPERTIES == type) + { + LLAvatarData* avatar_data = static_cast(data); + if (avatar_data) + { + if (avatar_data->avatar_id != mAvatarId) + { + return; + } + + LLAvatarIconCtrl::LLImagesCacheItem data(avatar_data->image_id, avatar_data->flags); + + updateFromCache(data); + sImagesCache.insert(std::pair(mAvatarId, data)); + } + } +} + +BOOL LLAvatarIconCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + + if(menu) + { + bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarId) != NULL; + + menu->setItemEnabled("Add Friend", !is_friend); + menu->setItemEnabled("Remove Friend", is_friend); + + if(gAgentID == mAvatarId) + { + menu->setItemEnabled("Add Friend", false); + menu->setItemEnabled("Send IM", false); + menu->setItemEnabled("Remove Friend", false); + } + + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + } + + return TRUE; +} + +void LLAvatarIconCtrl::nameUpdatedCallback( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group) +{ + if (id == mAvatarId) + { + mFirstName = first; + mLastName = last; + } +} + +void LLAvatarIconCtrl::onAvatarIconContextMenuItemClicked(const LLSD& userdata) +{ + std::string level = userdata.asString(); + LLUUID id = getAvatarId(); + + if (level == "profile") + { + LLAvatarActions::showProfile(id); + } + else if (level == "im") + { + std::string name; + name.assign(getFirstName()); + name.append(" "); + name.append(getLastName()); + + gIMMgr->addSession(name, IM_NOTHING_SPECIAL, id); + } + else if (level == "add") + { + std::string name; + name.assign(getFirstName()); + name.append(" "); + name.append(getLastName()); + + LLAvatarActions::requestFriendshipDialog(id, name); + } + else if (level == "remove") + { + LLAvatarActions::removeFriendDialog(id); + } +} diff --git a/indra/newview/llavatariconctrl.h b/indra/newview/llavatariconctrl.h new file mode 100644 index 0000000000..49e304a521 --- /dev/null +++ b/indra/newview/llavatariconctrl.h @@ -0,0 +1,100 @@ +/** + * @file llavatariconctrl.h + * @brief LLAvatarIconCtrl base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAVATARICONCTRL_H +#define LL_LLAVATARICONCTRL_H + +#include "lliconctrl.h" +#include "llavatarpropertiesprocessor.h" +#include "llviewermenu.h" + +class LLAvatarIconCtrl +: public LLIconCtrl, public LLAvatarPropertiesObserver +{ +public: + struct Params : public LLInitParam::Block + { + Optional avatar_id; + Optional draw_tooltip; + Params(); + }; + +protected: + LLAvatarIconCtrl(const Params&); + friend class LLUICtrlFactory; + + void onAvatarIconContextMenuItemClicked(const LLSD& userdata); + +public: + virtual ~LLAvatarIconCtrl(); + + virtual void setValue(const LLSD& value); + + // LLAvatarPropertiesProcessor observer trigger + virtual void processProperties(void* data, EAvatarProcessorType type); + + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + void nameUpdatedCallback( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group); + + const LLUUID& getAvatarId() const { return mAvatarId; } + const std::string& getFirstName() const { return mFirstName; } + const std::string& getLastName() const { return mLastName; } + +protected: + LLIconCtrl* mStatusSymbol; + LLUUID mAvatarId; + std::string mFirstName; + std::string mLastName; + LLHandle mPopupMenuHandle; + bool mDrawTooltip; + + struct LLImagesCacheItem + { + LLUUID image_id; + U32 flags; + + LLImagesCacheItem(LLUUID image_id_, U32 flags_) : image_id(image_id_), flags(flags_) {} + }; + + typedef std::map avatar_image_map_t; + + static avatar_image_map_t sImagesCache; + + void updateFromCache(LLAvatarIconCtrl::LLImagesCacheItem data); +}; + +#endif // LL_LLAVATARICONCTRL_H diff --git a/indra/newview/llavatarlist.cpp b/indra/newview/llavatarlist.cpp new file mode 100644 index 0000000000..f557adf6a6 --- /dev/null +++ b/indra/newview/llavatarlist.cpp @@ -0,0 +1,291 @@ +/** + * @file llavatarlist.h + * @brief Generic avatar list + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llavatarlist.h" + +// newview +#include "llcallingcard.h" // for LLAvatarTracker +#include "llcachename.h" +#include "lloutputmonitorctrl.h" +#include "llvoiceclient.h" + +static LLDefaultChildRegistry::Register r("avatar_list"); + +LLAvatarList::Params::Params() +: + volume_column_width("volume_column_width", 0) + , online_go_first("online_go_first", true) +{ + draw_heading = true; + draw_stripes = false; + multi_select = false; + column_padding = 0; + search_column = COL_NAME; + sort_column = COL_NAME; +} + +LLAvatarList::LLAvatarList(const Params& p) +: LLScrollListCtrl(p) + , mHaveVolumeColumn(p.volume_column_width > 0) + , mOnlineGoFirst(p.online_go_first) +{ + setCommitOnSelectionChange(TRUE); // there's no such param in LLScrollListCtrl::Params + + // "volume" column + { + LLScrollListColumn::Params col_params; + col_params.name = "volume"; + col_params.header.label = "Volume"; // *TODO: localize or remove the header + col_params.width.pixel_width = p.volume_column_width; + addColumn(col_params); + } + + // "name" column + { + LLScrollListColumn::Params col_params; + col_params.name = "name"; + col_params.header.label = "Name"; // *TODO: localize or remove the header + col_params.width.dynamic_width = true; + addColumn(col_params); + } + + // "online status" column + { + LLScrollListColumn::Params col_params; + col_params.name = "online"; + col_params.header.label = "Online"; // *TODO: localize or remove the header + col_params.width.pixel_width = 0; // invisible column + addColumn(col_params); + } + + + // invisible "id" column + { + LLScrollListColumn::Params col_params; + col_params.name = "id"; + col_params.header.label = "ID"; // *TODO: localize or remove the header + col_params.width.pixel_width = 0; + addColumn(col_params); + } + + // Primary sort = online status, secondary sort = name + // The corresponding parameters don't work because we create columns dynamically. + sortByColumnIndex(COL_NAME, TRUE); + if (mOnlineGoFirst) + sortByColumnIndex(COL_ONLINE, FALSE); + setSearchColumn(COL_NAME); +} + +// virtual +void LLAvatarList::draw() +{ + LLScrollListCtrl::draw(); + if (mHaveVolumeColumn) + { + updateVolume(); + } +} + +std::vector LLAvatarList::getSelectedIDs() +{ + LLUUID selected_id; + std::vector avatar_ids; + std::vector selected = getAllSelected(); + for(std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) + { + avatar_ids.push_back((*itr)->getUUID()); + } + return avatar_ids; +} + +void LLAvatarList::addItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos) +{ + std::string fullname; + + // Populate list item. + LLSD element; + element["id"] = id; + + // Update volume column (if we have one) + { + std::string icon = mHaveVolumeColumn ? getVolumeIcon(id) : ""; + LLSD& volume_column = element["columns"][COL_VOLUME]; + volume_column["column"] = "volume"; + volume_column["type"] = "icon"; + volume_column["value"] = icon; + } + + LLSD& friend_column = element["columns"][COL_NAME]; + friend_column["column"] = "name"; + friend_column["value"] = name; + + LLSD& online_column = element["columns"][COL_ONLINE]; + online_column["column"] = "online"; + online_column["value"] = is_bold ? "1" : "0"; + + LLScrollListItem* new_itemp = addElement(element, pos); + + // Indicate buddy online status. + // (looks like parsing font parameters from LLSD is broken) + if (is_bold) + { + LLScrollListText* name_textp = dynamic_cast(new_itemp->getColumn(COL_NAME)); + if (name_textp) + name_textp->setFontStyle(LLFontGL::BOLD); + else + { + llwarns << "Name column not found" << llendl; + } + } +} + +static bool findInsensitive(std::string haystack, const std::string& needle_upper) +{ + LLStringUtil::toUpper(haystack); + return haystack.find(needle_upper) != std::string::npos; +} + +BOOL LLAvatarList::update(const std::vector& all_buddies, const std::string& name_filter) +{ + BOOL have_names = TRUE; + + // Save selection. + std::vector selected_ids = getSelectedIDs(); + LLUUID current_id = getCurrentID(); + S32 pos = getScrollPos(); + + std::vector::const_iterator buddy_it = all_buddies.begin(); + deleteAllItems(); + for(; buddy_it != all_buddies.end(); ++buddy_it) + { + std::string name; + const LLUUID& buddy_id = *buddy_it; + have_names &= gCacheName->getFullName(buddy_id, name); + if (name_filter != LLStringUtil::null && !findInsensitive(name, name_filter)) + continue; + addItem(buddy_id, name, LLAvatarTracker::instance().isBuddyOnline(buddy_id)); + } + + // Changed item in place, need to request sort and update columns + // because we might have changed data in a column on which the user + // has already sorted. JC + updateSort(); + + // re-select items + selectMultiple(selected_ids); + setCurrentByID(current_id); +#if 0 + // Restore selection. + if(selected_ids.size() > 0) + { + // only non-null if friends was already found. This may fail, + // but we don't really care here, because refreshUI() will + // clean up the interface. + for(std::vector::iterator itr = selected_ids.begin(); itr != selected_ids.end(); ++itr) + { + setSelectedByValue(*itr, true); + } + } +#endif + setScrollPos(pos); + + return have_names; +} + +// static +std::string LLAvatarList::getVolumeIcon(const LLUUID& id) +{ + // + // Determine icon appropriate for the current avatar volume. + // + // *TODO: remove this in favor of LLOutputMonitorCtrl + // when ListView widget is implemented + // which is capable of containing arbitrary widgets. + // + static LLOutputMonitorCtrl::Params default_monitor_params(LLUICtrlFactory::getDefaultParams()); + bool muted = gVoiceClient->getIsModeratorMuted(id) || gVoiceClient->getOnMuteList(id); + F32 power = gVoiceClient->getCurrentPower(id); + std::string icon; + + if (muted) + { + icon = default_monitor_params.image_mute.name; + } + else if (power == 0.f) + { + icon = default_monitor_params.image_off.name; + } + else if (power < LLVoiceClient::OVERDRIVEN_POWER_LEVEL) + { + S32 icon_image_idx = llmin(2, llfloor((power / LLVoiceClient::OVERDRIVEN_POWER_LEVEL) * 3.f)); + switch(icon_image_idx) + { + default: + case 0: + icon = default_monitor_params.image_on.name; + break; + case 1: + icon = default_monitor_params.image_level_1.name; + break; + case 2: + icon = default_monitor_params.image_level_2.name; + break; + } + } + else + { + // overdriven + icon = default_monitor_params.image_level_3.name; + } + + return icon; +} + +// Update volume column for all list rows. +void LLAvatarList::updateVolume() +{ + item_list& items = getItemList(); + + for (item_list::iterator item_it = items.begin(); + item_it != items.end(); + ++item_it) + { + LLScrollListItem* itemp = (*item_it); + LLUUID speaker_id = itemp->getUUID(); + + LLScrollListCell* icon_cell = itemp->getColumn(COL_VOLUME); + if (icon_cell) + icon_cell->setValue(getVolumeIcon(speaker_id)); + } +} diff --git a/indra/newview/llavatarlist.h b/indra/newview/llavatarlist.h new file mode 100644 index 0000000000..8b419dbb57 --- /dev/null +++ b/indra/newview/llavatarlist.h @@ -0,0 +1,78 @@ +/** + * @file llavatarlist.h + * @brief Generic avatar list + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAVATARLIST_H +#define LL_LLAVATARLIST_H + +#include + +// *TODO: derive from ListView when it's ready. +class LLAvatarList : public LLScrollListCtrl +{ + LOG_CLASS(LLAvatarList); +public: + struct Params : public LLInitParam::Block + { + Optional volume_column_width; + Optional online_go_first; + Params(); + }; + + enum EColumnOrder + { + COL_VOLUME, + COL_NAME, + COL_ONLINE, + COL_ID, + }; + + LLAvatarList(const Params&); + virtual ~LLAvatarList() {} + + /*virtual*/ void draw(); + + BOOL update(const std::vector& all_buddies, + const std::string& name_filter = LLStringUtil::null); + +protected: + std::vector getSelectedIDs(); + void addItem(const LLUUID& id, const std::string& name, BOOL is_bold, EAddPosition pos = ADD_BOTTOM); + +private: + static std::string getVolumeIcon(const LLUUID& id); /// determine volume icon from current avatar volume + void updateVolume(); // update volume for all avatars + + bool mHaveVolumeColumn; + bool mOnlineGoFirst; +}; + +#endif // LL_LLAVATARLIST_H diff --git a/indra/newview/llavatarlistitem.cpp b/indra/newview/llavatarlistitem.cpp new file mode 100644 index 0000000000..253c2ee9a6 --- /dev/null +++ b/indra/newview/llavatarlistitem.cpp @@ -0,0 +1,274 @@ +/** + * @file llavatarlistitem.cpp + * @avatar list item source file + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" +#include "llavatarlistitem.h" +#include "llagent.h" + + + +//--------------------------------------------------------------------------------- +LLAvatarListItem::LLAvatarListItem(const Params& p) : LLPanel() +{ + mNeedsArrange = false; + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_list_item.xml"); + + mStatus = NULL; + mInfo = NULL; + mProfile = NULL; + mInspector = NULL; + + mAvatar = getChild("avatar_icon"); + //mAvatar->setValue(p.avatar_icon); + mName = getChild("name"); + //mName->setText(p.user_name); + + init(p); + + +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::init(const Params& p) +{ + mLocator = getChild("locator"); + + mStatus = getChild("user_status"); + + mInfo = getChild("info_btn"); + mInfo->setVisible(false); + + mProfile = getChild("profile_btn"); + mProfile->setVisible(false); + + if(!p.buttons.locator) + { + mLocator->setVisible(false); + delete mLocator; + mLocator = NULL; + } + + if(!p.buttons.status) + { + mStatus->setVisible(false); + delete mStatus; + mStatus = NULL; + } + + if(!p.buttons.info) + { + delete mInfo; + mInfo = NULL; + } + else + { + mInfo->setClickedCallback(boost::bind(&LLAvatarListItem::onInfoBtnClick, this)); + } + + if(!p.buttons.profile) + { + delete mProfile; + mProfile = NULL; + + LLRect rect; + + rect.setLeftTopAndSize(mName->getRect().mLeft, mName->getRect().mTop, mName->getRect().getWidth() + 30, mName->getRect().getHeight()); + mName->setRect(rect); + + if(mStatus) + { + rect.setLeftTopAndSize(mStatus->getRect().mLeft + 30, mStatus->getRect().mTop, mStatus->getRect().getWidth(), mStatus->getRect().getHeight()); + mStatus->setRect(rect); + } + + if(mLocator) + { + rect.setLeftTopAndSize(mLocator->getRect().mLeft + 30, mLocator->getRect().mTop, mLocator->getRect().getWidth(), mLocator->getRect().getHeight()); + mLocator->setRect(rect); + } + + if(mInfo) + { + rect.setLeftTopAndSize(mInfo->getRect().mLeft + 30, mInfo->getRect().mTop, mInfo->getRect().getWidth(), mInfo->getRect().getHeight()); + mInfo->setRect(rect); + } + } + +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + if(!mNeedsArrange) + { + LLView::reshape(width, height, called_from_parent); + return; + } + + LLRect rect; + S32 profile_delta = 0; + S32 width_delta = getRect().getWidth() - width; + + if(!mProfile) + { + profile_delta = 30; + } + else + { + rect.setLeftTopAndSize(mProfile->getRect().mLeft - width_delta, mProfile->getRect().mTop, mProfile->getRect().getWidth(), mProfile->getRect().getHeight()); + mProfile->setRect(rect); + } + + width_delta += profile_delta; + + if(mInfo) + { + rect.setLeftTopAndSize(mInfo->getRect().mLeft - width_delta, mInfo->getRect().mTop, mInfo->getRect().getWidth(), mInfo->getRect().getHeight()); + mInfo->setRect(rect); + } + + if(mLocator) + { + rect.setLeftTopAndSize(mLocator->getRect().mLeft - width_delta, mLocator->getRect().mTop, mLocator->getRect().getWidth(), mLocator->getRect().getHeight()); + mLocator->setRect(rect); + } + + if(mStatus) + { + rect.setLeftTopAndSize(mStatus->getRect().mLeft - width_delta, mStatus->getRect().mTop, mStatus->getRect().getWidth(), mStatus->getRect().getHeight()); + mStatus->setRect(rect); + } + + mNeedsArrange = false; + LLView::reshape(width, height, called_from_parent); +} + +//--------------------------------------------------------------------------------- +LLAvatarListItem::~LLAvatarListItem() +{ +} +//--------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------- +BOOL LLAvatarListItem::handleHover(S32 x, S32 y, MASK mask) +{ + mYPos = y; + mXPos = x; + + return true; +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + setTransparentColor( *(new LLColor4((F32)0.4, (F32)0.4, (F32)0.4)) ); + + if(mInfo) + mInfo->setVisible(true); + + if(mProfile) + mProfile->setVisible(true); +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + if(mInfo) + { + if( mInfo->getRect().pointInRect(x, y) ) + return; + + mInfo->setVisible(false); + } + + if(mProfile) + { + if( mProfile->getRect().pointInRect(x, y) ) + return; + + mProfile->setVisible(false); + } + + setTransparentColor( *(new LLColor4((F32)0.3, (F32)0.3, (F32)0.3)) ); +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::setStatus(int status) +{ +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::setName(std::string name) +{ +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::setAvatar(LLSD& data) +{ +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::onInfoBtnClick() +{ + mInspector = LLFloaterReg::showInstance("inspect_avatar", gAgent.getID()); + + if (!mInspector) + return; + + LLRect rect; + localPointToScreen(mXPos, mYPos, &mXPos, &mYPos); + + + // *TODO Vadim: rewrite this. "+= -" looks weird. + S32 delta = mYPos - mInspector->getRect().getHeight(); + if(delta < 0) + { + mYPos += -delta; + } + + rect.setLeftTopAndSize(mXPos, mYPos, + mInspector->getRect().getWidth(), mInspector->getRect().getHeight()); + mInspector->setRect(rect); + mInspector->setFrontmost(true); + mInspector->setVisible(true); + +} + +//--------------------------------------------------------------------------------- +void LLAvatarListItem::onProfileBtnClick() +{ +} + +//--------------------------------------------------------------------------------- diff --git a/indra/newview/llavatarlistitem.h b/indra/newview/llavatarlistitem.h new file mode 100644 index 0000000000..b41e0ff209 --- /dev/null +++ b/indra/newview/llavatarlistitem.h @@ -0,0 +1,104 @@ +/** + * @file llavatarlistitem.h + * @avatar list item header file + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llavatariconctrl.h" +#include +#include +#include +#include +#include +#include + +//#include "llfloaterminiinspector.h" + +class LLAvatarListItem : public LLPanel +{ +public: + struct Params : public LLInitParam::Block + { + Optional avatar_icon; + Optional user_name; + struct avatar_list_item_buttons + { + bool status; + bool info; + bool profile; + bool locator; + avatar_list_item_buttons() : status(true), info(true), profile(true), locator(true) + {}; + } buttons; + + Params() + : avatar_icon("avatar_icon"), + user_name("user_name") + {}; + }; + + + LLAvatarListItem(const Params& p); + virtual ~LLAvatarListItem(); + + void reshape(S32 width, S32 height, BOOL called_from_parent); + + //interface + void setStatus(int status); + void setName(std::string name); + void setAvatar(LLSD& data); + void needsArrange( void ) {mNeedsArrange = true;} + + + //event handlers + //mouse + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + //buttons + void onInfoBtnClick(); + void onProfileBtnClick(); + +private: + LLAvatarIconCtrl* mAvatar; + LLIconCtrl* mLocator; + LLTextBox* mName; + LLTextBox* mStatus; + LLButton* mInfo; + LLButton* mProfile; + + S32 mYPos; + S32 mXPos; + + LLFloater* mInspector; + bool mNeedsArrange; + + // + void init(const Params& p); +}; diff --git a/indra/newview/llavatarpropertiesprocessor.cpp b/indra/newview/llavatarpropertiesprocessor.cpp new file mode 100644 index 0000000000..ecd67e44ae --- /dev/null +++ b/indra/newview/llavatarpropertiesprocessor.cpp @@ -0,0 +1,442 @@ +/** + * @file llavatarpropertiesprocessor.cpp + * @brief LLAvatarPropertiesProcessor class implementation + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llavatarpropertiesprocessor.h" + +#include "message.h" +#include "llagent.h" +#include "llviewergenericmessage.h" + +LLAvatarPropertiesProcessor::LLAvatarPropertiesProcessor() +{ +} + +void LLAvatarPropertiesProcessor::addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) +{ + // Check if that observer is already in mObservers for that avatar_id + observer_multimap_t::iterator it; + + // IAN BUG this should update the observer's UUID if this is a dupe - sent to PE + it = mObservers.find(avatar_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + return; + } + else + { + ++it; + } + } + + mObservers.insert(std::pair(avatar_id, observer)); +} + +void LLAvatarPropertiesProcessor::removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer) +{ + if (!observer) + { + return; + } + + observer_multimap_t::iterator it; + it = mObservers.find(avatar_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + mObservers.erase(it); + break; + } + else + { + ++it; + } + } +} + +void LLAvatarPropertiesProcessor::sendDataRequest(const LLUUID& avatar_id, EAvatarProcessorType type, + const void * data) +{ + switch(type) + { + case APT_PROPERTIES: + sendAvatarPropertiesRequest(avatar_id); + break; + case APT_PICKS: + sendGenericRequest(avatar_id, "avatarpicksrequest"); + break; + case APT_PICK_INFO: + if (data) { + sendPickInfoRequest(avatar_id, *static_cast(data)); + } + break; + case APT_NOTES: + sendGenericRequest(avatar_id, "avatarnotesrequest"); + break; + case APT_GROUPS: + sendGenericRequest(avatar_id, "avatargroupsrequest"); + break; + default: + break; + } +} + +void LLAvatarPropertiesProcessor::sendGenericRequest(const LLUUID& avatar_id, const std::string method) +{ + std::vector strings; + strings.push_back( avatar_id.asString() ); + send_generic_message(method, strings); +} + +void LLAvatarPropertiesProcessor::sendAvatarPropertiesRequest(const LLUUID& avatar_id) +{ + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_AvatarPropertiesRequest); + msg->nextBlockFast( _PREHASH_AgentData); + msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast( _PREHASH_AvatarID, avatar_id); + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendDataUpdate(const void* data, EAvatarProcessorType type) +{ + switch(type) + { + case APT_PROPERTIES: + sendAvatarPropertiesUpdate(data); + break; + case APT_PICK_INFO: + sendPicInfoUpdate(data); + case APT_PICKS: +// sendGenericRequest(avatar_id, "avatarpicksrequest"); + break; + case APT_NOTES: +// sendGenericRequest(avatar_id, "avatarnotesrequest"); + break; + case APT_GROUPS: +// sendGenericRequest(avatar_id, "avatargroupsrequest"); + break; + default: + break; + } + +} +void LLAvatarPropertiesProcessor::sendAvatarPropertiesUpdate(const void* data) +{ + llinfos << "Sending avatarinfo update" << llendl; + + const LLAvatarData* avatar_props = static_cast(data); + // This value is required by sendAvatarPropertiesUpdate method. + //A profile should never be mature. (From the original code) + BOOL mature = FALSE; + + + + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); + msg->nextBlockFast(_PREHASH_PropertiesData); + + msg->addUUIDFast( _PREHASH_ImageID, avatar_props->image_id); + msg->addUUIDFast( _PREHASH_FLImageID, avatar_props->fl_image_id); + msg->addStringFast( _PREHASH_AboutText, avatar_props->about_text); + msg->addStringFast( _PREHASH_FLAboutText, avatar_props->fl_about_text); + + msg->addBOOL(_PREHASH_AllowPublish, avatar_props->allow_publish); + msg->addBOOL(_PREHASH_MaturePublish, mature); + msg->addString(_PREHASH_ProfileURL, avatar_props->profile_url); + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::processAvatarPropertiesReply(LLMessageSystem* msg, void**) +{ + LLAvatarData avatar_data; + + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AgentID, avatar_data.agent_id); + msg->getUUIDFast( _PREHASH_AgentData, _PREHASH_AvatarID, avatar_data.avatar_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_ImageID, avatar_data.image_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_FLImageID, avatar_data.fl_image_id); + msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_PartnerID, avatar_data.partner_id); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_AboutText, avatar_data.about_text); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_FLAboutText, avatar_data.fl_about_text); + msg->getStringFast( _PREHASH_PropertiesData, _PREHASH_BornOn, avatar_data.born_on); + msg->getString( _PREHASH_PropertiesData, _PREHASH_ProfileURL, avatar_data.profile_url); + msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_Flags, avatar_data.flags); + + + avatar_data.caption_index = 0; + + S32 charter_member_size = 0; + charter_member_size = msg->getSize(_PREHASH_PropertiesData, _PREHASH_CharterMember); + if(1 == charter_member_size) + { + msg->getBinaryData(_PREHASH_PropertiesData, _PREHASH_CharterMember, &avatar_data.caption_index, 1); + } + else if(1 < charter_member_size) + { + msg->getString(_PREHASH_PropertiesData, _PREHASH_CharterMember, avatar_data.caption_text); + } + notifyObservers(avatar_data.avatar_id,&avatar_data,APT_PROPERTIES); +} + +void LLAvatarPropertiesProcessor::processAvatarInterestsReply(LLMessageSystem* msg, void**) +{ +/* + AvatarInterestsReply is automatically sent by the server in response to the + AvatarPropertiesRequest sent when the panel is opened (in addition to the AvatarPropertiesReply message). + If the interests panel is no longer part of the design (?) we should just register the message + to a handler function that does nothing. + That will suppress the warnings and be compatible with old server versions. + WARNING: LLTemplateMessageReader::decodeData: Message from 216.82.37.237:13000 with no handler function received: AvatarInterestsReply +*/ +} +void LLAvatarPropertiesProcessor::processAvatarClassifiedReply(LLMessageSystem* msg, void**) +{ + // avatarclassifiedsrequest is not sent according to new UI design but + // keep this method according to resolved issues. +} +void LLAvatarPropertiesProcessor::processAvatarNotesReply(LLMessageSystem* msg, void**) +{ + LLAvatarNotes avatar_notes; + + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_notes.agent_id); + msg->getUUID(_PREHASH_Data, _PREHASH_TargetID, avatar_notes.target_id); + msg->getString(_PREHASH_Data, _PREHASH_Notes, avatar_notes.notes); + + notifyObservers(avatar_notes.target_id,&avatar_notes,APT_NOTES); +} + +void LLAvatarPropertiesProcessor::processAvatarPicksReply(LLMessageSystem* msg, void**) +{ + LLAvatarPicks avatar_picks; + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, avatar_picks.target_id); + msg->getUUID(_PREHASH_AgentData, _PREHASH_TargetID, avatar_picks.target_id); + + S32 block_count = msg->getNumberOfBlocks(_PREHASH_Data); + for (int block = 0; block < block_count; ++block) + { + LLUUID pick_id; + std::string pick_name; + + msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_id, block); + msg->getString(_PREHASH_Data, _PREHASH_PickName, pick_name, block); + + avatar_picks.picks_list.push_back(std::make_pair(pick_id,pick_name)); + } + notifyObservers(avatar_picks.target_id,&avatar_picks,APT_PICKS); +} + +void LLAvatarPropertiesProcessor::processPickInfoReply(LLMessageSystem* msg, void**) +{ + LLPickData pick_data; + + // Extract the agent id and verify the message is for this + // client. + msg->getUUID(_PREHASH_AgentData, _PREHASH_AgentID, pick_data.agent_id ); + msg->getUUID(_PREHASH_Data, _PREHASH_PickID, pick_data.pick_id); + msg->getUUID(_PREHASH_Data, _PREHASH_CreatorID, pick_data.creator_id); + + // ** top_pick should be deleted, not being used anymore - angela + msg->getBOOL(_PREHASH_Data, _PREHASH_TopPick, pick_data.top_pick); + msg->getUUID(_PREHASH_Data, _PREHASH_ParcelID, pick_data.parcel_id); + msg->getString(_PREHASH_Data, _PREHASH_Name, pick_data.name); + msg->getString(_PREHASH_Data, _PREHASH_Desc, pick_data.desc); + msg->getUUID(_PREHASH_Data, _PREHASH_SnapshotID, pick_data.snapshot_id); + + // "Location text" is actually the owner name, the original + // name that owner gave the parcel, and the location. + msg->getString(_PREHASH_Data, _PREHASH_User, pick_data.location_text); + pick_data.location_text.append(", "); + + msg->getString(_PREHASH_Data, _PREHASH_OriginalName, pick_data.original_name); + if (!pick_data.original_name.empty()) + { + pick_data.location_text.append(pick_data.original_name); + pick_data.location_text.append(", "); + } + + msg->getString(_PREHASH_Data, _PREHASH_SimName, pick_data.sim_name); + pick_data.location_text.append(pick_data.sim_name); + pick_data.location_text.append(" "); + + msg->getVector3d(_PREHASH_Data, _PREHASH_PosGlobal, pick_data.pos_global); + S32 region_x = llround((F32)pick_data.pos_global.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = llround((F32)pick_data.pos_global.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = llround((F32)pick_data.pos_global.mdV[VZ]); + pick_data.location_text.append(llformat("(%d, %d, %d)", region_x, region_y, region_z)); + + msg->getS32(_PREHASH_Data, _PREHASH_SortOrder, pick_data.sort_order); + msg->getBOOL(_PREHASH_Data, _PREHASH_Enabled, pick_data.enabled); + + notifyObservers(pick_data.creator_id, &pick_data, APT_PICK_INFO); +} + +void LLAvatarPropertiesProcessor::processAvatarGroupsReply(LLMessageSystem* msg, void**) +{ + LLAvatarGroups avatar_groups; + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, avatar_groups.agent_id ); + msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_groups.avatar_id ); + + S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); + for(S32 i = 0; i < group_count; ++i) + { + LLAvatarGroups::LLGroupData group_data; + + msg->getU64( _PREHASH_GroupData, _PREHASH_GroupPowers, group_data.group_powers, i ); + msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_data.group_title, i ); + msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_data.group_id, i); + msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_data.group_name, i ); + msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_data.group_insignia_id, i ); + + avatar_groups.group_list.push_back(group_data); + } + + notifyObservers(avatar_groups.avatar_id,&avatar_groups,APT_GROUPS); +} + +void LLAvatarPropertiesProcessor::notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type) +{ + LLAvatarPropertiesProcessor::observer_multimap_t observers = LLAvatarPropertiesProcessor::getInstance()->mObservers; + + observer_multimap_t::iterator oi = observers.lower_bound(id); + observer_multimap_t::iterator end = observers.upper_bound(id); + for (; oi != end; ++oi) + { + oi->second->processProperties(data,type); + } +} + +void LLAvatarPropertiesProcessor::sendFriendRights(const LLUUID& avatar_id, S32 rights) +{ + if(!avatar_id.isNull()) + { + LLMessageSystem* msg = gMessageSystem; + + // setup message header + msg->newMessageFast(_PREHASH_GrantUserRights); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_Rights); + msg->addUUID(_PREHASH_AgentRelated, avatar_id); + msg->addS32(_PREHASH_RelatedRights, rights); + + gAgent.sendReliableMessage(); + } +} + +void LLAvatarPropertiesProcessor::sendNotes(const LLUUID& avatar_id, const std::string notes) +{ + if(!avatar_id.isNull()) + { + LLMessageSystem* msg = gMessageSystem; + + // setup message header + msg->newMessageFast(_PREHASH_AvatarNotesUpdate); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_Data); + msg->addUUID(_PREHASH_TargetID, avatar_id); + msg->addString(_PREHASH_Notes, notes); + + gAgent.sendReliableMessage(); + } +} + + +void LLAvatarPropertiesProcessor::sendPickDelete( const LLUUID& pick_id ) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessage(_PREHASH_PickDelete); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, pick_id); + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPicInfoUpdate(const void* pick_data) +{ + if (!pick_data) return; + const LLPickData *new_pick = static_cast(pick_data); + if (!new_pick) return; + + LLMessageSystem* msg = gMessageSystem; + + msg->newMessage(_PREHASH_PickInfoUpdate); + msg->nextBlock(_PREHASH_AgentData); + msg->addUUID(_PREHASH_AgentID, gAgent.getID()); + msg->addUUID(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlock(_PREHASH_Data); + msg->addUUID(_PREHASH_PickID, new_pick->pick_id); + msg->addUUID(_PREHASH_CreatorID, new_pick->creator_id); + + //legacy var need to be deleted + msg->addBOOL(_PREHASH_TopPick, FALSE); + + // fills in on simulator if null + msg->addUUID(_PREHASH_ParcelID, new_pick->parcel_id); + msg->addString(_PREHASH_Name, new_pick->name); + msg->addString(_PREHASH_Desc, new_pick->desc); + msg->addUUID(_PREHASH_SnapshotID, new_pick->snapshot_id); + msg->addVector3d(_PREHASH_PosGlobal, new_pick->pos_global); + + // Only top picks have a sort order + msg->addS32(_PREHASH_SortOrder, 0); + + msg->addBOOL(_PREHASH_Enabled, new_pick->enabled); + gAgent.sendReliableMessage(); +} + +void LLAvatarPropertiesProcessor::sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id) +{ + // Must ask for a pick based on the creator id because + // the pick database is distributed to the inventory cluster. JC + std::vector request_params; + request_params.push_back(creator_id.asString() ); + request_params.push_back(pick_id.asString() ); + send_generic_message("pickinforequest", request_params); +} diff --git a/indra/newview/llavatarpropertiesprocessor.h b/indra/newview/llavatarpropertiesprocessor.h new file mode 100644 index 0000000000..2e10dea834 --- /dev/null +++ b/indra/newview/llavatarpropertiesprocessor.h @@ -0,0 +1,208 @@ +/** + * @file llavatarpropertiesprocessor.h + * @brief LLAvatatIconCtrl base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAVATARPROPERTIESPROCESSOR_H +#define LL_LLAVATARPROPERTIESPROCESSOR_H + +#include "lluuid.h" +#include "llsingleton.h" +#include "v3dmath.h" // LLVector3d +#include + +/* +*TODO Vadim: This needs some refactoring: +- Remove EAvatarProcessorType in favor of separate observers, derived from a common parent (to get rid of void*). +*/ + +/* +*TODO: mantipov: get rid of sendDataRequest and sendDataUpdate methods. Use exact methods instead of. +*/ + +class LLMessageSystem; + +enum EAvatarProcessorType +{ + APT_PROPERTIES, + APT_NOTES, + APT_GROUPS, + APT_PICKS, + APT_PICK_INFO +}; + +struct LLAvatarData +{ + LLUUID agent_id; + LLUUID avatar_id; //target id + LLUUID image_id; + LLUUID fl_image_id; + LLUUID partner_id; + std::string about_text; + std::string fl_about_text; + std::string born_on; + std::string profile_url; + U8 caption_index; + std::string caption_text; + U32 flags; + BOOL allow_publish; +}; + +struct LLAvatarPicks +{ + LLUUID agent_id; + LLUUID target_id; //target id + + typedef std::pair pick_data_t; + typedef std::list< pick_data_t> picks_list_t; + picks_list_t picks_list; +}; + +struct LLPickData +{ + LLUUID agent_id; + LLUUID pick_id; + LLUUID creator_id; + BOOL top_pick; + LLUUID parcel_id; + std::string name; + std::string desc; + LLUUID snapshot_id; + LLVector3d pos_global; + S32 sort_order; + BOOL enabled; + + //used only in read requests + std::string location_text; + std::string original_name; + std::string sim_name; + + //used only in write (update) requests + LLUUID session_id; + +}; + +struct LLAvatarNotes +{ + LLUUID agent_id; + LLUUID target_id; //target id + std::string notes; +}; + +struct LLAvatarGroups +{ + LLUUID agent_id; + LLUUID avatar_id; //target id + BOOL list_in_profile; + + struct LLGroupData; + typedef std::list group_list_t; + + group_list_t group_list; + + struct LLGroupData + { + U64 group_powers; + BOOL accept_notices; + std::string group_title; + LLUUID group_id; + std::string group_name; + LLUUID group_insignia_id; + }; +}; + +class LLAvatarPropertiesObserver +{ +public: + virtual ~LLAvatarPropertiesObserver() {} + virtual void processProperties(void* data, EAvatarProcessorType type) = 0; +}; + +class LLAvatarPropertiesProcessor + : public LLSingleton +{ +public: + + LLAvatarPropertiesProcessor(); + virtual ~LLAvatarPropertiesProcessor() + {} + + void addObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer); + + void removeObserver(const LLUUID& avatar_id, LLAvatarPropertiesObserver* observer); + + void sendDataRequest(const LLUUID& avatar_id, EAvatarProcessorType type, const void * data = NULL); + + void sendDataUpdate(const void* data, EAvatarProcessorType type); + + void sendFriendRights(const LLUUID& avatar_id, S32 rights); + + void sendNotes(const LLUUID& avatar_id, const std::string notes); + + void sendPickDelete(const LLUUID& pick_id); + + static void processAvatarPropertiesReply(LLMessageSystem* msg, void**); + + static void processAvatarInterestsReply(LLMessageSystem* msg, void**); + + static void processAvatarClassifiedReply(LLMessageSystem* msg, void**); + + static void processAvatarGroupsReply(LLMessageSystem* msg, void**); + + static void processAvatarNotesReply(LLMessageSystem* msg, void**); + + static void processAvatarPicksReply(LLMessageSystem* msg, void**); + + static void processPickInfoReply(LLMessageSystem* msg, void**); +protected: + + void sendAvatarPropertiesRequest(const LLUUID& avatar_id); + + void sendGenericRequest(const LLUUID& avatar_id, const std::string method); + + void sendAvatarPropertiesUpdate(const void* data); + + void sendPickInfoRequest(const LLUUID& creator_id, const LLUUID& pick_id); + + void sendPicInfoUpdate(const void * pick_data); + + static void notifyObservers(const LLUUID& id,void* data, EAvatarProcessorType type); + + typedef void* (*processor_method_t)(LLMessageSystem*); + static processor_method_t getProcessor(EAvatarProcessorType type); + +protected: + + typedef std::multimap observer_multimap_t; + + observer_multimap_t mObservers; +}; + +#endif // LL_LLAVATARPROPERTIESPROCESSOR_H diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp new file mode 100644 index 0000000000..2403e891f6 --- /dev/null +++ b/indra/newview/llbottomtray.cpp @@ -0,0 +1,191 @@ +/** + * @file llbottomtray.cpp + * @brief LLBottomTray class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" // must be first include +#include "llbottomtray.h" + +#include "llagent.h" +#include "llchiclet.h" +#include "llfloaterreg.h" +#include "llflyoutbutton.h" +#include "lllayoutstack.h" +#include "llnearbychatbar.h" +#include "llsplitbutton.h" +#include "llfloatercamera.h" +#include "llimpanel.h" +#include "llactiveimwindow.h" + +LLBottomTray::LLBottomTray(const LLSD&) +: mChicletPanel(NULL), + mIMWell(NULL), + mSysWell(NULL), + mTalkBtn(NULL), + mNearbyChatBar(NULL), + mToolbarStack(NULL) + +{ + mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL); + + LLUICtrlFactory::getInstance()->buildPanel(this,"panel_bottomtray.xml"); + + mChicletPanel = getChild("chiclet_list"); + mIMWell = getChild("im_well"); + mSysWell = getChild("sys_well"); + + mSysWell->setNotificationChicletWindow(LLFloaterReg::getInstance("syswell_window")); + mChicletPanel->setChicletClickedCallback(boost::bind(&LLBottomTray::onChicletClick,this,_1)); + + LLSplitButton* presets = getChild("presets"); + presets->setSelectionCallback(LLFloaterCamera::onClickCameraPresets); + + LLIMMgr::getInstance()->addSessionObserver(this); + + //this is to fix a crash that occurs because LLBottomTray is a singleton + //and thus is deleted at the end of the viewers lifetime, but to be cleanly + //destroyed LLBottomTray requires some subsystems that are long gone + LLUI::getRootView()->addChild(this); + + // Necessary for focus movement among child controls + setFocusRoot(TRUE); + + LLActiveIMWindow::init(mIMWell); +} + +BOOL LLBottomTray::postBuild() +{ + mNearbyChatBar = getChild("chat_bar"); + mToolbarStack = getChild("toolbar_stack"); + + return TRUE; +} + +LLBottomTray::~LLBottomTray() +{ + if (!LLSingleton::destroyed()) + { + LLIMMgr::getInstance()->removeSessionObserver(this); + } +} + +void LLBottomTray::onChicletClick(LLUICtrl* ctrl) +{ + LLIMChiclet* chiclet = dynamic_cast(ctrl); + if (chiclet) + { + // Until you can type into an IM Window and have a conversation, + // still show the old communicate window + //LLFloaterReg::showInstance("communicate", chiclet->getSessionId()); + + // Show after comm window so it is frontmost (and hence will not + // auto-hide) + +// this logic has been moved to LLIMChiclet::handleMouseDown +// LLIMFloater::show(chiclet->getSessionId()); +// chiclet->setCounter(0); + } +} + +void* LLBottomTray::createNearbyChatBar(void* userdata) +{ + return new LLNearbyChatBar(); +} + +//virtual +void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) +{ + if(getChicletPanel()) + { + if(getChicletPanel()->findChiclet(session_id)) + { + + } + else + { + LLIMChiclet* chiclet = getChicletPanel()->createChiclet(session_id); + chiclet->setIMSessionName(name); + chiclet->setOtherParticipantId(other_participant_id); + } + } + updateImChicletCount(); +} + +//virtual +void LLBottomTray::sessionRemoved(const LLUUID& session_id) +{ + if(getChicletPanel()) + { + getChicletPanel()->removeChiclet(session_id); + } + updateImChicletCount(); +} + +//virtual +void LLBottomTray::onFocusLost() +{ + if (gAgent.cameraMouselook()) + { + setVisible(FALSE); + } +} + +//virtual +// setVisible used instead of onVisibilityChange, since LLAgent calls it on entering/leaving mouselook mode. +// If bottom tray is already visible in mouselook mode, then onVisibilityChange will not be called from setVisible(true), +void LLBottomTray::setVisible(BOOL visible) +{ + LLPanel::setVisible(visible); + + // *NOTE: we must check mToolbarStack against NULL because setVisible is called from the + // LLPanel::initFromParams BEFORE postBuild is called and child controls are not exist yet + if (NULL != mToolbarStack) + { + BOOL visibility = gAgent.cameraMouselook() ? false : true; + + for ( child_list_const_iter_t child_it = mToolbarStack->getChildList()->begin(); + child_it != mToolbarStack->getChildList()->end(); child_it++) + { + LLView* viewp = *child_it; + + if ("chat_bar" == viewp->getName()) + continue; + else + { + viewp->setVisible(visibility); + } + } + } +} + +void LLBottomTray::updateImChicletCount() { + U32 chicletCount = mChicletPanel->getChicletCount(); + mIMWell->setCounter(chicletCount); +} diff --git a/indra/newview/llbottomtray.h b/indra/newview/llbottomtray.h new file mode 100644 index 0000000000..7f606339bc --- /dev/null +++ b/indra/newview/llbottomtray.h @@ -0,0 +1,91 @@ +/** +* @file llbottomtray.h +* @brief LLBottomTray class header file +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLBOTTOMPANEL_H +#define LL_LLBOTTOMPANEL_H + +#include "llpanel.h" +#include "llimview.h" + +class LLChicletPanel; +class LLLineEditor; +class LLLayoutStack; +class LLNotificationChiclet; +class LLTalkButton; +class LLNearbyChatBar; + +class LLBottomTray + : public LLSingleton + , public LLPanel + , public LLIMSessionObserver +{ + friend class LLSingleton; +public: + ~LLBottomTray(); + + BOOL postBuild(); + + LLChicletPanel* getChicletPanel() {return mChicletPanel;} + LLNotificationChiclet* getIMWell() {return mIMWell;} + LLNotificationChiclet* getSysWell() {return mSysWell;} + LLNearbyChatBar* getNearbyChatBar() {return mNearbyChatBar;} + + void onCommitGesture(LLUICtrl* ctrl); + + // LLIMSessionObserver observe triggers + virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + virtual void sessionRemoved(const LLUUID& session_id); + + virtual void onFocusLost(); + virtual void setVisible(BOOL visible); + +private: + void updateImChicletCount(); + +protected: + + LLBottomTray(const LLSD& key = LLSD()); + + void onChicletClick(LLUICtrl* ctrl); + + static void* createNearbyChatBar(void* userdata); + + LLChicletPanel* mChicletPanel; + LLNotificationChiclet* mIMWell; + LLNotificationChiclet* mSysWell; + LLTalkButton* mTalkBtn; + LLNearbyChatBar* mNearbyChatBar; + LLLayoutStack* mToolbarStack; + +}; + +#endif // LL_LLBOTTOMPANEL_H diff --git a/indra/newview/llbreadcrumbview.cpp b/indra/newview/llbreadcrumbview.cpp new file mode 100644 index 0000000000..342994ee30 --- /dev/null +++ b/indra/newview/llbreadcrumbview.cpp @@ -0,0 +1,37 @@ +/** + * @file llbreadcrumbview.cpp + * @brief UI widget for displaying position in a folder hierarchy and allowing + * the user to click on a location in the hierarchy. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "llviewerprecompiledheaders.h" + +#include "llbreadcrumbview.h" + +// TODO diff --git a/indra/newview/llbreadcrumbview.h b/indra/newview/llbreadcrumbview.h new file mode 100644 index 0000000000..ca6fbe7fb2 --- /dev/null +++ b/indra/newview/llbreadcrumbview.h @@ -0,0 +1,36 @@ +/** + * @file llbreadcrumbview.h + * @brief UI widget for displaying position in a folder hierarchy and allowing + * the user to click on a location in the hierarchy. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLBREADCRUMBVIEW_H +#define LLBREADCRUMBVIEW_H + +#endif // LLBREADCRUMBVIEW_H diff --git a/indra/newview/llcallingcard.cpp b/indra/newview/llcallingcard.cpp index db28c7ad38..7326e39af3 100644 --- a/indra/newview/llcallingcard.cpp +++ b/indra/newview/llcallingcard.cpp @@ -95,29 +95,8 @@ const F32 OFFLINE_SECONDS = FIND_FREQUENCY + 8.0f; // static LLAvatarTracker LLAvatarTracker::sInstance; -/* -class LLAvatarTrackerInventoryObserver : public LLInventoryObserver -{ -public: - LLAvatarTrackerInventoryObserver(LLAvatarTracker* at) : - mAT(at) {} - virtual ~LLAvatarTrackerInventoryObserver() {} - virtual void changed(U32 mask); -protected: - LLAvatarTracker* mAT; -}; -*/ -/* -void LLAvatarTrackerInventoryObserver::changed(U32 mask) -{ - // if there's a calling card change, just do it. - if((mask & LLInventoryObserver::CALLING_CARD) != 0) - { - mAT->inventoryChanged(); - } -} -*/ + ///---------------------------------------------------------------------------- /// Class LLAvatarTracker @@ -329,7 +308,8 @@ void LLAvatarTracker::terminateBuddy(const LLUUID& id) msg->nextBlock("ExBlock"); msg->addUUID("OtherID", id); gAgent.sendReliableMessage(); - mModifyMask |= LLFriendObserver::REMOVE; + + addChangedMask(LLFriendObserver::REMOVE, id); delete buddy; } @@ -503,6 +483,18 @@ void LLAvatarTracker::notifyObservers() (*it)->changed(mModifyMask); } mModifyMask = LLFriendObserver::NONE; + mChangedBuddyIDs.clear(); +} + +// store flag for change +// and id of object change applies to +void LLAvatarTracker::addChangedMask(U32 mask, const LLUUID& referent) +{ + mModifyMask |= mask; + if (referent.notNull()) + { + mChangedBuddyIDs.insert(referent); + } } void LLAvatarTracker::applyFunctor(LLRelationshipFunctor& f) @@ -684,7 +676,7 @@ void LLAvatarTracker::processNotify(LLMessageSystem* msg, bool online) { std::string notifyMsg = notification->getMessage(); if (!notifyMsg.empty()) - floater->addHistoryLine(notifyMsg,gSavedSettings.getColor4("SystemChatColor")); + floater->addHistoryLine(notifyMsg,LLUIColorTable::instance().getColor("SystemChatColor")); } } @@ -706,7 +698,7 @@ void LLAvatarTracker::formFriendship(const LLUUID& id) //visible online to each other. buddy_info = new LLRelationship(LLRelationship::GRANT_ONLINE_STATUS,LLRelationship::GRANT_ONLINE_STATUS, false); at.mBuddyInfo[id] = buddy_info; - at.mModifyMask |= LLFriendObserver::ADD; + at.addChangedMask(LLFriendObserver::ADD, id); at.notifyObservers(); } } @@ -722,7 +714,7 @@ void LLAvatarTracker::processTerminateFriendship(LLMessageSystem* msg, void**) LLRelationship* buddy = get_ptr_in_map(at.mBuddyInfo, id); if(!buddy) return; at.mBuddyInfo.erase(id); - at.mModifyMask |= LLFriendObserver::REMOVE; + at.addChangedMask(LLFriendObserver::REMOVE, id); delete buddy; at.notifyObservers(); } diff --git a/indra/newview/llcallingcard.h b/indra/newview/llcallingcard.h index 85a1ab6e1e..113f16de70 100644 --- a/indra/newview/llcallingcard.h +++ b/indra/newview/llcallingcard.h @@ -147,6 +147,17 @@ public: void removeObserver(LLFriendObserver* observer); void notifyObservers(); + /** + * Stores flag for change and id of object change applies to + * + * This allows outsiders to tell the AvatarTracker if something has + * been changed 'under the hood', + * and next notification will have exact avatar IDs have been changed. + */ + void addChangedMask(U32 mask, const LLUUID& referent); + + const std::set& getChangedIDs() { return mChangedBuddyIDs; } + // Apply the functor to every buddy. Do not actually modify the // buddy list in the functor or bad things will happen. void applyFunctor(LLRelationshipFunctor& f); @@ -179,6 +190,9 @@ protected: buddy_map_t mBuddyInfo; + typedef std::set changed_buddy_t; + changed_buddy_t mChangedBuddyIDs; + typedef std::vector observer_list_t; observer_list_t mObservers; diff --git a/indra/newview/llcapabilitylistener.cpp b/indra/newview/llcapabilitylistener.cpp index 3277da8930..4134e9e0a4 100644 --- a/indra/newview/llcapabilitylistener.cpp +++ b/indra/newview/llcapabilitylistener.cpp @@ -21,6 +21,7 @@ // other Linden headers #include "stringize.h" #include "llcapabilityprovider.h" +#include "message.h" class LLCapabilityListener::CapabilityMappers: public LLSingleton { diff --git a/indra/newview/llcapabilitylistener.h b/indra/newview/llcapabilitylistener.h index 061227e04d..ce16b7da5d 100644 --- a/indra/newview/llcapabilitylistener.h +++ b/indra/newview/llcapabilitylistener.h @@ -17,6 +17,7 @@ #include "llerror.h" // LOG_CLASS() class LLCapabilityProvider; +class LLMessageSystem; class LLSD; class LLCapabilityListener diff --git a/indra/newview/llcaphttpsender.cpp b/indra/newview/llcaphttpsender.cpp index 1127f43424..b44e1f11fa 100644 --- a/indra/newview/llcaphttpsender.cpp +++ b/indra/newview/llcaphttpsender.cpp @@ -32,9 +32,10 @@ #include "llviewerprecompiledheaders.h" -#include "linden_common.h" #include "llcaphttpsender.h" +#include "llhost.h" + LLCapHTTPSender::LLCapHTTPSender(const std::string& cap) : mCap(cap) { diff --git a/indra/newview/llchannelmanager.cpp b/indra/newview/llchannelmanager.cpp new file mode 100644 index 0000000000..a8373491cf --- /dev/null +++ b/indra/newview/llchannelmanager.cpp @@ -0,0 +1,229 @@ +/** + * @file llchannelmanager.cpp + * @brief This class rules screen notification channels. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llchannelmanager.h" + +#include "llappviewer.h" +#include "llviewercontrol.h" +#include "llimview.h" + +#include + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLChannelManager::LLChannelManager() +{ + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLChannelManager::onLoginCompleted, this)); + mChannelList.clear(); + mStartUpChannel = NULL; +} + +//-------------------------------------------------------------------------- +LLChannelManager::~LLChannelManager() +{ + //All channels are being deleted by Parent View +} + +//-------------------------------------------------------------------------- +void LLChannelManager::onLoginCompleted() +{ + S32 away_notifications = 0; + + for(std::vector::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) + { + if((*it).channel->getChannelID() == LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))) + { + continue; + } + + if(!(*it).channel->getDisplayToastsAlways()) + { + away_notifications +=(*it).channel->getNumberOfHiddenToasts(); + } + } + + // *TODO: calculate IM notifications + away_notifications += gIMMgr->getNumberOfUnreadIM(); + + if(!away_notifications) + { + onStartUpToastClose(); + return; + } + + LLChannelManager::Params p; + p.id = LLUUID(gSavedSettings.getString("StartUpChannelUUID")); + p.channel_right_bound = getRootView()->getRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); + p.channel_width = gSavedSettings.getS32("NotifyBoxWidth"); + mStartUpChannel = createChannel(p); + + if(!mStartUpChannel) + { + onStartUpToastClose(); + return; + } + + mStartUpChannel->setShowToasts(true); + static_cast(mStartUpChannel)->setCommitCallback(boost::bind(&LLChannelManager::onStartUpToastClose, this)); + mStartUpChannel->createStartUpToast(away_notifications, gSavedSettings.getS32("ChannelBottomPanelMargin"), gSavedSettings.getS32("StartUpToastTime")); +} + +//-------------------------------------------------------------------------- +void LLChannelManager::onStartUpToastClose() +{ + if(mStartUpChannel) + { + mStartUpChannel->setVisible(FALSE); + mStartUpChannel->closeStartUpToast(); + getRootView()->removeChild(mStartUpChannel); + removeChannelByID(LLUUID(gSavedSettings.getString("StartUpChannelUUID"))); + delete mStartUpChannel; + mStartUpChannel = NULL; + } + + // set StartUp Toast Flag + LLScreenChannel::setStartUpToastShown(); + + // allow all other channels to show incoming toasts + for(std::vector::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) + { + (*it).channel->setShowToasts(true); + } + + // force NEARBY CHAT CHANNEL to repost all toasts if present + LLScreenChannel* nearby_channel = getChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + nearby_channel->loadStoredToastsToChannel(); + nearby_channel->setCanStoreToasts(false); +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::createChannel(LLChannelManager::Params& p) +{ + LLScreenChannel* new_channel = NULL; + + if(!p.chiclet) + { + new_channel = getChannelByID(p.id); + } + else + { + new_channel = getChannelByChiclet(p.chiclet); + } + + if(new_channel) + return new_channel; + + new_channel = new LLScreenChannel(p.id); + getRootView()->addChild(new_channel); + new_channel->init(p.channel_right_bound - p.channel_width, p.channel_right_bound); + new_channel->setToastAlignment(p.align); + new_channel->setDisplayToastsAlways(p.display_toasts_always); + + ChannelElem new_elem; + new_elem.id = p.id; + new_elem.chiclet = p.chiclet; + new_elem.channel = new_channel; + + mChannelList.push_back(new_elem); //TODO: remove chiclet from ScreenChannel? + + return new_channel; +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::getChannelByID(const LLUUID id) +{ + std::vector::iterator it = find(mChannelList.begin(), mChannelList.end(), id); + if(it != mChannelList.end()) + { + return (*it).channel; + } + + return NULL; +} + +//-------------------------------------------------------------------------- +LLScreenChannel* LLChannelManager::getChannelByChiclet(const LLChiclet* chiclet) +{ + std::vector::iterator it = find(mChannelList.begin(), mChannelList.end(), chiclet); + if(it != mChannelList.end()) + { + return (*it).channel; + } + + return NULL; +} + +//-------------------------------------------------------------------------- +void LLChannelManager::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + for(std::vector::iterator it = mChannelList.begin(); it != mChannelList.end(); ++it) + { + if((*it).channel->getToastAlignment() == NA_CENTRE) + { + LLRect channel_rect = (*it).channel->getRect(); + S32 screen_width = getRootView()->getRect().getWidth(); + channel_rect.setLeftTopAndSize(screen_width/2, channel_rect.mTop, channel_rect.getWidth(), channel_rect.getHeight()); + (*it).channel->setRect(channel_rect); + (*it).channel->showToasts(); + } + } +} + +//-------------------------------------------------------------------------- +void LLChannelManager::removeChannelByID(const LLUUID id) +{ + std::vector::iterator it = find(mChannelList.begin(), mChannelList.end(), id); + if(it != mChannelList.end()) + { + mChannelList.erase(it); + } +} + +//-------------------------------------------------------------------------- +void LLChannelManager::removeChannelByChiclet(const LLChiclet* chiclet) +{ + std::vector::iterator it = find(mChannelList.begin(), mChannelList.end(), chiclet); + if(it != mChannelList.end()) + { + mChannelList.erase(it); + } +} + +//-------------------------------------------------------------------------- + + + + + diff --git a/indra/newview/llchannelmanager.h b/indra/newview/llchannelmanager.h new file mode 100644 index 0000000000..e26c96b62e --- /dev/null +++ b/indra/newview/llchannelmanager.h @@ -0,0 +1,124 @@ +/** + * @file llchannelmanager.h + * @brief This class rules screen notification channels. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCHANNELMANAGER_H +#define LL_LLCHANNELMANAGER_H + + +#include "llchiclet.h" +#include "llscreenchannel.h" + +#include "lluuid.h" + +#include +#include + +namespace LLNotificationsUI +{ +/** + * Manager for screen channels. + * Responsible for instantiating and retrieving screen channels. + */ +class LLChannelManager : public LLUICtrl, public LLSingleton +{ +public: + struct Params : public LLInitParam::Block + { + LLUUID id; + LLChiclet* chiclet; + S32 channel_right_bound; + S32 channel_width; + bool display_toasts_always; + EToastAlignment align; + + Params(): id(LLUUID("")), chiclet(NULL), + channel_right_bound(0), channel_width(0), + display_toasts_always(false), align(NA_BOTTOM) + {} + }; + + struct ChannelElem + { + LLUUID id; + LLChiclet* chiclet; + LLScreenChannel* channel; + + ChannelElem() : id(LLUUID("")), chiclet(NULL), channel(NULL) { } + + ChannelElem(const ChannelElem &elem) + { + id = elem.id; + chiclet = elem.chiclet; + channel = elem.channel; + } + + bool operator == (const LLUUID &id_op) const + { + return (id == id_op); + } + + bool operator == (const LLChiclet* chiclet_op) const + { + return (chiclet == chiclet_op); + } + + }; + + LLChannelManager(); + virtual ~LLChannelManager(); + + // On LoginCompleted - show StartUp toast + void onLoginCompleted(); + // removes a channel intended for the startup toast and allows other channels to show their toasts + void onStartUpToastClose(); + + //TODO: make protected? in order to be shure that channels are created only by notification handlers + LLScreenChannel* createChannel(LLChannelManager::Params& p); + + LLScreenChannel* getChannelByID(const LLUUID id); + LLScreenChannel* getChannelByChiclet(const LLChiclet* chiclet); + + // remove channel methods + void removeChannelByID(const LLUUID id); + void removeChannelByChiclet(const LLChiclet* chiclet); + + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +private: + + LLScreenChannel* mStartUpChannel; + std::vector mChannelList; +}; + +} +#endif + diff --git a/indra/newview/llchatbar.cpp b/indra/newview/llchatbar.cpp index 2395f3c5ae..3ee2c93961 100644 --- a/indra/newview/llchatbar.cpp +++ b/indra/newview/llchatbar.cpp @@ -67,7 +67,7 @@ #include "llui.h" #include "llviewermenu.h" #include "lluictrlfactory.h" - +#include "llbottomtray.h" // // Globals @@ -76,11 +76,6 @@ const F32 AGENT_TYPING_TIMEOUT = 5.f; // seconds LLChatBar *gChatBar = NULL; -// legacy calllback glue -void toggleChatHistory(void* user_data); -void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); - - class LLChatBarGestureObserver : public LLGestureManagerObserver { public: @@ -92,12 +87,14 @@ private: }; +extern void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); + // // Functions // LLChatBar::LLChatBar() -: LLPanel(LLStringUtil::null, LLRect(), BORDER_NO), +: LLPanel(), mInputEditor(NULL), mGestureLabelTimer(), mLastSpecialChatChannel(0), @@ -106,16 +103,12 @@ LLChatBar::LLChatBar() mObserver(NULL) { setIsChrome(TRUE); - - #if !LL_RELEASE_FOR_DOWNLOAD - childDisplayNotFound(); -#endif } LLChatBar::~LLChatBar() { - gGestureManager.removeObserver(mObserver); + LLGestureManager::instance().removeObserver(mObserver); delete mObserver; mObserver = NULL; // LLView destructor cleans up children @@ -123,34 +116,25 @@ LLChatBar::~LLChatBar() BOOL LLChatBar::postBuild() { - childSetAction("History", toggleChatHistory, this); - childSetCommitCallback("Say", onClickSay, this); + getChild("Say")->setCommitCallback(boost::bind(&LLChatBar::onClickSay, this, _1)); + // * NOTE: mantipov: getChild with default parameters returns dummy widget. + // Seems this class will be completle removed // attempt to bind to an existing combo box named gesture - setGestureCombo(getChild( "Gesture")); - - LLButton * sayp = getChild("Say"); - if(sayp) - { - setDefaultBtn(sayp); - } + setGestureCombo(findChild( "Gesture")); mInputEditor = getChild("Chat Editor"); - if (mInputEditor) - { - mInputEditor->setCallbackUserData(this); - mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke); - mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this); - mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this ); - mInputEditor->setCommitOnFocusLost( FALSE ); - mInputEditor->setRevertOnEsc( FALSE ); - mInputEditor->setIgnoreTab(TRUE); - mInputEditor->setPassDelete(TRUE); - mInputEditor->setReplaceNewlinesWithSpaces(FALSE); + mInputEditor->setKeystrokeCallback(&onInputEditorKeystroke, this); + mInputEditor->setFocusLostCallback(&onInputEditorFocusLost, this); + mInputEditor->setFocusReceivedCallback( &onInputEditorGainFocus, this ); + mInputEditor->setCommitOnFocusLost( FALSE ); + mInputEditor->setRevertOnEsc( FALSE ); + mInputEditor->setIgnoreTab(TRUE); + mInputEditor->setPassDelete(TRUE); + mInputEditor->setReplaceNewlinesWithSpaces(FALSE); - mInputEditor->setMaxTextLength(1023); - mInputEditor->setEnableLineHistory(TRUE); - } + mInputEditor->setMaxTextLength(1023); + mInputEditor->setEnableLineHistory(TRUE); mIsBuilt = TRUE; @@ -209,10 +193,7 @@ void LLChatBar::refresh() gAgent.stopTyping(); } - childSetValue("History", LLFloaterChat::instanceVisible(LLSD())); - childSetEnabled("Say", mInputEditor->getText().size() > 0); - childSetEnabled("Shout", mInputEditor->getText().size() > 0); } @@ -230,7 +211,7 @@ void LLChatBar::refreshGestures() // collect list of unique gestures std::map unique; LLGestureManager::item_map_t::iterator it; - for (it = gGestureManager.mActive.begin(); it != gGestureManager.mActive.end(); ++it) + for (it = LLGestureManager::instance().mActive.begin(); it != LLGestureManager::instance().mActive.end(); ++it) { LLMultiGesture* gesture = (*it).second; if (gesture) @@ -311,12 +292,11 @@ void LLChatBar::setGestureCombo(LLComboBox* combo) mGestureCombo = combo; if (mGestureCombo) { - mGestureCombo->setCommitCallback(onCommitGesture); - mGestureCombo->setCallbackUserData(this); + mGestureCombo->setCommitCallback(boost::bind(&LLChatBar::onCommitGesture, this, _1)); // now register observer since we have a place to put the results mObserver = new LLChatBarGestureObserver(this); - gGestureManager.addObserver(mObserver); + LLGestureManager::instance().addObserver(mObserver); // refresh list from current active gestures refreshGestures(); @@ -397,7 +377,7 @@ void LLChatBar::sendChat( EChatType type ) if (0 == channel) { // discard returned "found" boolean - gGestureManager.triggerAndReviseString(utf8text, &utf8_revised_text); + LLGestureManager::instance().triggerAndReviseString(utf8text, &utf8_revised_text); } else { @@ -434,17 +414,26 @@ void LLChatBar::sendChat( EChatType type ) // static void LLChatBar::startChat(const char* line) { - gChatBar->setVisible(TRUE); - gChatBar->setKeyboardFocus(TRUE); - gSavedSettings.setBOOL("ChatVisible", TRUE); + //TODO* remove DUMMY chat + //if(gBottomTray && gBottomTray->getChatBox()) + //{ + // gBottomTray->setVisible(TRUE); + // gBottomTray->getChatBox()->setFocus(TRUE); + //} - if (line && gChatBar->mInputEditor) - { - std::string line_string(line); - gChatBar->mInputEditor->setText(line_string); - } - // always move cursor to end so users don't obliterate chat when accidentally hitting WASD - gChatBar->mInputEditor->setCursorToEnd(); + // *TODO Vadim: Why was this code commented out? + +// gChatBar->setVisible(TRUE); +// gChatBar->setKeyboardFocus(TRUE); +// gSavedSettings.setBOOL("ChatVisible", TRUE); +// +// if (line && gChatBar->mInputEditor) +// { +// std::string line_string(line); +// gChatBar->mInputEditor->setText(line_string); +// } +// // always move cursor to end so users don't obliterate chat when accidentally hitting WASD +// gChatBar->mInputEditor->setCursorToEnd(); } @@ -452,21 +441,29 @@ void LLChatBar::startChat(const char* line) // static void LLChatBar::stopChat() { - // In simple UI mode, we never release focus from the chat bar - gChatBar->setKeyboardFocus(FALSE); + //TODO* remove DUMMY chat + //if(gBottomTray && gBottomTray->getChatBox()) + ///{ + // gBottomTray->getChatBox()->setFocus(FALSE); + //} - // If we typed a movement key and pressed return during the - // same frame, the keyboard handlers will see the key as having - // gone down this frame and try to move the avatar. - gKeyboard->resetKeys(); - gKeyboard->resetMaskKeys(); + // *TODO Vadim: Why was this code commented out? - // stop typing animation - gAgent.stopTyping(); - - // hide chat bar so it doesn't grab focus back - gChatBar->setVisible(FALSE); - gSavedSettings.setBOOL("ChatVisible", FALSE); +// // In simple UI mode, we never release focus from the chat bar +// gChatBar->setKeyboardFocus(FALSE); +// +// // If we typed a movement key and pressed return during the +// // same frame, the keyboard handlers will see the key as having +// // gone down this frame and try to move the avatar. +// gKeyboard->resetKeys(); +// gKeyboard->resetMaskKeys(); +// +// // stop typing animation +// gAgent.stopTyping(); +// +// // hide chat bar so it doesn't grab focus back +// gChatBar->setVisible(FALSE); +// gSavedSettings.setBOOL("ChatVisible", FALSE); } // static @@ -519,7 +516,7 @@ void LLChatBar::onInputEditorKeystroke( LLLineEditor* caller, void* userdata ) std::string utf8_trigger = wstring_to_utf8str(raw_text); std::string utf8_out_str(utf8_trigger); - if (gGestureManager.matchPrefix(utf8_trigger, &utf8_out_str)) + if (LLGestureManager::instance().matchPrefix(utf8_trigger, &utf8_out_str)) { if (self->mInputEditor) { @@ -553,20 +550,19 @@ void LLChatBar::onInputEditorGainFocus( LLFocusableElement* caller, void* userda LLFloaterChat::setHistoryCursorAndScrollToEnd(); } -// static -void LLChatBar::onClickSay( LLUICtrl* ctrl, void* userdata ) +void LLChatBar::onClickSay( LLUICtrl* ctrl ) { + std::string cmd = ctrl->getValue().asString(); e_chat_type chat_type = CHAT_TYPE_NORMAL; - if (ctrl->getValue().asString() == "shout") + if (cmd == "shout") { chat_type = CHAT_TYPE_SHOUT; } - else if (ctrl->getValue().asString() == "whisper") + else if (cmd == "whisper") { chat_type = CHAT_TYPE_WHISPER; } - LLChatBar* self = (LLChatBar*) userdata; - self->sendChat(chat_type); + sendChat(chat_type); } void LLChatBar::sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate) @@ -622,7 +618,7 @@ void LLChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL send_chat_from_viewer(utf8_out_text, type, channel); } - +/* void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) { LLMessageSystem* msg = gMessageSystem; @@ -639,13 +635,11 @@ void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); } +*/ - -// static -void LLChatBar::onCommitGesture(LLUICtrl* ctrl, void* data) +void LLChatBar::onCommitGesture(LLUICtrl* ctrl) { - LLChatBar* self = (LLChatBar*)data; - LLCtrlListInterface* gestures = self->mGestureCombo ? self->mGestureCombo->getListInterface() : NULL; + LLCtrlListInterface* gestures = mGestureCombo ? mGestureCombo->getListInterface() : NULL; if (gestures) { S32 index = gestures->getFirstSelectedIndex(); @@ -659,29 +653,23 @@ void LLChatBar::onCommitGesture(LLUICtrl* ctrl, void* data) // substitution and logging. std::string text(trigger); std::string revised_text; - gGestureManager.triggerAndReviseString(text, &revised_text); + LLGestureManager::instance().triggerAndReviseString(text, &revised_text); revised_text = utf8str_trim(revised_text); if (!revised_text.empty()) { // Don't play nodding animation - self->sendChatFromViewer(revised_text, CHAT_TYPE_NORMAL, FALSE); + sendChatFromViewer(revised_text, CHAT_TYPE_NORMAL, FALSE); } } - self->mGestureLabelTimer.start(); - if (self->mGestureCombo != NULL) + mGestureLabelTimer.start(); + if (mGestureCombo != NULL) { // free focus back to chat bar - self->mGestureCombo->setFocus(FALSE); + mGestureCombo->setFocus(FALSE); } } -void toggleChatHistory(void* user_data) -{ - LLFloaterChat::toggleInstance(LLSD()); -} - - class LLChatHandler : public LLCommandHandler { public: @@ -690,7 +678,7 @@ public: // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 2) return false; S32 channel = tokens[0].asInteger(); @@ -701,4 +689,4 @@ public: }; // Creating the object registers with the dispatcher. -LLChatHandler gChatHandler; +//LLChatHandler gChatHandler; diff --git a/indra/newview/llchatbar.h b/indra/newview/llchatbar.h index 56a98a78f9..a41947218d 100644 --- a/indra/newview/llchatbar.h +++ b/indra/newview/llchatbar.h @@ -45,6 +45,7 @@ class LLFrameTimer; class LLChatBarGestureObserver; class LLComboBox; + class LLChatBar : public LLPanel { @@ -82,14 +83,14 @@ public: LLWString stripChannelNumber(const LLWString &mesg, S32* channel); // callbacks - static void onClickSay( LLUICtrl*, void* userdata ); + void onClickSay(LLUICtrl* ctrl); static void onTabClick( void* userdata ); static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); static void onInputEditorFocusLost(LLFocusableElement* caller,void* userdata); static void onInputEditorGainFocus(LLFocusableElement* caller,void* userdata); - static void onCommitGesture(LLUICtrl* ctrl, void* data); + void onCommitGesture(LLUICtrl* ctrl); static void startChat(const char* line); static void stopChat(); diff --git a/indra/newview/llchatitemscontainerctrl.cpp b/indra/newview/llchatitemscontainerctrl.cpp new file mode 100644 index 0000000000..f5dfbb2851 --- /dev/null +++ b/indra/newview/llchatitemscontainerctrl.cpp @@ -0,0 +1,554 @@ +/** + * @file llchatitemscontainer.cpp + * @brief chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llchatitemscontainerctrl.h" +#include "lltextbox.h" + +#include "llchatmsgbox.h" +#include "llavatariconctrl.h" +#include "llfloaterreg.h" +#include "lltrans.h" + +#include "llviewercontrol.h" +#include "llagentdata.h" + +static const S32 BORDER_MARGIN = 2; +static const S32 PARENT_BORDER_MARGIN = 0; + +static const S32 HORIZONTAL_MULTIPLE = 8; +static const S32 VERTICAL_MULTIPLE = 16; +static const F32 MIN_AUTO_SCROLL_RATE = 120.f; +static const F32 MAX_AUTO_SCROLL_RATE = 500.f; +static const F32 AUTO_SCROLL_RATE_ACCEL = 120.f; + +static const S32 msg_left_offset = 30; +static const S32 msg_right_offset = 10; + +#define MAX_CHAT_HISTORY 100 + + +static LLDefaultChildRegistry::Register t2("chat_items_container"); + + + +//******************************************************************************************************************* +//LLChatItemCtrl +//******************************************************************************************************************* + +LLChatItemCtrl* LLChatItemCtrl::createInstance() +{ + LLChatItemCtrl* item = new LLChatItemCtrl(); + LLUICtrlFactory::getInstance()->buildPanel(item, "panel_chat_item.xml"); + return item; +} + +void LLChatItemCtrl::draw() +{ + LLPanel::draw(); +} + +void LLChatItemCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +{ + LLPanel::reshape(width, height,called_from_parent); + + // *NOTE: we must check if child items exist because reshape is called from the + // LLView::initFromParams BEFORE postBuild is called and child controls are not exist yet + LLPanel* caption = findChild("msg_caption", false); + LLChatMsgBox* msg_text = findChild("msg_text" ,false); + if(caption && msg_text) + { + LLRect caption_rect = caption->getRect(); + caption_rect.setLeftTopAndSize( 2, height, width - 4, caption_rect.getHeight()); + caption->reshape( width - 4, caption_rect.getHeight(), 1); + caption->setRect(caption_rect); + + LLRect msg_text_rect = msg_text->getRect(); + msg_text_rect.setLeftTopAndSize( msg_left_offset, height - caption_rect.getHeight() , width - msg_left_offset - msg_right_offset, height - caption_rect.getHeight()); + msg_text->reshape( width - msg_left_offset - msg_right_offset, height - caption_rect.getHeight(), 1); + msg_text->setRect(msg_text_rect); + } +} + +BOOL LLChatItemCtrl::postBuild() +{ + return LLPanel::postBuild(); +} + + +std::string LLChatItemCtrl::appendTime() +{ + time_t utc_time; + utc_time = time_corrected(); + std::string timeStr ="["+ LLTrans::getString("TimeHour")+"]:[" + +LLTrans::getString("TimeMin")+"] "; + + LLSD substitution; + + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + + return timeStr; +} + + + +void LLChatItemCtrl::addText (const std::string& message) +{ + LLChatMsgBox* msg_text = getChild("msg_text", false); + msg_text->addText(message); + mMessages.push_back(message); +} + +void LLChatItemCtrl::setMessage (const LLChat& msg) +{ + LLPanel* caption = getChild("msg_caption", false); + + std::string str_sender; + + + if(gAgentID != msg.mFromID) + str_sender = msg.mFromName; + else + str_sender = LLTrans::getString("You");; + + caption->getChild("sender_name", false)->setText(str_sender); + + std::string tt = appendTime(); + + caption->getChild("msg_time", false)->setText(tt); + + + caption->getChild("avatar_icon", false)->setValue(msg.mFromID); + + mOriginalMessage = msg; + + LLChatMsgBox* msg_text = getChild("msg_text", false); + msg_text->setText(msg.mText); + + LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); + if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + msg_inspector->setVisible(false); + + mMessages.clear(); + +} + +void LLChatItemCtrl::snapToMessageHeight () +{ + LLChatMsgBox* text_box = getChild("msg_text", false); + S32 new_height = text_box->getTextPixelHeight(); + LLRect panel_rect = getRect(); + + S32 caption_height = 0; + LLPanel* caption = getChild("msg_caption", false); + caption_height = caption->getRect().getHeight(); + + panel_rect.setLeftTopAndSize( panel_rect.mLeft, panel_rect.mTop, panel_rect.getWidth() , caption_height + new_height); + + reshape( getRect().getWidth(), caption_height + new_height, 1); + + setRect(panel_rect); + +} + + +void LLChatItemCtrl::setWidth(S32 width) +{ + LLChatMsgBox* text_box = getChild("msg_text", false); + text_box->reshape(width - msg_left_offset - msg_right_offset,100/*its not magic number, we just need any number*/); + + LLChatMsgBox* msg_text = getChild("msg_text", false); + if(mOriginalMessage.mText.length()) + msg_text->setText(mOriginalMessage.mText); + + for(size_t i=0;iaddText(mMessages[i]); + + setRect(LLRect(getRect().mLeft, getRect().mTop, getRect().mLeft + width , getRect().mBottom)); + snapToMessageHeight (); +} + +void LLChatItemCtrl::onMouseLeave (S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild("msg_caption", false); + LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); + msg_inspector->setVisible(false); + +} +void LLChatItemCtrl::onMouseEnter (S32 x, S32 y, MASK mask) +{ + if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + return; + LLPanel* caption = getChild("msg_caption", false); + LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); + msg_inspector->setVisible(true); +} + +BOOL LLChatItemCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +{ + if(mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + return LLPanel::handleMouseDown(x,y,mask); + LLPanel* caption = getChild("msg_caption", false); + LLUICtrl* msg_inspector = caption->getChild("msg_inspector"); + S32 local_x = x - msg_inspector->getRect().mLeft - caption->getRect().mLeft; + S32 local_y = y - msg_inspector->getRect().mBottom - caption->getRect().mBottom; + if(msg_inspector->pointInView(local_x, local_y)) + { + LLFloaterReg::showInstance("inspect_avatar", mOriginalMessage.mFromID); + } + return LLPanel::handleMouseDown(x,y,mask); +} + +void LLChatItemCtrl::setHeaderVisibility(EShowItemHeader e) +{ + LLPanel* caption = getChild("msg_caption", false); + + LLUICtrl* icon = caption->getChild("avatar_icon", false); + LLUICtrl* name = caption->getChild("sender_name", false); + + icon->setVisible(e == CHATITEMHEADER_SHOW_ONLY_ICON || e==CHATITEMHEADER_SHOW_BOTH); + name->setVisible(e == CHATITEMHEADER_SHOW_ONLY_NAME || e==CHATITEMHEADER_SHOW_BOTH); + +} + +bool LLChatItemCtrl::canAddText () +{ + LLChatMsgBox* msg_text = findChild("msg_text"); + if(!msg_text) + return false; + return msg_text->getTextLinesNum()<10; +} + +BOOL LLChatItemCtrl::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + LLPanel* caption = getChild("msg_caption", false); + LLUICtrl* avatar_icon = caption->getChild("avatar_icon", false); + + S32 local_x = x - avatar_icon->getRect().mLeft - caption->getRect().mLeft; + S32 local_y = y - avatar_icon->getRect().mBottom - caption->getRect().mBottom; + + //eat message for avatar icon if msg was from object + if(avatar_icon->pointInView(local_x, local_y) && mOriginalMessage.mSourceType != CHAT_SOURCE_AGENT) + return TRUE; + return LLPanel::handleRightMouseDown(x,y,mask); +} + + +//******************************************************************************************************************* +//LLChatItemsContainerCtrl +//******************************************************************************************************************* + +LLChatItemsContainerCtrl::LLChatItemsContainerCtrl(const Params& params):LLPanel(params) +{ + mEShowItemHeader = CHATITEMHEADER_SHOW_BOTH; +} + + +void LLChatItemsContainerCtrl::addMessage(const LLChat& msg) +{ + /* + if(msg.mChatType == CHAT_TYPE_DEBUG_MSG) + return; + */ + if(mItems.size() >= MAX_CHAT_HISTORY) + { + LLChatItemCtrl* item = mItems[0]; + removeChild(item); + delete item; + mItems.erase(mItems.begin()); + } + + + if(mItems.size() > 0 + && msg.mFromID == mItems[mItems.size()-1]->getMessage().mFromID + && (msg.mTime-mItems[mItems.size()-1]->getMessage().mTime)<60 + && mItems[mItems.size()-1]->canAddText() + ) + { + mItems[mItems.size()-1]->addText(msg.mText); + mItems[mItems.size()-1]->snapToMessageHeight(); + } + else + { + LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); + mItems.push_back(item); + addChild(item,0); + item->setWidth(getRect().getWidth() - 16); + item->setMessage(msg); + item->snapToMessageHeight(); + + item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + + item->setVisible(true); + } + + arrange(getRect().getWidth(),getRect().getHeight()); + updateLayout(getRect().getWidth(),getRect().getHeight()); + scrollToBottom(); +} + +void LLChatItemsContainerCtrl::scrollToBottom () +{ + if(mScrollbar->getVisible()) + { + mScrollbar->setDocPos(mScrollbar->getDocPosMax()); + onScrollPosChangeCallback(0,0); + } +} + +void LLChatItemsContainerCtrl::draw() +{ + LLLocalClipRect clip(getRect()); + LLPanel::draw(); +} + +void LLChatItemsContainerCtrl::reshape (S32 width, S32 height, BOOL called_from_parent ) +{ + S32 delta_width = width - getRect().getWidth(); + S32 delta_height = height - getRect().getHeight(); + + if (delta_width || delta_height || sForceReshape) + { + arrange(width, height); + } + + updateBoundingRect(); +} + +void LLChatItemsContainerCtrl::arrange (S32 width, S32 height) +{ + S32 delta_width = width - getRect().getWidth(); + if(delta_width)//width changed...too bad. now we need to reformat all items + reformatHistoryScrollItems(width); + + calcRecuiredHeight(); + + show_hide_scrollbar(width,height); + + updateLayout(width,height); +} + +void LLChatItemsContainerCtrl::reformatHistoryScrollItems(S32 width) +{ + for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) + { + (*it)->setWidth(width); + } +} + +S32 LLChatItemsContainerCtrl::calcRecuiredHeight () +{ + S32 rec_height = 0; + + std::vector::iterator it; + for(it=mItems.begin(); it!=mItems.end(); ++it) + { + rec_height += (*it)->getRect().getHeight(); + } + + mInnerRect.setLeftTopAndSize(0,rec_height + BORDER_MARGIN*2,getRect().getWidth(),rec_height + BORDER_MARGIN); + + return mInnerRect.getHeight(); +} + + +void LLChatItemsContainerCtrl::updateLayout (S32 width, S32 height) +{ + S32 panel_top = height - BORDER_MARGIN ; + S32 panel_width = width; + if(mScrollbar->getVisible()) + { + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + panel_top+=mScrollbar->getDocPos(); + panel_width-=scrollbar_size; + } + + + //set sizes for first panels and dragbars + for(size_t i=0;igetRect(); + panelSetLeftTopAndSize(mItems[i],panel_rect.mLeft,panel_top,panel_width,panel_rect.getHeight()); + panel_top-=panel_rect.getHeight(); + } +} + +void LLChatItemsContainerCtrl::show_hide_scrollbar (S32 width, S32 height) +{ + calcRecuiredHeight(); + if(getRecuiredHeight() > height ) + showScrollbar(width, height); + else + hideScrollbar(width, height); +} + +void LLChatItemsContainerCtrl::showScrollbar (S32 width, S32 height) +{ + bool was_visible = mScrollbar->getVisible(); + + mScrollbar->setVisible(true); + + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + panelSetLeftTopAndSize(mScrollbar,width-scrollbar_size + ,height-PARENT_BORDER_MARGIN,scrollbar_size,height-2*PARENT_BORDER_MARGIN); + + mScrollbar->setPageSize(height); + mScrollbar->setDocParams(mInnerRect.getHeight(),mScrollbar->getDocPos()); + + if(was_visible) + { + S32 scroll_pos = llmin(mScrollbar->getDocPos(), getRecuiredHeight() - height - 1); + mScrollbar->setDocPos(scroll_pos); + updateLayout(width,height); + return; + } +} + +void LLChatItemsContainerCtrl::hideScrollbar (S32 width, S32 height) +{ + if(mScrollbar->getVisible() == false) + return; + mScrollbar->setVisible(false); + + mScrollbar->setDocPos(0); + + if(mItems.size()>0) + { + S32 panel_top = height - BORDER_MARGIN; // Top coordinate of the first panel + S32 diff = panel_top - mItems[0]->getRect().mTop; + shiftPanels(diff); + } +} + +//--------------------------------------------------------------------------------- +void LLChatItemsContainerCtrl::panelSetLeftTopAndSize(LLView* panel, S32 left, S32 top, S32 width, S32 height) +{ + if(!panel) + return; + LLRect panel_rect = panel->getRect(); + panel_rect.setLeftTopAndSize( left, top, width, height); + panel->reshape( width, height, 1); + panel->setRect(panel_rect); +} + +void LLChatItemsContainerCtrl::panelShiftVertical(LLView* panel,S32 delta) +{ + if(!panel) + return; + panel->translate(0,delta); +} + +void LLChatItemsContainerCtrl::shiftPanels(S32 delta) +{ + //Arrange panels + for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) + { + panelShiftVertical((*it),delta); + } + +} + +//--------------------------------------------------------------------------------- + +void LLChatItemsContainerCtrl::onScrollPosChangeCallback(S32, LLScrollbar*) +{ + updateLayout(getRect().getWidth(),getRect().getHeight()); +} + +BOOL LLChatItemsContainerCtrl::postBuild() +{ + static LLUICachedControl scrollbar_size ("UIScrollbarSize", 0); + + LLRect scroll_rect; + scroll_rect.setOriginAndSize( + getRect().getWidth() - scrollbar_size, + 1, + scrollbar_size, + getRect().getHeight() - 1); + + + LLScrollbar::Params sbparams; + sbparams.name("scrollable vertical"); + sbparams.rect(scroll_rect); + sbparams.orientation(LLScrollbar::VERTICAL); + sbparams.doc_size(mInnerRect.getHeight()); + sbparams.doc_pos(0); + sbparams.page_size(mInnerRect.getHeight()); + sbparams.step_size(VERTICAL_MULTIPLE); + sbparams.follows.flags(FOLLOWS_RIGHT | FOLLOWS_TOP | FOLLOWS_BOTTOM); + sbparams.change_callback(boost::bind(&LLChatItemsContainerCtrl::onScrollPosChangeCallback, this, _1, _2)); + + mScrollbar = LLUICtrlFactory::create (sbparams); + LLView::addChild( mScrollbar ); + mScrollbar->setVisible( true ); + mScrollbar->setFollowsRight(); + mScrollbar->setFollowsTop(); + mScrollbar->setFollowsBottom(); + + reformatHistoryScrollItems(getRect().getWidth()); + arrange(getRect().getWidth(),getRect().getHeight()); + + return LLPanel::postBuild(); +} +BOOL LLChatItemsContainerCtrl::handleMouseDown (S32 x, S32 y, MASK mask) +{ + return LLPanel::handleMouseDown(x,y,mask); +} +BOOL LLChatItemsContainerCtrl::handleKeyHere (KEY key, MASK mask) +{ + if( mScrollbar->getVisible() && mScrollbar->handleKeyHere( key,mask ) ) + return TRUE; + return LLPanel::handleKeyHere(key,mask); +} +BOOL LLChatItemsContainerCtrl::handleScrollWheel ( S32 x, S32 y, S32 clicks ) +{ + if( mScrollbar->getVisible() && mScrollbar->handleScrollWheel( 0, 0, clicks ) ) + return TRUE; + return false; +} + +void LLChatItemsContainerCtrl::setHeaderVisibility(EShowItemHeader e) +{ + if(e == mEShowItemHeader) + return; + mEShowItemHeader = e; + for(std::vector::iterator it = mItems.begin(); it != mItems.end();++it) + { + (*it)->setHeaderVisibility(e); + } +} + + diff --git a/indra/newview/llchatitemscontainerctrl.h b/indra/newview/llchatitemscontainerctrl.h new file mode 100644 index 0000000000..de16cf9505 --- /dev/null +++ b/indra/newview/llchatitemscontainerctrl.h @@ -0,0 +1,154 @@ +/** + * @file llchatitemscontainer.h + * @brief chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCHATITEMSCONTAINER_H_ +#define LL_LLCHATITEMSCONTAINER_H_ + +#include "llpanel.h" +#include "llscrollbar.h" +#include "string" +#include "llchat.h" + +typedef enum e_show_item_header +{ + CHATITEMHEADER_SHOW_ONLY_NAME = 0, + CHATITEMHEADER_SHOW_ONLY_ICON = 1, + CHATITEMHEADER_SHOW_BOTH +} EShowItemHeader; + +class LLChatItemCtrl: public LLPanel +{ +protected: + LLChatItemCtrl(){}; +public: + + + ~LLChatItemCtrl(){} + + static LLChatItemCtrl* createInstance(); + + void draw(); + + const LLChat& getMessage() const { return mOriginalMessage;} + + void addText (const std::string& message); + void setMessage (const LLChat& msg); + void setWidth (S32 width); + void snapToMessageHeight (); + + bool canAddText (); + + void onMouseLeave (S32 x, S32 y, MASK mask); + void onMouseEnter (S32 x, S32 y, MASK mask); + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + + virtual BOOL postBuild(); + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + void setHeaderVisibility(EShowItemHeader e); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); +private: + + std::string appendTime (); + +private: + LLChat mOriginalMessage; + + std::vector mMessages; +}; + +class LLChatItemsContainerCtrl: public LLPanel +{ +public: + struct Params + : public LLInitParam::Block + { + Params(){}; + }; + + LLChatItemsContainerCtrl(const Params& params); + + + ~LLChatItemsContainerCtrl(){} + + void addMessage (const LLChat& msg); + + void draw(); + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + void onScrollPosChangeCallback(S32, LLScrollbar*); + + virtual BOOL postBuild(); + + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + BOOL handleKeyHere (KEY key, MASK mask); + BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + void scrollToBottom (); + + void setHeaderVisibility(EShowItemHeader e); + EShowItemHeader getHeaderVisibility() const { return mEShowItemHeader;}; + + +private: + void reformatHistoryScrollItems(S32 width); + void arrange (S32 width, S32 height); + + S32 calcRecuiredHeight (); + S32 getRecuiredHeight () const { return mInnerRect.getHeight(); } + + void updateLayout (S32 width, S32 height); + + void show_hide_scrollbar (S32 width, S32 height); + + void showScrollbar (S32 width, S32 height); + void hideScrollbar (S32 width, S32 height); + + void panelSetLeftTopAndSize (LLView* panel, S32 left, S32 top, S32 width, S32 height); + void panelShiftVertical (LLView* panel,S32 delta); + void shiftPanels (S32 delta); + +private: + std::vector mItems; + + EShowItemHeader mEShowItemHeader; + + LLRect mInnerRect; + LLScrollbar* mScrollbar; + +}; + +#endif + + diff --git a/indra/newview/llchatmsgbox.cpp b/indra/newview/llchatmsgbox.cpp new file mode 100644 index 0000000000..9399e1f68d --- /dev/null +++ b/indra/newview/llchatmsgbox.cpp @@ -0,0 +1,389 @@ +/** + * @file llchatmsgbox.cpp + * @brief chat history text box, able to show array of strings with separator + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llchatmsgbox.h" +#include "llwindow.h" +#include "llfocusmgr.h" + +static LLDefaultChildRegistry::Register r("text_chat"); + +LLChatMsgBox::Params::Params() +: text_color("text_color"), + highlight_on_hover("hover", false), + border_visible("border_visible", false), + border_drop_shadow_visible("border_drop_shadow_visible", false), + bg_visible("bg_visible", false), + use_ellipses("use_ellipses"), + word_wrap("word_wrap", false), + hover_color("hover_color"), + disabled_color("disabled_color"), + background_color("background_color"), + border_color("border_color"), + line_spacing("line_spacing", 4), + block_spacing("block_spacing",10), + text("text"), + font_shadow("font_shadow", LLFontGL::NO_SHADOW) +{} + +LLChatMsgBox::LLChatMsgBox(const LLChatMsgBox::Params& p) +: LLUICtrl(p), + mFontGL(p.font), + mHoverActive( p.highlight_on_hover ), + mHasHover( FALSE ), + mBackgroundVisible( p.bg_visible ), + mBorderVisible( p.border_visible ), + mShadowType( p.font_shadow ), + mBorderDropShadowVisible( p.border_drop_shadow_visible ), + mUseEllipses( p.use_ellipses ), + mVAlign( LLFontGL::TOP ), + mClickedCallback(NULL), + mTextColor(p.text_color()), + mDisabledColor(p.disabled_color()), + mBackgroundColor(p.background_color()), + mBorderColor(p.border_color()), + mHoverColor(p.hover_color()), + mHAlign(p.font_halign), + mLineSpacing(p.line_spacing), + mBlockSpasing(p.block_spacing), + mWordWrap( p.word_wrap ), + mFontStyle(LLFontGL::getStyleFromString(p.font.style)) +{ + setText( p.text() ); +} + +BOOL LLChatMsgBox::handleMouseDown(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback) + { + handled = TRUE; + + // Route future Mouse messages here preemptively. (Release on mouse up.) + gFocusMgr.setMouseCapture( this ); + + if (getSoundFlags() & MOUSE_DOWN) + { + make_ui_sound("UISndClick"); + } + } + + return handled; +} + +BOOL LLChatMsgBox::handleMouseUp(S32 x, S32 y, MASK mask) +{ + BOOL handled = FALSE; + + // We only handle the click if the click both started and ended within us + + // HACK: Only do this if there actually is a click callback, so that + // overly large text boxes in the older UI won't start eating clicks. + if (mClickedCallback + && hasMouseCapture()) + { + handled = TRUE; + + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + + if (getSoundFlags() & MOUSE_UP) + { + make_ui_sound("UISndClickRelease"); + } + + // DO THIS AT THE VERY END to allow the button to be destroyed as a result of being clicked. + // If mouseup in the widget, it's been clicked + if (mClickedCallback) + { + mClickedCallback(); + } + } + + return handled; +} + +BOOL LLChatMsgBox::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x,y,mask); + if(mHoverActive) + { + mHasHover = TRUE; // This should be set every frame during a hover. + getWindow()->setCursor(UI_CURSOR_ARROW); + } + + return (handled || mHasHover); +} + +void LLChatMsgBox::addText( const LLStringExplicit& text ) +{ + boost::shared_ptr t(new text_block()); + t->text = wrapText(text); + setLineLengths(*t); + mTextStrings.push_back(t); +} + +void LLChatMsgBox::setText(const LLStringExplicit& text) +{ + mTextStrings.clear(); + + addText(text); + +} + +void LLChatMsgBox::resetLineLengths() +{ + for(std::vector< boost::shared_ptr >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr tblock = *it; + setLineLengths(*tblock); + } +} + +void LLChatMsgBox::setLineLengths(text_block& t) +{ + t.lines.clear(); + + std::string::size_type cur = 0; + std::string::size_type len = t.text.length(); + + while (cur < len) + { + std::string::size_type end = t.text.getWString().find('\n', cur); + std::string::size_type runLen; + + if (end == std::string::npos) + { + runLen = len - cur; + cur = len; + } + else + { + runLen = end - cur; + cur = end + 1; // skip the new line character + } + + t.lines.push_back( (S32)runLen ); + } +} + +std::string LLChatMsgBox::wrapText(const LLStringExplicit& in_text, F32 max_width) +{ + if (max_width < 0.0f) + { + max_width = (F32)getRect().getWidth(); + } + + LLWString wtext = utf8str_to_wstring(in_text); + LLWString final_wtext; + + LLWString::size_type cur = 0;; + LLWString::size_type len = wtext.size(); + while (cur < len) + { + LLWString::size_type end = wtext.find('\n', cur); + if (end == LLWString::npos) + { + end = len; + } + + LLWString::size_type runLen = end - cur; + if (runLen > 0) + { + LLWString run(wtext, cur, runLen); + LLWString::size_type useLen = + mFontGL->maxDrawableChars(run.c_str(), max_width, runLen, TRUE); + + final_wtext.append(wtext, cur, useLen); + cur += useLen; + // not enough room to add any more characters + if (useLen == 0) break; + } + + if (cur < len) + { + if (wtext[cur] == '\n') + cur += 1; + else + final_wtext += '\n'; + } + } + + std::string final_text = wstring_to_utf8str(final_wtext); + return final_text; +} + +S32 LLChatMsgBox::getTextLinesNum() +{ + S32 num_lines = 0; + for(std::vector< boost::shared_ptr >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr tblock = *it; + num_lines+=tblock->lines.size(); + } + + if( num_lines < 1 ) + { + num_lines = 1; + } + + return num_lines; +} + +S32 LLChatMsgBox::getTextPixelHeight() +{ + S32 num_lines = getTextLinesNum(); + return (S32)(num_lines * mFontGL->getLineHeight() + (num_lines-1)*mLineSpacing + mBlockSpasing*(mTextStrings.size()-1) + 2*mLineSpacing);//some extra space +} + +void LLChatMsgBox::setValue(const LLSD& value ) +{ + setText(value.asString()); +} + + +void LLChatMsgBox::draw() +{ + if (mBorderVisible) + { + gl_rect_2d_offset_local(getLocalRect(), 2, FALSE); + } + + if( mBorderDropShadowVisible ) + { + static LLUICachedControl color_drop_shadow ("ColorDropShadow", *(new LLColor4)); + static LLUICachedControl drop_shadow_tooltip ("DropShadowTooltip", 0); + gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, + color_drop_shadow, drop_shadow_tooltip); + } + + if (mBackgroundVisible) + { + LLRect r( 0, getRect().getHeight(), getRect().getWidth(), 0 ); + gl_rect_2d( r, mBackgroundColor.get() ); + } + + S32 text_x = 0; + switch( mHAlign ) + { + case LLFontGL::LEFT: + break; + case LLFontGL::HCENTER: + text_x = getRect().getWidth() / 2; + break; + case LLFontGL::RIGHT: + text_x = getRect().getWidth() ; + break; + } + + S32 text_y = getRect().getHeight() ; + + if ( getEnabled() ) + { + if(mHasHover) + { + drawText( text_x, text_y, mHoverColor.get() ); + } + else + { + drawText( text_x, text_y, mTextColor.get() ); + } + } + else + { + drawText( text_x, text_y, mDisabledColor.get() ); + } + + if (sDebugRects) + { + drawDebugRect(); + } + + //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) + //std::set::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); + //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) + //{ + // drawDebugRect(); + //} + + mHasHover = FALSE; // This is reset every frame. +} + +void LLChatMsgBox::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + // reparse line lengths + LLView::reshape(width, height, called_from_parent); + resetLineLengths(); +} + +void LLChatMsgBox::drawText( S32 x, S32 y, const LLColor4& color ) +{ + S32 width = getRect().getWidth()-10; + + + for(std::vector< boost::shared_ptr >::iterator it = mTextStrings.begin(); + it!=mTextStrings.end();++it) + { + boost::shared_ptr tblock = *it; + + S32 cur_pos = 0; + for (std::vector::iterator iter = tblock->lines.begin(); + iter != tblock->lines.end(); ++iter) + { + S32 line_length = *iter; + mFontGL->render(tblock->text, cur_pos, (F32)x, (F32)y, color, + mHAlign, mVAlign, + mFontStyle, + mShadowType, + line_length, getRect().getWidth(), NULL, mUseEllipses ); + cur_pos += line_length + 1; + y -= llfloor(mFontGL->getLineHeight()) + mLineSpacing; + + } + std::vector< boost::shared_ptr >::iterator next = it; + ++next; + if(next == mTextStrings.end()) + break; + //separator + gl_line_2d(5,y-mBlockSpasing/2,width,y-mBlockSpasing/2,LLColor4::grey); + y-=mBlockSpasing; + } + +} + diff --git a/indra/newview/llchatmsgbox.h b/indra/newview/llchatmsgbox.h new file mode 100644 index 0000000000..61035499c7 --- /dev/null +++ b/indra/newview/llchatmsgbox.h @@ -0,0 +1,160 @@ +/** + * @file llchatmsgbox.h + * @brief chat history text box, able to show array of strings with separator + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLCHATMSGBOX_H +#define LL_LLCHATMSGBOX_H + + +#include "lluictrl.h" +#include "v4color.h" +#include "llstring.h" +#include "lluistring.h" + + +class LLChatMsgBox +: public LLUICtrl +{ +protected: + struct text_block + { + LLUIString text; + std::vector lines; + }; +public: + typedef boost::function callback_t; + + struct Params : public LLInitParam::Block + { + Optional text; + + Optional highlight_on_hover, + border_visible, + border_drop_shadow_visible, + bg_visible, + use_ellipses, + word_wrap; + + Optional font_shadow; + + Optional text_color, + hover_color, + disabled_color, + background_color, + border_color; + + Optional line_spacing; + + Optional block_spacing; + + Params(); + }; +protected: + LLChatMsgBox(const Params&); + friend class LLUICtrlFactory; +public: + virtual void draw(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + + void setColor( const LLColor4& c ) { mTextColor = c; } + void setDisabledColor( const LLColor4& c) { mDisabledColor = c; } + void setBackgroundColor( const LLColor4& c) { mBackgroundColor = c; } + void setBorderColor( const LLColor4& c) { mBorderColor = c; } + + void setHoverColor( const LLColor4& c ) { mHoverColor = c; } + void setHoverActive( BOOL active ) { mHoverActive = active; } + + void setText( const LLStringExplicit& text ); + void addText( const LLStringExplicit& text ); + + void setUseEllipses( BOOL use_ellipses ) { mUseEllipses = use_ellipses; } + + void setBackgroundVisible(BOOL visible) { mBackgroundVisible = visible; } + void setBorderVisible(BOOL visible) { mBorderVisible = visible; } + void setBorderDropshadowVisible(BOOL visible){ mBorderDropShadowVisible = visible; } + void setRightAlign() { mHAlign = LLFontGL::RIGHT; } + void setHAlign( LLFontGL::HAlign align ) { mHAlign = align; } + void setClickedCallback( boost::function cb, void* userdata = NULL ){ mClickedCallback = boost::bind(cb, userdata); } // mouse down and up within button + + const LLFontGL* getFont() const { return mFontGL; } + + S32 getTextPixelHeight(); + S32 getTextLinesNum(); + + virtual void setValue(const LLSD& value ); + + + +private: + std::string wrapText (const LLStringExplicit& in_text, F32 max_width = -1.0); + + void setLineLengths (text_block& t); + void resetLineLengths (); + void drawText (S32 x, S32 y, const LLColor4& color ); + + const LLFontGL* mFontGL; + LLUIColor mTextColor; + LLUIColor mDisabledColor; + LLUIColor mBackgroundColor; + LLUIColor mBorderColor; + LLUIColor mHoverColor; + + BOOL mHoverActive; + BOOL mHasHover; + BOOL mBackgroundVisible; + BOOL mBorderVisible; + BOOL mWordWrap; + + U8 mFontStyle; // style bit flags for font + LLFontGL::ShadowType mShadowType; + BOOL mBorderDropShadowVisible; + BOOL mUseEllipses; + + S32 mLineSpacing; + S32 mBlockSpasing; + + LLFontGL::HAlign mHAlign; + LLFontGL::VAlign mVAlign; + + callback_t mClickedCallback; + + + //same as mLineLengthList and mText in LLTextBox + std::vector< boost::shared_ptr > mTextStrings; + +}; + +#endif + diff --git a/indra/newview/llchiclet.cpp b/indra/newview/llchiclet.cpp new file mode 100644 index 0000000000..6b4dfa73a4 --- /dev/null +++ b/indra/newview/llchiclet.cpp @@ -0,0 +1,1184 @@ +/** +* @file llchiclet.cpp +* @brief LLChiclet class implementation +* +* $LicenseInfo:firstyear=2002&license=viewergpl$ +* +* Copyright (c) 2002-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" // must be first include +#include "llchiclet.h" +#include "llagent.h" +#include "llavataractions.h" +#include "llbottomtray.h" +#include "llgroupactions.h" +#include "lliconctrl.h" +#include "llimpanel.h" // LLFloaterIMPanel +#include "llimview.h" +#include "llfloaterreg.h" +#include "llmenugl.h" +#include "lloutputmonitorctrl.h" +#include "lltextbox.h" +#include "llvoiceclient.h" +#include "llvoicecontrolpanel.h" +#include "llgroupmgr.h" + +static const std::string P2P_MENU_NAME = "IMChiclet P2P Menu"; +static const std::string GROUP_MENU_NAME = "IMChiclet Group Menu"; + +static LLDefaultChildRegistry::Register t1("chiclet_panel"); +static LLDefaultChildRegistry::Register t2("chiclet_talk"); +static LLDefaultChildRegistry::Register t3("chiclet_notification"); +static LLDefaultChildRegistry::Register t4("chiclet_im"); + +S32 LLNotificationChiclet::mUreadSystemNotifications = 0; +S32 LLNotificationChiclet::mUreadIMNotifications = 0; + + +boost::signals2::signal > > + LLIMChiclet::sFindChicletsSignal; +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLNotificationChiclet::Params::Params() +: button("button") +, unread_notifications("unread_notifications") +{ + button.name("button"); + button.tab_stop(FALSE); + button.label(LLStringUtil::null); + + unread_notifications.name("unread"); + unread_notifications.font(LLFontGL::getFontSansSerif()); + unread_notifications.text_color=(LLColor4::white); + unread_notifications.font_halign(LLFontGL::HCENTER); + unread_notifications.mouse_opaque(FALSE); +} + +LLNotificationChiclet::LLNotificationChiclet(const Params& p) +: LLChiclet(p) +, mButton(NULL) +, mCounterCtrl(NULL) +, mNotificationChicletWindow(NULL) +{ + LLButton::Params button_params = p.button; + button_params.rect(p.rect()); + mButton = LLUICtrlFactory::create(button_params); + addChild(mButton); + + LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; + mCounterCtrl = LLUICtrlFactory::create(unread_params); + addChild(mCounterCtrl); +} + +LLNotificationChiclet::~LLNotificationChiclet() +{ + +} + +void LLNotificationChiclet::setCounter(S32 counter) +{ + mCounterCtrl->setCounter(counter); +} + +void LLNotificationChiclet::setShowCounter(bool show) +{ + LLChiclet::setShowCounter(show); + mCounterCtrl->setVisible(getShowCounter()); +} + +boost::signals2::connection LLNotificationChiclet::setClickCallback( + const commit_callback_t& cb) +{ + return mButton->setClickedCallback(cb); +} + +void LLNotificationChiclet::updateUreadIMNotifications() +{ + mUreadIMNotifications = gIMMgr->getNumberOfUnreadIM(); + setCounter(mUreadSystemNotifications + mUreadIMNotifications); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChiclet::Params::Params() + : show_counter("show_counter") +{ + show_counter = true; +} + +LLChiclet::LLChiclet(const Params& p) +: LLUICtrl(p) +, mSessionId(LLUUID::null) +, mShowCounter(p.show_counter) +{ + +} + +LLChiclet::~LLChiclet() +{ + +} + +boost::signals2::connection LLChiclet::setLeftButtonClickCallback( + const commit_callback_t& cb) +{ + return mCommitSignal.connect(cb); +} + +BOOL LLChiclet::handleMouseDown(S32 x, S32 y, MASK mask) +{ + onCommit(); + childrenHandleMouseDown(x,y,mask); + return TRUE; +} + +boost::signals2::connection LLChiclet::setChicletSizeChangedCallback( + const chiclet_size_changed_callback_t& cb) +{ + return mChicletSizeChangedSignal.connect(cb); +} + +void LLChiclet::onChicletSizeChanged() +{ + mChicletSizeChangedSignal(this, getValue()); +} + +LLSD LLChiclet::getValue() const +{ + return LLSD(getSessionId()); +} + +void LLChiclet::setValue(const LLSD& value) +{ + if(value.isUUID()) + setSessionId(value.asUUID()); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLIMChiclet::Params::Params() +: avatar_icon("avatar_icon") +, group_insignia("group_insignia") +, unread_notifications("unread_notifications") +, speaker("speaker") +, show_speaker("show_speaker") +{ + rect(LLRect(0, 25, 45, 0)); + + avatar_icon.name("avatar_icon"); + avatar_icon.visible(false); + avatar_icon.rect(LLRect(0, 25, 25, 0)); + + //it's an icon for a group in case there is a group chat created + group_insignia.name("group_icon"); + group_insignia.visible(false); + group_insignia.rect(LLRect(0, 25, 25, 0)); + + unread_notifications.name("unread"); + unread_notifications.rect(LLRect(25, 25, 45, 0)); + unread_notifications.font(LLFontGL::getFontSansSerif()); + unread_notifications.font_halign(LLFontGL::HCENTER); + unread_notifications.v_pad(5); + unread_notifications.text_color(LLColor4::white); + + speaker.name("speaker"); + speaker.rect(LLRect(45, 25, 65, 0)); + + show_speaker = false; +} + +LLIMChiclet::LLIMChiclet(const Params& p) +: LLChiclet(p) +, LLGroupMgrObserver(LLUUID()) +, mAvatarCtrl(NULL) +, mGroupInsignia(NULL) +, mCounterCtrl(NULL) +, mSpeakerCtrl(NULL) +, mShowSpeaker(p.show_speaker) +, mPopupMenu(NULL) +{ + LLChicletAvatarIconCtrl::Params avatar_params = p.avatar_icon; + mAvatarCtrl = LLUICtrlFactory::create(avatar_params); + addChild(mAvatarCtrl); + + //Before setOtherParticipantId() we are UNAWARE which dialog type will it be + //so keeping both icons for all both p2p and group chat cases + LLIconCtrl::Params grop_icon_params = p.group_insignia; + mGroupInsignia = LLUICtrlFactory::create(grop_icon_params); + addChild(mGroupInsignia); + + LLChicletNotificationCounterCtrl::Params unread_params = p.unread_notifications; + mCounterCtrl = LLUICtrlFactory::create(unread_params); + addChild(mCounterCtrl); + + setCounter(getCounter()); + setShowCounter(getShowCounter()); + + LLChicletSpeakerCtrl::Params speaker_params = p.speaker; + mSpeakerCtrl = LLUICtrlFactory::create(speaker_params); + addChild(mSpeakerCtrl); + + setShowSpeaker(getShowSpeaker()); +} + +LLIMChiclet::~LLIMChiclet() +{ + LLGroupMgr::getInstance()->removeObserver(this); +} + + +void LLIMChiclet::setCounter(S32 counter) +{ + mCounterCtrl->setCounter(counter); + + if(getShowCounter()) + { + LLRect counter_rect = mCounterCtrl->getRect(); + LLRect required_rect = mCounterCtrl->getRequiredRect(); + bool needs_resize = required_rect.getWidth() != counter_rect.getWidth(); + + if(needs_resize) + { + counter_rect.mRight = counter_rect.mLeft + required_rect.getWidth(); + mCounterCtrl->reshape(counter_rect.getWidth(), counter_rect.getHeight()); + mCounterCtrl->setRect(counter_rect); + + onChicletSizeChanged(); + } + } +} + +void LLIMChiclet::onMouseDown() +{ + LLIMFloater::toggle(getSessionId()); + setCounter(0); +} + +LLRect LLIMChiclet::getRequiredRect() +{ + LLRect rect(0, 0, mAvatarCtrl->getRect().getWidth(), 0); + if(getShowCounter()) + { + rect.mRight += mCounterCtrl->getRequiredRect().getWidth(); + } + if(getShowSpeaker()) + { + rect.mRight += mSpeakerCtrl->getRect().getWidth(); + } + return rect; +} + +void LLIMChiclet::setShowCounter(bool show) +{ + bool needs_resize = getShowCounter() != show; + + LLChiclet::setShowCounter(show); + mCounterCtrl->setVisible(getShowCounter()); + + if(needs_resize) + { + onChicletSizeChanged(); + } +} + + +void LLIMChiclet::setSessionId(const LLUUID& session_id) +{ + LLChiclet::setSessionId(session_id); + + //for a group chat session_id = group_id + LLFloaterIMPanel* im = LLIMMgr::getInstance()->findFloaterBySession(session_id); + if (!im) return; //should never happen + + EInstantMessage type = im->getDialogType(); + if (type == IM_SESSION_INVITE || type == IM_SESSION_GROUP_START) + { + if (!gAgent.isInGroup(session_id)) return; + + if (mGroupInsignia) { + LLGroupMgr* grp_mgr = LLGroupMgr::getInstance(); + LLGroupMgrGroupData* group_data = grp_mgr->getGroupData(session_id); + if (group_data && group_data->mInsigniaID.notNull()) + { + mGroupInsignia->setVisible(TRUE); + mGroupInsignia->setValue(group_data->mInsigniaID); + } + else + { + mID = session_id; //needed for LLGroupMgrObserver + grp_mgr->addObserver(this); + grp_mgr->sendGroupPropertiesRequest(session_id); + } + } + } +} + +void LLIMChiclet::setIMSessionName(const std::string& name) +{ + setToolTip(name); +} + +//session id should be set before calling this +void LLIMChiclet::setOtherParticipantId(const LLUUID& other_participant_id) +{ + llassert(getSessionId().notNull()); + + LLFloaterIMPanel*floater = gIMMgr->findFloaterBySession(getSessionId()); + + //all alive sessions have alive floater, haven't they? + llassert(floater); + + mOtherParticipantId = other_participant_id; + + if (mAvatarCtrl && floater->getDialogType() == IM_NOTHING_SPECIAL) + { + mAvatarCtrl->setVisible(TRUE); + mAvatarCtrl->setValue(other_participant_id); + } +} + + +void LLIMChiclet::changed(LLGroupChange gc) +{ + LLSD group_insignia = mGroupInsignia->getValue(); + if (group_insignia.isUUID() && group_insignia.asUUID().notNull()) return; + + if (GC_PROPERTIES == gc) + { + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(getSessionId()); + if (group_data && group_data->mInsigniaID.notNull()) + { + mGroupInsignia->setVisible(TRUE); + mGroupInsignia->setValue(group_data->mInsigniaID); + } + } +} + +LLUUID LLIMChiclet::getOtherParticipantId() +{ + return mOtherParticipantId; +} + +void LLIMChiclet::updateMenuItems() +{ + if(!mPopupMenu) + return; + if(getSessionId().isNull()) + return; + + if(P2P_MENU_NAME == mPopupMenu->getName()) + { + bool is_friend = LLAvatarActions::isFriend(getOtherParticipantId()); + + mPopupMenu->getChild("Add Friend")->setEnabled(!is_friend); + mPopupMenu->getChild("Remove Friend")->setEnabled(is_friend); + } +} + +BOOL LLIMChiclet::handleMouseDown(S32 x, S32 y, MASK mask) +{ + onMouseDown(); + return LLChiclet::handleMouseDown(x, y, mask); +} + +void LLIMChiclet::setShowSpeaker(bool show) +{ + bool needs_resize = getShowSpeaker() != show; + + mShowSpeaker = show; + mSpeakerCtrl->setVisible(getShowSpeaker()); + + if(needs_resize) + { + onChicletSizeChanged(); + } +} + +void LLIMChiclet::draw() +{ + LLUICtrl::draw(); + + //if we have a docked floater, we want to position it relative to us + LLIMFloater* im_floater = LLFloaterReg::findTypedInstance("impanel", getSessionId()); + + if (im_floater && im_floater->isDocked()) + { + S32 x, y; + getParent()->localPointToScreen(getRect().getCenterX(), 0, &x, &y); + im_floater->translate(x - im_floater->getRect().getCenterX(), 10 - im_floater->getRect().mBottom); + //set this so the docked floater knows it's been positioned and can now draw + im_floater->setPositioned(true); + } + + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0, LLColor4(0.0f,0.0f,0.0f,1.f), FALSE); +} + +BOOL LLIMChiclet::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if(!mPopupMenu) + createPopupMenu(); + + updateMenuItems(); + + if (mPopupMenu) + { + mPopupMenu->arrangeAndClear(); + } + + LLMenuGL::showPopup(this, mPopupMenu, x, y); + + return TRUE; +} + +void LLIMChiclet::createPopupMenu() +{ + if(mPopupMenu) + { + llwarns << "Menu already exists" << llendl; + return; + } + if(getSessionId().isNull()) + return; + + LLFloaterIMPanel*floater = gIMMgr->findFloaterBySession(getSessionId()); + if(!floater) + return; + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("IMChicletMenu.Action", boost::bind(&LLIMChiclet::onMenuItemClicked, this, _2)); + + switch(floater->getDialogType()) + { + case IM_SESSION_GROUP_START: + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile + ("menu_imchiclet_group.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + break; + case IM_NOTHING_SPECIAL: + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile + ("menu_imchiclet_p2p.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + break; + default: + llwarns << "Unexpected dialog type" << llendl; + break; + } +} + +void LLIMChiclet::onMenuItemClicked(const LLSD& user_data) +{ + std::string level = user_data.asString(); + LLUUID other_participant_id = getOtherParticipantId(); + + if("profile" == level) + { + LLAvatarActions::showProfile(other_participant_id); + } + else if("im" == level) + { + LLAvatarActions::startIM(other_participant_id); + } + else if("add" == level) + { + LLAvatarActions::requestFriendshipDialog(other_participant_id); + } + else if("group chat" == level) + { + LLGroupActions::startChat(other_participant_id); + } + else if("info" == level) + { + LLGroupActions::show(other_participant_id); + } +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletPanel::Params::Params() +: chiclet_padding("chiclet_padding") +, scrolling_offset("scrolling_offset") +, left_scroll_button("left_scroll_button") +, right_scroll_button("right_scroll_button") +, min_width("min_width") +{ + chiclet_padding = 3; + scrolling_offset = 40; + min_width = 70; + + LLRect scroll_button_rect(0, 25, 19, 5); + + left_scroll_button.name("left_scroll"); + left_scroll_button.label(LLStringUtil::null); + left_scroll_button.rect(scroll_button_rect); + left_scroll_button.tab_stop(false); + left_scroll_button.image_selected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + left_scroll_button.image_unselected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + left_scroll_button.image_hover_selected(LLUI::getUIImage("bottom_tray_scroll_left.tga")); + + right_scroll_button.name("right_scroll"); + right_scroll_button.label(LLStringUtil::null); + right_scroll_button.rect(scroll_button_rect); + right_scroll_button.tab_stop(false); + right_scroll_button.image_selected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); + right_scroll_button.image_unselected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); + right_scroll_button.image_hover_selected(LLUI::getUIImage("bottom_tray_scroll_right.tga")); +}; + +LLChicletPanel::LLChicletPanel(const Params&p) +: LLPanel(p) +, mScrollArea(NULL) +, mLeftScrollButton(NULL) +, mRightScrollButton(NULL) +, mChicletPadding(p.chiclet_padding) +, mScrollingOffset(p.scrolling_offset) +, mMinWidth(p.min_width) +, mShowControls(true) +{ + LLButton::Params scroll_button_params = p.left_scroll_button; + + mLeftScrollButton = LLUICtrlFactory::create(scroll_button_params); + addChild(mLeftScrollButton); + + mLeftScrollButton->setClickedCallback(boost::bind(&LLChicletPanel::onLeftScrollClick,this)); + mLeftScrollButton->setEnabled(false); + + scroll_button_params = p.right_scroll_button; + mRightScrollButton = LLUICtrlFactory::create(scroll_button_params); + addChild(mRightScrollButton); + + mRightScrollButton->setClickedCallback(boost::bind(&LLChicletPanel::onRightScrollClick,this)); + mRightScrollButton->setEnabled(false); + + LLPanel::Params panel_params; + mScrollArea = LLUICtrlFactory::create(panel_params,this); + addChild(mScrollArea); +} + +LLChicletPanel::~LLChicletPanel() +{ + +} + +void im_chiclet_callback(LLChicletPanel* panel, const LLSD& data){ + + LLUUID session_id = data["session_id"].asUUID(); + std::list chiclets = LLIMChiclet::sFindChicletsSignal(session_id); + std::list::iterator iter; + for (iter = chiclets.begin(); iter != chiclets.end(); iter++) { + LLChiclet* chiclet = *iter; + if (chiclet != NULL) + { + chiclet->setCounter(data["num_unread"].asInteger()); + } + else + { + llwarns << "Unable to set counter for chiclet " << session_id << llendl; + } + } + +} + + +BOOL LLChicletPanel::postBuild() +{ + LLPanel::postBuild(); + LLIMModel::instance().addChangedCallback(boost::bind(im_chiclet_callback, this, _1)); + LLIMChiclet::sFindChicletsSignal.connect(boost::bind(&LLChicletPanel::findChiclet, this, _1)); + + return TRUE; +} + +bool LLChicletPanel::addChiclet(LLChiclet* chiclet, S32 index) +{ + if(mScrollArea->addChild(chiclet)) + { + S32 offset = 0; + // Do not scroll chiclets if chiclets are scrolled right and new + // chiclet is added to the beginning of the list + if(canScrollLeft()) + { + offset = - (chiclet->getRequiredRect().getWidth() + getChicletPadding()); + if(0 == index) + { + offset += getChiclet(0)->getRect().mLeft; + } + } + + mChicletList.insert(mChicletList.begin() + index, chiclet); + + getChiclet(0)->translate(offset, 0); + + chiclet->setLeftButtonClickCallback(boost::bind(&LLChicletPanel::onChicletClick, this, _1, _2)); + chiclet->setChicletSizeChangedCallback(boost::bind(&LLChicletPanel::onChicletSizeChanged, this, _1, index)); + + arrange(); + showScrollButtonsIfNeeded(); + + return true; + } + + return false; +} + +void LLChicletPanel::onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param) +{ + S32 chiclet_width = ctrl->getRect().getWidth(); + S32 chiclet_new_width = ctrl->getRequiredRect().getWidth(); + + if(chiclet_new_width == chiclet_width) + { + return; + } + + LLRect chiclet_rect = ctrl->getRect(); + chiclet_rect.mRight = chiclet_rect.mLeft + chiclet_new_width; + + ctrl->setRect(chiclet_rect); + + S32 offset = chiclet_new_width - chiclet_width; + S32 index = getChicletIndex(ctrl); + + shiftChiclets(offset, index + 1); + trimChiclets(); + showScrollButtonsIfNeeded(); +} + +void LLChicletPanel::onChicletClick(LLUICtrl*ctrl,const LLSD¶m) +{ + mCommitSignal(ctrl,param); +} + +void LLChicletPanel::removeChiclet(chiclet_list_t::iterator it) +{ + mScrollArea->removeChild(*it); + mChicletList.erase(it); + + arrange(); + trimChiclets(); + showScrollButtonsIfNeeded(); +} + +void LLChicletPanel::removeChiclet(S32 index) +{ + if(index >= 0 && index < getChicletCount()) + { + removeChiclet(mChicletList.begin() + index); + } +} + +S32 LLChicletPanel::getChicletIndex(const LLChiclet* chiclet) +{ + if(mChicletList.empty()) + return -1; + + S32 size = getChicletCount(); + for(int n = 0; n < size; ++n) + { + if(chiclet == mChicletList[n]) + return n; + } + + return -1; +} + +void LLChicletPanel::removeChiclet(LLChiclet*chiclet) +{ + chiclet_list_t::iterator it = mChicletList.begin(); + for( ; mChicletList.end() != it; ++it) + { + LLChiclet* temp = *it; + if(temp == chiclet) + { + removeChiclet(it); + return; + } + } +} + +void LLChicletPanel::removeChiclet(const LLUUID& im_session_id) +{ + chiclet_list_t::iterator it = mChicletList.begin(); + for( ; mChicletList.end() != it; ++it) + { + LLIMChiclet* chiclet = dynamic_cast(*it); + + if(chiclet->getSessionId() == im_session_id) + { + removeChiclet(it); + return; + } + } +} + +void LLChicletPanel::removeAll() +{ + S32 size = getChicletCount(); + for(S32 n = 0; n < size; ++n) + { + mScrollArea->removeChild(mChicletList[n]); + } + + mChicletList.erase(mChicletList.begin(), mChicletList.end()); + + showScrollButtonsIfNeeded(); +} + +void LLChicletPanel::reshape(S32 width, S32 height, BOOL called_from_parent ) +{ + LLPanel::reshape(width,height,called_from_parent); + + static const S32 SCROLL_BUTTON_PAD = 5; + + LLRect scroll_button_rect = mLeftScrollButton->getRect(); + mLeftScrollButton->setRect(LLRect(0,height,scroll_button_rect.getWidth(), + height - scroll_button_rect.getHeight())); + + scroll_button_rect = mRightScrollButton->getRect(); + mRightScrollButton->setRect(LLRect(width - scroll_button_rect.getWidth(),height, + width, height - scroll_button_rect.getHeight())); + + mScrollArea->setRect(LLRect(scroll_button_rect.getWidth() + SCROLL_BUTTON_PAD, + height + 7, width - scroll_button_rect.getWidth() - SCROLL_BUTTON_PAD, 0)); + + mShowControls = width > mMinWidth; + mScrollArea->setVisible(mShowControls); + + trimChiclets(); + + showScrollButtonsIfNeeded(); +} + +void LLChicletPanel::arrange() +{ + if(mChicletList.empty()) + return; + + S32 chiclet_left = getChiclet(0)->getRect().mLeft; + + S32 size = getChicletCount(); + for( int n = 0; n < size; ++n) + { + LLChiclet* chiclet = getChiclet(n); + + S32 chiclet_width = chiclet->getRequiredRect().getWidth(); + LLRect rect = chiclet->getRect(); + rect.set(chiclet_left, rect.mTop, chiclet_left + chiclet_width, rect.mBottom); + + chiclet->setRect(rect); + + chiclet_left += chiclet_width + getChicletPadding(); + } +} + +void LLChicletPanel::trimChiclets() +{ + // trim right + if(canScrollLeft() && !canScrollRight()) + { + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + S32 scroll_width = mScrollArea->getRect().getWidth(); + if(last_chiclet_right < scroll_width) + { + shiftChiclets(scroll_width - last_chiclet_right); + } + } + + // trim left + if(!mChicletList.empty()) + { + LLRect first_chiclet_rect = getChiclet(0)->getRect(); + if(first_chiclet_rect.mLeft > 0) + { + shiftChiclets( - first_chiclet_rect.mLeft); + } + } +} + +void LLChicletPanel::showScrollButtonsIfNeeded() +{ + bool can_scroll_left = canScrollLeft(); + bool can_scroll_right = canScrollRight(); + + mLeftScrollButton->setEnabled(can_scroll_left); + mRightScrollButton->setEnabled(can_scroll_right); + + bool show_scroll_buttons = (can_scroll_left || can_scroll_right) && mShowControls; + + mLeftScrollButton->setVisible(show_scroll_buttons); + mRightScrollButton->setVisible(show_scroll_buttons); +} + +void LLChicletPanel::draw() +{ + child_list_const_iter_t it = getChildList()->begin(); + for( ; getChildList()->end() != it; ++it) + { + LLView* child = *it; + if(child == dynamic_cast(mScrollArea)) + { + LLLocalClipRect clip(mScrollArea->getRect()); + drawChild(mScrollArea); + } + else + { + drawChild(child); + } + } +} + +bool LLChicletPanel::canScrollRight() +{ + if(mChicletList.empty()) + return false; + + S32 scroll_width = mScrollArea->getRect().getWidth(); + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + + if(last_chiclet_right > scroll_width) + return true; + + return false; +} + +bool LLChicletPanel::canScrollLeft() +{ + if(mChicletList.empty()) + return false; + + return getChiclet(0)->getRect().mLeft < 0; +} + +void LLChicletPanel::scroll(S32 offset) +{ + shiftChiclets(offset); +} + +void LLChicletPanel::shiftChiclets(S32 offset, S32 start_index /* = 0 */) +{ + if(start_index < 0 || start_index >= getChicletCount()) + { + return; + } + + chiclet_list_t::const_iterator it = mChicletList.begin() + start_index; + for(;mChicletList.end() != it; ++it) + { + LLChiclet* chiclet = *it; + chiclet->translate(offset,0); + } +} + +void LLChicletPanel::scrollLeft() +{ + if(canScrollLeft()) + { + S32 offset = getScrollingOffset(); + LLRect first_chiclet_rect = getChiclet(0)->getRect(); + + // shift chiclets in case first chiclet is partially visible + if(first_chiclet_rect.mLeft < 0 && first_chiclet_rect.mRight > 0) + { + offset = llabs(first_chiclet_rect.mLeft); + } + + scroll(offset); + + showScrollButtonsIfNeeded(); + } +} + +void LLChicletPanel::scrollRight() +{ + if(canScrollRight()) + { + S32 offset = - getScrollingOffset(); + + S32 last_chiclet_right = (*mChicletList.rbegin())->getRect().mRight; + S32 scroll_rect_width = mScrollArea->getRect().getWidth(); + // if after scrolling, the last chiclet will not be aligned to + // scroll area right side - align it. + if( last_chiclet_right + offset < scroll_rect_width ) + { + offset = scroll_rect_width - last_chiclet_right; + } + + scroll(offset); + + showScrollButtonsIfNeeded(); + } +} + +void LLChicletPanel::onLeftScrollClick() +{ + scrollLeft(); +} + +void LLChicletPanel::onRightScrollClick() +{ + scrollRight(); +} + +boost::signals2::connection LLChicletPanel::setChicletClickedCallback( + const commit_callback_t& cb) +{ + return mCommitSignal.connect(cb); +} + +BOOL LLChicletPanel::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if(clicks > 0) + { + scrollRight(); + } + else + { + scrollLeft(); + } + return TRUE; +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLTalkButton::Params::Params() + : speak_button("speak_button") + , show_button("show_button") + , monitor("monitor") +{ + speak_button.name("left"); + speak_button.label("Speak"); + speak_button.label_selected("Speak"); + speak_button.font(LLFontGL::getFontSansSerifSmall()); + speak_button.tab_stop(false); + speak_button.is_toggle(true); + speak_button.picture_style(true); + speak_button.image_selected(LLUI::getUIImage("SegmentedBtn_Left_Selected")); + speak_button.image_unselected(LLUI::getUIImage("SegmentedBtn_Left_Off")); + + show_button.name("right"); + show_button.label(LLStringUtil::null); + show_button.rect(LLRect(0, 0, 20, 0)); + show_button.tab_stop(false); + show_button.is_toggle(true); + show_button.picture_style(true); + show_button.image_selected(LLUI::getUIImage("ComboButton_Selected")); + show_button.image_unselected(LLUI::getUIImage("ComboButton_Off")); + + monitor.name("monitor"); + // *TODO: Make this data driven. + monitor.rect(LLRect(0, 18, 18, 0)); +} + +LLTalkButton::LLTalkButton(const Params& p) +: LLUICtrl(p) +, mPrivateCallPanel(NULL) +, mOutputMonitor(NULL) +, mSpeakBtn(NULL) +, mShowBtn(NULL) +{ + LLRect rect = p.rect(); + LLRect speak_rect(0, rect.getHeight(), rect.getWidth(), 0); + LLRect show_rect = p.show_button.rect(); + show_rect.set(0, rect.getHeight(), show_rect.getWidth(), 0); + + speak_rect.mRight -= show_rect.getWidth(); + show_rect.mLeft = speak_rect.getWidth(); + show_rect.mRight = rect.getWidth(); + + LLButton::Params speak_params = p.speak_button; + speak_params.rect(speak_rect); + mSpeakBtn = LLUICtrlFactory::create(speak_params); + addChild(mSpeakBtn); + + mSpeakBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_SpeakBtn, this)); + mSpeakBtn->setToggleState(FALSE); + + LLButton::Params show_params = p.show_button; + show_params.rect(show_rect); + mShowBtn = LLUICtrlFactory::create(show_params); + addChild(mShowBtn); + + mShowBtn->setClickedCallback(boost::bind(&LLTalkButton::onClick_ShowBtn, this)); + mShowBtn->setToggleState(FALSE); + + static const S32 MONITOR_RIGHT_PAD = 2; + + LLRect monitor_rect = p.monitor.rect(); + S32 monitor_height = monitor_rect.getHeight(); + monitor_rect.mLeft = speak_rect.getWidth() - monitor_rect.getWidth() - MONITOR_RIGHT_PAD; + monitor_rect.mRight = speak_rect.getWidth() - MONITOR_RIGHT_PAD; + monitor_rect.mBottom = (rect.getHeight() / 2) - (monitor_height / 2); + monitor_rect.mTop = monitor_rect.mBottom + monitor_height; + + LLOutputMonitorCtrl::Params monitor_params = p.monitor; + monitor_params.draw_border(false); + monitor_params.rect(monitor_rect); + mOutputMonitor = LLUICtrlFactory::create(monitor_params); + mSpeakBtn->addChild(mOutputMonitor); + + // never show "muted" because you can't mute yourself + mOutputMonitor->setIsMuted(false); +} + +LLTalkButton::~LLTalkButton() +{ +} + +void LLTalkButton::draw() +{ + // Always provide speaking feedback. User can trigger speaking + // with keyboard or middle-mouse shortcut. + mOutputMonitor->setPower(gVoiceClient->getCurrentPower(gAgent.getID())); + mOutputMonitor->setIsTalking( gVoiceClient->getUserPTTState() ); + mSpeakBtn->setToggleState( gVoiceClient->getUserPTTState() ); + + LLUICtrl::draw(); +} + +void LLTalkButton::setSpeakBtnToggleState(bool state) +{ + mSpeakBtn->setToggleState(state); +} + +void LLTalkButton::onClick_SpeakBtn() +{ + bool speaking = mSpeakBtn->getToggleState(); + gVoiceClient->setUserPTTState(speaking); +} + +void LLTalkButton::onClick_ShowBtn() +{ + if(!mShowBtn->getToggleState()) + { + mPrivateCallPanel->onClickClose(mPrivateCallPanel); + delete mPrivateCallPanel; + mPrivateCallPanel = NULL; + mShowBtn->setToggleState(FALSE); + return; + } + + S32 x = mSpeakBtn->getRect().mLeft; + S32 y = 0; + + localPointToScreen(x, y, &x, &y); + + mPrivateCallPanel = new LLVoiceControlPanel; + getRootView()->addChild(mPrivateCallPanel); + + y = LLBottomTray::getInstance()->getRect().getHeight() + mPrivateCallPanel->getRect().getHeight(); + + LLRect rect; + rect.setLeftTopAndSize(x, y, mPrivateCallPanel->getRect().getWidth(), mPrivateCallPanel->getRect().getHeight()); + mPrivateCallPanel->setRect(rect); + + LLAvatarListItem::Params p; + p.buttons.status = true; + p.buttons.info = true; + p.buttons.profile = false; + p.buttons.locator = true; + + mPrivateCallPanel->addItem(new LLAvatarListItem(p)); + mPrivateCallPanel->setVisible(TRUE); + mPrivateCallPanel->setFrontmost(TRUE); + + mShowBtn->setToggleState(TRUE); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletNotificationCounterCtrl::LLChicletNotificationCounterCtrl(const Params& p) + : LLTextBox(p) + , mCounter(0) + , mInitialWidth(0) +{ + mInitialWidth = getRect().getWidth(); +} + +void LLChicletNotificationCounterCtrl::setCounter(S32 counter) +{ + mCounter = counter; + + std::stringstream stream; + stream << getCounter(); + if(mCounter != 0) + { + setText(stream.str()); + } + else + { + setText(std::string("")); + } +} + +LLRect LLChicletNotificationCounterCtrl::getRequiredRect() +{ + LLRect rc; + S32 text_width = getFont()->getWidth(getText()); + + rc.mRight = rc.mLeft + llmax(text_width, mInitialWidth); + + return rc; +} + +void LLChicletNotificationCounterCtrl::setValue(const LLSD& value) +{ + if(value.isInteger()) + setCounter(value.asInteger()); +} + +LLSD LLChicletNotificationCounterCtrl::getValue() const +{ + return LLSD(getCounter()); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletAvatarIconCtrl::LLChicletAvatarIconCtrl(const Params& p) + : LLAvatarIconCtrl(p) +{ +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLChicletSpeakerCtrl::LLChicletSpeakerCtrl(const Params&p) + : LLIconCtrl(p) +{ +} diff --git a/indra/newview/llchiclet.h b/indra/newview/llchiclet.h new file mode 100644 index 0000000000..b1e73c9d8d --- /dev/null +++ b/indra/newview/llchiclet.h @@ -0,0 +1,730 @@ +/** +* @file llchiclet.h +* @brief LLChiclet class header file +* +* $LicenseInfo:firstyear=2002&license=viewergpl$ +* +* Copyright (c) 2002-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLCHICLET_H +#define LL_LLCHICLET_H + +#include "llavatariconctrl.h" +#include "llbutton.h" +#include "llpanel.h" +#include "lltextbox.h" +#include "lloutputmonitorctrl.h" +#include "llgroupmgr.h" + +class LLVoiceControlPanel; +class LLMenuGL; +class LLIMFloater; + +/* + * Class for displaying amount of messages/notifications(unread). +*/ +class LLChicletNotificationCounterCtrl : public LLTextBox +{ +public: + + struct Params : public LLInitParam::Block + { + Params() + {}; + }; + + /* + * Sets number of notifications + */ + virtual void setCounter(S32 counter); + + /* + * Returns number of notifications + */ + virtual S32 getCounter() const { return mCounter; } + + /* + * Returns width, required to display amount of notifications in text form. + * Width is the only valid value. + */ + /*virtual*/ LLRect getRequiredRect(); + + /* + * Sets number of notifications using LLSD + */ + /*virtual*/ void setValue(const LLSD& value); + + /* + * Returns number of notifications wrapped in LLSD + */ + /*virtual*/ LLSD getValue() const; + +protected: + + LLChicletNotificationCounterCtrl(const Params& p); + friend class LLUICtrlFactory; + +private: + + S32 mCounter; + S32 mInitialWidth; +}; + +/* + * Class for displaying avatar's icon. +*/ +class LLChicletAvatarIconCtrl : public LLAvatarIconCtrl +{ +public: + + struct Params : public LLInitParam::Block + { + Params() + { + draw_tooltip(FALSE); + mouse_opaque(FALSE); + }; + }; + +protected: + + LLChicletAvatarIconCtrl(const Params& p); + friend class LLUICtrlFactory; +}; + +/* + * Class for displaying status of Voice Chat +*/ +class LLChicletSpeakerCtrl : public LLIconCtrl +{ +public: + + struct Params : public LLInitParam::Block + { + Params(){}; + }; +protected: + + LLChicletSpeakerCtrl(const Params&p); + friend class LLUICtrlFactory; +}; + +/* + * Base class for all chiclets. + */ +class LLChiclet : public LLUICtrl +{ +public: + + struct Params : public LLInitParam::Block + { + Optional show_counter; + + Params(); + }; + + /*virtual*/ ~LLChiclet(); + + /* + * Associates chat session id with chiclet. + */ + virtual void setSessionId(const LLUUID& session_id) { mSessionId = session_id; } + + /* + * Returns associated chat session. + */ + virtual const LLUUID& getSessionId() const { return mSessionId; } + + /* + * Sets number of unread notifications. + */ + virtual void setCounter(S32 counter) = 0; + + /* + * Returns number of unread notifications. + */ + virtual S32 getCounter() = 0; + + /* + * Sets show counter state. + */ + virtual void setShowCounter(bool show) { mShowCounter = show; } + + /* + * Returns show counter state. + */ + virtual bool getShowCounter() {return mShowCounter;}; + + /* + * Connects chiclet clicked event with callback. + */ + /*virtual*/ boost::signals2::connection setLeftButtonClickCallback( + const commit_callback_t& cb); + + typedef boost::function + chiclet_size_changed_callback_t; + + /* + * Connects chiclets size changed event with callback. + */ + virtual boost::signals2::connection setChicletSizeChangedCallback( + const chiclet_size_changed_callback_t& cb); + + /* + * Sets IM Session id using LLSD + */ + /*virtual*/ LLSD getValue() const; + + /* + * Returns IM Session id using LLSD + */ + /*virtual*/ void setValue(const LLSD& value); + +protected: + + friend class LLUICtrlFactory; + LLChiclet(const Params& p); + + /* + * Notifies subscribers about click on chiclet. + */ + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + + /* + * Notifies subscribers about chiclet size changed event. + */ + virtual void onChicletSizeChanged(); + +private: + + LLUUID mSessionId; + + bool mShowCounter; + + typedef boost::signals2::signal + chiclet_size_changed_signal_t; + + chiclet_size_changed_signal_t mChicletSizeChangedSignal; +}; + +/* +* Implements Instant Message chiclet. +* IMChiclet displays avatar's icon, number of unread messages(optional) +* and voice chat status(optional). +*/ +class LLIMChiclet : public LLChiclet, LLGroupMgrObserver +{ +public: + struct Params : public LLInitParam::Block + { + Optional avatar_icon; + + Optional group_insignia; + + Optional unread_notifications; + + Optional speaker; + + Optional show_speaker; + + Params(); + }; + + /*virtual*/ ~LLIMChiclet(); + + virtual void setSessionId(const LLUUID& session_id); + + /* + * Sets IM session name. This name will be displayed in chiclet tooltip. + */ + virtual void setIMSessionName(const std::string& name); + + /* + * Sets id of person/group user is chatting with. + * Session id should be set before calling this + */ + virtual void setOtherParticipantId(const LLUUID& other_participant_id); + + /* + * Gets id of person/group user is chatting with. + */ + virtual LLUUID getOtherParticipantId(); + + /* + * Shows/hides voice chat status control. + */ + virtual void setShowSpeaker(bool show); + + /* + * Returns voice chat status control visibility. + */ + virtual bool getShowSpeaker() {return mShowSpeaker;}; + + /* + * Sets number of unread messages. Will update chiclet's width if number text + * exceeds size of counter and notify it's parent about size change. + */ + /*virtual*/ void setCounter(S32); + + /* + * Returns number of unread messages. + */ + /*virtual*/ S32 getCounter() { return mCounterCtrl->getCounter(); } + + /* + * Shows/hides number of unread messages. + */ + /*virtual*/ void setShowCounter(bool show); + + /* + * Draws border around chiclet. + */ + /*virtual*/ void draw(); + + /** + * The action taken on mouse down event. + * + * Made public so that it can be triggered from outside + * (more specifically, from the Active IM window). + */ + void onMouseDown(); + + /* + * Returns rect, required to display chiclet. + * Width is the only valid value. + */ + /*virtual*/ LLRect getRequiredRect(); + + /** comes from LLGroupMgrObserver */ + virtual void changed(LLGroupChange gc); + +protected: + + LLIMChiclet(const Params& p); + friend class LLUICtrlFactory; + + /* + * Creates chiclet popup menu. Will create P2P or Group IM Chat menu + * based on other participant's id. + */ + virtual void createPopupMenu(); + + /* + * Processes clicks on chiclet popup menu. + */ + virtual void onMenuItemClicked(const LLSD& user_data); + + /* + * Enables/disables menus based on relationship with other participant. + */ + virtual void updateMenuItems(); + + /* + * Displays popup menu. + */ + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + +protected: + LLChicletAvatarIconCtrl* mAvatarCtrl; + + /** the icon of a group in case of group chat */ + LLIconCtrl* mGroupInsignia; + LLChicletNotificationCounterCtrl* mCounterCtrl; + LLChicletSpeakerCtrl* mSpeakerCtrl; + + LLMenuGL* mPopupMenu; + + bool mShowSpeaker; + + /** the id of another participant, either an avatar id or a group id*/ + LLUUID mOtherParticipantId; + + template + struct CollectChicletCombiner { + typedef Container result_type; + + template + Container operator()(InputIterator first, InputIterator last) const { + Container c = Container(); + for (InputIterator iter = first; iter != last; iter++) { + if (*iter != NULL) { + c.push_back(*iter); + } + } + return c; + } + }; + +public: + static boost::signals2::signal > > + sFindChicletsSignal; +}; + +/* + * Implements notification chiclet. Used to display total amount of unread messages + * across all IM sessions, total amount of system notifications. +*/ +class LLNotificationChiclet : public LLChiclet +{ +public: + + struct Params : public LLInitParam::Block + { + Optional button; + + Optional unread_notifications; + + Params(); + }; + + /*virtual*/ void setCounter(S32 counter); + + /*virtual*/S32 getCounter() { return mCounterCtrl->getCounter(); } + + /*virtual*/ void setShowCounter(bool show); + + boost::signals2::connection setClickCallback(const commit_callback_t& cb); + + /*virtual*/ ~ LLNotificationChiclet(); + + // Notification Chiclet Window + void setNotificationChicletWindow(LLFloater* wnd) { mNotificationChicletWindow = wnd; } + + // methods for updating a number of unread System or IM notifications + void incUreadSystemNotifications() { setCounter(++mUreadSystemNotifications + mUreadIMNotifications); } + void decUreadSystemNotifications() { setCounter(--mUreadSystemNotifications + mUreadIMNotifications); } + void updateUreadIMNotifications(); + +protected: + LLNotificationChiclet(const Params& p); + friend class LLUICtrlFactory; + + LLFloater* mNotificationChicletWindow; + + static S32 mUreadSystemNotifications; + static S32 mUreadIMNotifications; + +protected: + LLButton* mButton; + LLChicletNotificationCounterCtrl* mCounterCtrl; +}; + +/* + * Storage class for all IM chiclets. Provides mechanism to display, + * scroll, create, remove chiclets. +*/ +class LLChicletPanel : public LLPanel +{ +public: + + struct Params : public LLInitParam::Block + { + Optional chiclet_padding, + scrolling_offset; + + Optional left_scroll_button, + right_scroll_button; + + Optional min_width; + + Params(); + }; + + virtual ~LLChicletPanel(); + + /* + * Creates chiclet and adds it to chiclet list. + */ + template T* createChiclet(const LLUUID& session_id = LLUUID::null, S32 index = 0); + + /* + * Returns pointer to chiclet of specified type at specified index. + */ + template T* getChiclet(S32 index); + + /* + * Returns pointer to LLChiclet at specified index. + */ + LLChiclet* getChiclet(S32 index) { return getChiclet(index); } + + /* + * Searches a chiclet using IM session id. + */ + template T* findChiclet(const LLUUID& im_session_id); + + /* + * Returns number of hosted chiclets. + */ + S32 getChicletCount() {return mChicletList.size();}; + + /* + * Returns index of chiclet in list. + */ + S32 getChicletIndex(const LLChiclet* chiclet); + + /* + * Removes chiclet by index. + */ + void removeChiclet(S32 index); + + /* + * Removes chiclet by pointer. + */ + void removeChiclet(LLChiclet* chiclet); + + /* + * Removes chiclet by IM session id. + */ + void removeChiclet(const LLUUID& im_session_id); + + /* + * Removes all chiclets. + */ + void removeAll(); + + boost::signals2::connection setChicletClickedCallback( + const commit_callback_t& cb); + + /*virtual*/ BOOL postBuild(); + + /* + * Reshapes controls and rearranges chiclets if needed. + */ + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE ); + + /*virtual*/ void draw(); + +protected: + LLChicletPanel(const Params&p); + friend class LLUICtrlFactory; + + /* + * Adds chiclet to list and rearranges all chiclets. + */ + bool addChiclet(LLChiclet*, S32 index); + + /* + * Arranges chiclets. + */ + void arrange(); + + /* + * Returns true if chiclets can be scrolled right. + */ + bool canScrollRight(); + + /* + * Returns true if chiclets can be scrolled left. + */ + bool canScrollLeft(); + + /* + * Shows or hides chiclet scroll buttons if chiclets can or can not be scrolled. + */ + void showScrollButtonsIfNeeded(); + + /* + * Shifts chiclets left or right. + */ + void shiftChiclets(S32 offset, S32 start_index = 0); + + /* + * Removes gaps between first chiclet and scroll area left side, + * last chiclet and scroll area right side. + */ + void trimChiclets(); + + /* + * Scrolls chiclets to right or left. + */ + void scroll(S32 offset); + + /* + * Verifies that chiclets can be scrolled left, then calls scroll() + */ + void scrollLeft(); + + /* + * Verifies that chiclets can be scrolled right, then calls scroll() + */ + void scrollRight(); + + /* + * Callback for left scroll button clicked + */ + void onLeftScrollClick(); + + /* + * Callback for right scroll button clicked + */ + void onRightScrollClick(); + + /* + * Callback for mouse wheel scrolled, calls scrollRight() or scrollLeft() + */ + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + + /* + * Notifies subscribers about click on chiclet. + * Do not place any code here, instead subscribe on event (see setChicletClickedCallback). + */ + void onChicletClick(LLUICtrl*ctrl,const LLSD¶m); + + /* + * Callback for chiclet size changed event, rearranges chiclets. + */ + void onChicletSizeChanged(LLChiclet* ctrl, const LLSD& param); + + typedef std::vector chiclet_list_t; + + /* + * Removes chiclet from scroll area and chiclet list. + */ + void removeChiclet(chiclet_list_t::iterator it); + + S32 getChicletPadding() { return mChicletPadding; } + + S32 getScrollingOffset() { return mScrollingOffset; } + +protected: + + chiclet_list_t mChicletList; + LLButton* mLeftScrollButton; + LLButton* mRightScrollButton; + LLPanel* mScrollArea; + + S32 mChicletPadding; + S32 mScrollingOffset; + S32 mMinWidth; + bool mShowControls; +}; + +/* + * Button displaying voice chat status. Displays voice chat options When clicked. +*/ +class LLTalkButton : public LLUICtrl +{ +public: + + struct Params : public LLInitParam::Block + { + Optional speak_button, + show_button; + + Optional monitor; + + Params(); + }; + + /*virtual*/ ~LLTalkButton(); + + /*virtual*/ void draw(); + void setSpeakBtnToggleState(bool state); + +protected: + friend class LLUICtrlFactory; + LLTalkButton(const Params& p); + + void onClick_SpeakBtn(); + + void onClick_ShowBtn(); + +private: + LLButton* mSpeakBtn; + LLButton* mShowBtn; + LLVoiceControlPanel* mPrivateCallPanel; + LLOutputMonitorCtrl* mOutputMonitor; +}; + +template +T* LLChicletPanel::createChiclet(const LLUUID& session_id /*= LLUUID::null*/, S32 index /*= 0*/) +{ + typename T::Params params; + T* chiclet = LLUICtrlFactory::create(params); + if(!chiclet) + { + llwarns << "Could not create chiclet" << llendl; + return NULL; + } + if(!addChiclet(chiclet, index)) + { + delete chiclet; + llwarns << "Could not add chiclet to chiclet panel" << llendl; + return NULL; + } + + chiclet->setSessionId(session_id); + + return chiclet; +} + +template +T* LLChicletPanel::findChiclet(const LLUUID& im_session_id) +{ + if(im_session_id.isNull()) + { + return NULL; + } + + chiclet_list_t::const_iterator it = mChicletList.begin(); + for( ; mChicletList.end() != it; ++it) + { + LLChiclet* chiclet = *it; + + if(chiclet->getSessionId() == im_session_id) + { + T* result = dynamic_cast(chiclet); + if(!result && chiclet) + { + llwarns << "Found chiclet but of wrong type " << llendl; + } + return result; + } + } + return NULL; +} + +template T* LLChicletPanel::getChiclet(S32 index) +{ + if(index < 0 || index >= getChicletCount()) + { + return NULL; + } + + LLChiclet* chiclet = mChicletList[index]; + T*result = dynamic_cast(chiclet); + if(!result && chiclet) + { + llwarns << "Found chiclet but of wrong type " << llendl; + } + return result; +} + +#endif // LL_LLCHICLET_H diff --git a/indra/newview/llclassifiedstatsresponder.cpp b/indra/newview/llclassifiedstatsresponder.cpp index a218e2b4e5..ecd1879090 100644 --- a/indra/newview/llclassifiedstatsresponder.cpp +++ b/indra/newview/llclassifiedstatsresponder.cpp @@ -33,7 +33,6 @@ #include "llviewerprecompiledheaders.h" -#include "llagent.h" #include "llclassifiedstatsresponder.h" #include "llpanelclassified.h" diff --git a/indra/newview/llclassifiedstatsresponder.h b/indra/newview/llclassifiedstatsresponder.h index c4591df8de..9c52ed5ae1 100644 --- a/indra/newview/llclassifiedstatsresponder.h +++ b/indra/newview/llclassifiedstatsresponder.h @@ -44,6 +44,7 @@ public: //If we get back a normal response, handle it here virtual void result(const LLSD& content); //If we get back an error (not found, etc...), handle it here + virtual void error(U32 status, const std::string& reason); protected: diff --git a/indra/newview/llcloud.cpp b/indra/newview/llcloud.cpp index 0099817de4..af6f4e3286 100644 --- a/indra/newview/llcloud.cpp +++ b/indra/newview/llcloud.cpp @@ -37,6 +37,7 @@ #include "v3math.h" #include "v4math.h" #include "llquaternion.h" +#include "llrand.h" #include "v4color.h" #include "llwind.h" diff --git a/indra/newview/llcloud.h b/indra/newview/llcloud.h index f4ae03b689..155bf4eae9 100644 --- a/indra/newview/llcloud.h +++ b/indra/newview/llcloud.h @@ -72,7 +72,7 @@ #include "v3dmath.h" #include "v4math.h" #include "v4color.h" -#include "llmemory.h" +#include "llpointer.h" #include "lldarray.h" #include "llframetimer.h" diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp index 5f8d9ed27b..31c2d93c05 100644 --- a/indra/newview/llcolorswatch.cpp +++ b/indra/newview/llcolorswatch.cpp @@ -37,74 +37,69 @@ // Linden library includes #include "v4color.h" +#include "llwindow.h" // setCursor() // Project includes #include "llui.h" #include "llrender.h" #include "lluiconstants.h" -#include "llviewerwindow.h" #include "llviewercontrol.h" #include "llbutton.h" #include "lltextbox.h" #include "llfloatercolorpicker.h" #include "llviewborder.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llfocusmgr.h" -static LLRegisterWidget r("color_swatch"); +static LLDefaultChildRegistry::Register r("color_swatch"); -LLColorSwatchCtrl::LLColorSwatchCtrl(const std::string& name, const LLRect& rect, const LLColor4& color, - void (*commit_callback)(LLUICtrl* ctrl, void* userdata), - void* userdata ) -: LLUICtrl(name, rect, TRUE, commit_callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP), - mValid( TRUE ), - mColor( color ), - mBorderColor( gColors.getColor("DefaultHighlightLight") ), - mCanApplyImmediately(FALSE), - mOnCancelCallback(NULL), - mOnSelectCallback(NULL) +LLColorSwatchCtrl::Params::Params() +: color("color", LLColor4::white), + can_apply_immediately("can_apply_immediately", false), + alpha_background_image("alpha_background_image"), + border_color("border_color"), + label_width("label_width", -1), + caption_text("caption_text"), + border("border") { - mCaption = new LLTextBox( name, - LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ), - name, - LLFontGL::getFontSansSerifSmall() ); - mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); - addChild( mCaption ); - - // Scalable UI made this off-by-one, I don't know why. JC - LLRect border_rect(0, getRect().getHeight()-1, getRect().getWidth()-1, 0); - border_rect.mBottom += BTN_HEIGHT_SMALL; - mBorder = new LLViewBorder(std::string("border"), border_rect, LLViewBorder::BEVEL_IN); - addChild(mBorder); - - mAlphaGradientImage = LLUI::getUIImage("color_swatch_alpha.tga"); + name = "colorswatch"; } -LLColorSwatchCtrl::LLColorSwatchCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLColor4& color, - void (*commit_callback)(LLUICtrl* ctrl, void* userdata), - void* userdata ) -: LLUICtrl(name, rect, TRUE, commit_callback, userdata, FOLLOWS_LEFT | FOLLOWS_TOP), +LLColorSwatchCtrl::LLColorSwatchCtrl(const Params& p) +: LLUICtrl(p), mValid( TRUE ), - mColor( color ), - mBorderColor( gColors.getColor("DefaultHighlightLight") ), - mCanApplyImmediately(FALSE), - mOnCancelCallback(NULL), - mOnSelectCallback(NULL) -{ - mCaption = new LLTextBox( label, - LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ), - label, - LLFontGL::getFontSansSerifSmall() ); - mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); + mColor(p.color), + mCanApplyImmediately(p.can_apply_immediately), + mAlphaGradientImage(p.alpha_background_image), + mOnCancelCallback(p.cancel_callback()), + mOnSelectCallback(p.select_callback()), + mBorderColor(p.border_color()), + mLabelWidth(p.label_width) +{ + LLTextBox::Params tp = p.caption_text; + // label_width is specified, not -1 + if(mLabelWidth!= -1) + { + tp.rect(LLRect( 0, BTN_HEIGHT_SMALL, mLabelWidth, 0 )); + } + else + { + tp.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 )); + } + + tp.text(p.label); + mCaption = LLUICtrlFactory::create(tp); addChild( mCaption ); - // Scalable UI made this off-by-one, I don't know why. JC - LLRect border_rect(0, getRect().getHeight()-1, getRect().getWidth()-1, 0); + LLRect border_rect = getLocalRect(); + border_rect.mTop -= 1; + border_rect.mRight -=1; border_rect.mBottom += BTN_HEIGHT_SMALL; - mBorder = new LLViewBorder(std::string("border"), border_rect, LLViewBorder::BEVEL_IN); - addChild(mBorder); - mAlphaGradientImage = LLUI::getUIImage("color_swatch_alpha.tga"); + LLViewBorder::Params params = p.border; + params.rect(border_rect); + mBorder = LLUICtrlFactory::create (params); + addChild(mBorder); } LLColorSwatchCtrl::~LLColorSwatchCtrl () @@ -114,9 +109,8 @@ LLColorSwatchCtrl::~LLColorSwatchCtrl () if (pickerp) { pickerp->cancelSelection(); - pickerp->close(); + pickerp->closeFloater(); } - mAlphaGradientImage = NULL; } BOOL LLColorSwatchCtrl::handleDoubleClick(S32 x, S32 y, MASK mask) @@ -206,7 +200,7 @@ void LLColorSwatchCtrl::draw() mBorder->setKeyboardFocusHighlight(hasFocus()); // Draw border LLRect border( 0, getRect().getHeight(), getRect().getWidth(), BTN_HEIGHT_SMALL ); - gl_rect_2d( border, mBorderColor, FALSE ); + gl_rect_2d( border, mBorderColor.get(), FALSE ); LLRect interior = border; interior.stretch( -1 ); @@ -233,7 +227,7 @@ void LLColorSwatchCtrl::draw() { if (!mFallbackImageName.empty()) { - LLPointer fallback_image = gImageList.getImageFromFile(mFallbackImageName); + LLPointer fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); if( fallback_image->getComponents() == 4 ) { gl_rect_2d_checkerboard( interior ); @@ -264,7 +258,7 @@ void LLColorSwatchCtrl::setEnabled( BOOL enabled ) if (pickerp) { pickerp->cancelSelection(); - pickerp->close(); + pickerp->closeFloater(); } } } @@ -295,11 +289,11 @@ void LLColorSwatchCtrl::onColorChanged ( void* data, EColorPickOp pick_op ) if (pick_op == COLOR_CANCEL && subject->mOnCancelCallback) { - subject->mOnCancelCallback(subject, subject->mCallbackUserData); + subject->mOnCancelCallback( subject, LLSD()); } else if (pick_op == COLOR_SELECT && subject->mOnSelectCallback) { - subject->mOnSelectCallback(subject, subject->mCallbackUserData); + subject->mOnSelectCallback( subject, LLSD() ); } else { @@ -343,59 +337,3 @@ void LLColorSwatchCtrl::showPicker(BOOL take_focus) } } -// virtual -LLXMLNodePtr LLColorSwatchCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("color", TRUE)->setFloatValue(4, mColor.mV); - - node->createChild("border_color", TRUE)->setFloatValue(4, mBorderColor.mV); - - if (mCaption) - { - node->createChild("label", TRUE)->setStringValue(mCaption->getText()); - } - - node->createChild("can_apply_immediately", TRUE)->setBoolValue(mCanApplyImmediately); - - return node; -} - -LLView* LLColorSwatchCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("colorswatch"); - node->getAttributeString("name", name); - - std::string label; - node->getAttributeString("label", label); - - LLColor4 color(1.f, 1.f, 1.f, 1.f); - node->getAttributeColor("initial_color", color); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL can_apply_immediately = FALSE; - node->getAttributeBOOL("can_apply_immediately", can_apply_immediately); - - LLUICtrlCallback callback = NULL; - - if (label.empty()) - { - label.assign(node->getValue()); - } - - LLColorSwatchCtrl* color_swatch = new LLColorSwatchCtrl( - name, - rect, - label, - color, - callback, - NULL ); - - color_swatch->setCanApplyImmediately(can_apply_immediately); - color_swatch->initFromXML(node, parent); - - return color_swatch; -} diff --git a/indra/newview/llcolorswatch.h b/indra/newview/llcolorswatch.h index 0dd021f51f..e3e267f831 100644 --- a/indra/newview/llcolorswatch.h +++ b/indra/newview/llcolorswatch.h @@ -36,7 +36,8 @@ #include "lluictrl.h" #include "v4color.h" #include "llfloater.h" -#include "llviewerimage.h" +#include "llviewertexture.h" +#include "lltextbox.h" // // Classes @@ -44,7 +45,7 @@ class LLColor4; class LLTextBox; class LLFloaterColorPicker; -class LLViewerImage; +class LLViewerTexture; class LLColorSwatchCtrl : public LLUICtrl @@ -57,53 +58,65 @@ public: COLOR_CANCEL } EColorPickOp; - LLColorSwatchCtrl(const std::string& name, const LLRect& rect, const LLColor4& color, - void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata), - void* callback_userdata); - LLColorSwatchCtrl(const std::string& name, const LLRect& rect, const std::string& label, const LLColor4& color, - void (*on_commit_callback)(LLUICtrl* ctrl, void* userdata), - void* callback_userdata); + struct Params : public LLInitParam::Block + { + Optional color; + Optional can_apply_immediately; + Optional alpha_background_image; + Optional cancel_callback; + Optional select_callback; + Optional border_color; + Optional label_width; + + Optional caption_text; + Optional border; + Params(); + }; +protected: + LLColorSwatchCtrl(const Params& p); + friend class LLUICtrlFactory; +public: ~LLColorSwatchCtrl (); - virtual void setValue(const LLSD& value); + /*virtual*/ void setValue(const LLSD& value); - virtual LLSD getValue() const { return mColor.getValue(); } + /*virtual*/ LLSD getValue() const { return mColor.getValue(); } const LLColor4& get() { return mColor; } void set(const LLColor4& color, BOOL update_picker = FALSE, BOOL from_event = FALSE); void setOriginal(const LLColor4& color); void setValid(BOOL valid); void setLabel(const std::string& label); + void setLabelWidth(S32 label_width) {mLabelWidth =label_width;} void setCanApplyImmediately(BOOL apply) { mCanApplyImmediately = apply; } - void setOnCancelCallback(LLUICtrlCallback cb) { mOnCancelCallback = cb; } - void setOnSelectCallback(LLUICtrlCallback cb) { mOnSelectCallback = cb; } + void setOnCancelCallback(commit_callback_t cb) { mOnCancelCallback = cb; } + void setOnSelectCallback(commit_callback_t cb) { mOnSelectCallback = cb; } void setFallbackImageName(const std::string& name) { mFallbackImageName = name; } void showPicker(BOOL take_focus); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); - virtual BOOL handleDoubleClick(S32 x,S32 y,MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - virtual void draw(); - virtual void setEnabled( BOOL enabled ); - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x,S32 y,MASK mask); + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleUnicodeCharHere(llwchar uni_char); + /*virtual*/ void draw(); + /*virtual*/ void setEnabled( BOOL enabled ); static void onColorChanged ( void* data, EColorPickOp pick_op = COLOR_CHANGE ); protected: BOOL mValid; LLColor4 mColor; - LLColor4 mBorderColor; + LLUIColor mBorderColor; LLTextBox* mCaption; LLHandle mPickerHandle; LLViewBorder* mBorder; BOOL mCanApplyImmediately; - LLUICtrlCallback mOnCancelCallback; - LLUICtrlCallback mOnSelectCallback; + commit_callback_t mOnCancelCallback; + commit_callback_t mOnSelectCallback; + S32 mLabelWidth; LLPointer mAlphaGradientImage; std::string mFallbackImageName; diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp index 422c94ade5..a04182a910 100644 --- a/indra/newview/llcommandhandler.cpp +++ b/indra/newview/llcommandhandler.cpp @@ -55,7 +55,7 @@ public: bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); private: @@ -84,7 +84,7 @@ void LLCommandHandlerRegistry::add(const char* cmd, bool require_trusted_browser bool LLCommandHandlerRegistry::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { std::map::iterator it = mMap.find(cmd); @@ -126,7 +126,7 @@ LLCommandHandler::~LLCommandHandler() bool LLCommandDispatcher::dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { return LLCommandHandlerRegistry::instance().dispatch( diff --git a/indra/newview/llcommandhandler.h b/indra/newview/llcommandhandler.h index ab4c2cc488..5cb3ee73d4 100644 --- a/indra/newview/llcommandhandler.h +++ b/indra/newview/llcommandhandler.h @@ -47,7 +47,7 @@ public: // Your code here bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (tokens.size() < 1) return false; LLUUID id( tokens[0] ); @@ -60,7 +60,7 @@ LLFooHandler gFooHandler; */ -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLCommandHandler { @@ -68,14 +68,14 @@ public: LLCommandHandler(const char* command, bool allow_from_untrusted_browser); // Automatically registers object to get called when // command is executed. All commands can be processed - // in links from LLWebBrowserCtrl, but some (like teleport) + // in links from LLMediaCtrl, but some (like teleport) // should not be allowed from outside the app. virtual ~LLCommandHandler(); virtual bool handle(const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web) = 0; + LLMediaCtrl* web) = 0; // For URL secondlife:///app/foo/bar/baz?cat=1&dog=2 // @params - array of "bar", "baz", possibly empty // @query_map - map of "cat" -> 1, "dog" -> 2, possibly empty @@ -91,7 +91,7 @@ public: static bool dispatch(const std::string& cmd, const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // Execute a command registered via the above mechanism, // passing string parameters. diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp index 689033a07b..9d3b92d937 100644 --- a/indra/newview/llcompilequeue.cpp +++ b/indra/newview/llcompilequeue.cpp @@ -46,6 +46,7 @@ #include "llassetuploadqueue.h" #include "llassetuploadresponders.h" #include "llchat.h" +#include "llfloaterreg.h" #include "llviewerwindow.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -55,28 +56,24 @@ #include "llviewerobject.h" #include "llviewerregion.h" #include "llresmgr.h" + #include "llbutton.h" #include "lldir.h" #include "llfloaterchat.h" #include "llviewerstats.h" +#include "llvfile.h" #include "lluictrlfactory.h" +#include "lltrans.h" #include "llselectmgr.h" +// *TODO: This should be separated into the script queue, and the floater views of that queue. +// There should only be one floater class that can view any queue type + ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -// *TODO:Translate -const std::string COMPILE_QUEUE_TITLE("Recompilation Progress"); -const std::string COMPILE_START_STRING("recompile"); -const std::string RESET_QUEUE_TITLE("Reset Progress"); -const std::string RESET_START_STRING("reset"); -const std::string RUN_QUEUE_TITLE("Set Running Progress"); -const std::string RUN_START_STRING("set running"); -const std::string NOT_RUN_QUEUE_TITLE("Set Not Running Progress"); -const std::string NOT_RUN_START_STRING("set not running"); - struct LLScriptQueueData { LLUUID mQueueID; @@ -92,54 +89,26 @@ struct LLScriptQueueData /// Class LLFloaterScriptQueue ///---------------------------------------------------------------------------- -// static -LLMap LLFloaterScriptQueue::sInstances; - - // Default constructor -LLFloaterScriptQueue::LLFloaterScriptQueue(const std::string& name, - const LLRect& rect, - const std::string& title, - const std::string& start_string) : - LLFloater(name, rect, title, - RESIZE_YES, DEFAULT_MIN_WIDTH, DEFAULT_MIN_HEIGHT, - DRAG_ON_TOP, MINIMIZE_YES, CLOSE_YES) +LLFloaterScriptQueue::LLFloaterScriptQueue(const LLSD& key) : + LLFloater(key), + mDone(FALSE) { - mID.generate(); - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_queue.xml"); - - childSetAction("close",onCloseBtn,this); - childSetEnabled("close",FALSE); - - setTitle(title); - - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - - mStartString = start_string; - mDone = FALSE; - sInstances.addData(mID, this); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_queue.xml", FALSE); } // Destroys the object LLFloaterScriptQueue::~LLFloaterScriptQueue() { - sInstances.removeData(mID); } -// find an instance by ID. Return NULL if it does not exist. -// static -LLFloaterScriptQueue* LLFloaterScriptQueue::findInstance(const LLUUID& id) +BOOL LLFloaterScriptQueue::postBuild() { - if(sInstances.checkData(id)) - { - return sInstances.getData(id); - } - return NULL; + childSetAction("close",onCloseBtn,this); + childSetEnabled("close",FALSE); + return TRUE; } - // This is the callback method for the viewer object currently being // worked on. // NOT static, virtual! @@ -185,7 +154,7 @@ void LLFloaterScriptQueue::inventoryChanged(LLViewerObject* viewer_object, void LLFloaterScriptQueue::onCloseBtn(void* user_data) { LLFloaterScriptQueue* self = (LLFloaterScriptQueue*)user_data; - self->close(); + self->closeFloater(); } void LLFloaterScriptQueue::addObject(const LLUUID& id) @@ -210,10 +179,12 @@ BOOL LLFloaterScriptQueue::start() n_objects = selectHandle->getRootObjectCount(); } - buffer = llformat("Starting %s of %d items.", mStartString.c_str(), n_objects); // *TODO: Translate + LLStringUtil::format_map_t args; + args["[START]"] = mStartString; + args["[COUNT]"] = llformat ("%d", mObjectIDs.count()); + buffer = getString ("Starting", args); - LLScrollListCtrl* list = getChild("queue output"); - list->addCommentText(buffer); + getChild("queue output")->setCommentText(buffer); return nextObject(); } @@ -245,12 +216,8 @@ BOOL LLFloaterScriptQueue::nextObject() } while((mObjectIDs.count() > 0) && !successful_start); if(isDone() && !mDone) { - - LLScrollListCtrl* list = getChild("queue output"); - mDone = TRUE; - std::string buffer = "Done."; // *TODO: Translate - list->addCommentText(buffer); + getChild("queue output")->setCommentText(getString("Done")); childSetEnabled("close",TRUE); } return successful_start; @@ -275,7 +242,7 @@ BOOL LLFloaterScriptQueue::popNext() { llinfos << "LLFloaterScriptQueue::popNext() requesting inv for " << mCurrentObjectID << llendl; - LLUUID* id = new LLUUID(mID); + LLUUID* id = new LLUUID(getKey().asUUID()); registerVOInventoryListener(obj,id); requestVOInventory(); rv = TRUE; @@ -289,65 +256,49 @@ BOOL LLFloaterScriptQueue::popNext() /// Class LLFloaterCompileQueue ///---------------------------------------------------------------------------- -// static -LLFloaterCompileQueue* LLFloaterCompileQueue::create(BOOL mono) +class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("CompileOutputRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLFloaterCompileQueue* new_queue = new LLFloaterCompileQueue("queue", rect); +public: - class LLCompileFloaterUploadQueueSupplier : public LLAssetUploadQueueSupplier + LLCompileFloaterUploadQueueSupplier(const LLUUID& queue_id) : + mQueueId(queue_id) { - public: - - LLCompileFloaterUploadQueueSupplier(const LLUUID& queue_id) : - mQueueId(queue_id) - { - } + } - virtual LLAssetUploadQueue* get() const + virtual LLAssetUploadQueue* get() const + { + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", LLSD(mQueueId)); + if(NULL == queue) { - LLFloaterCompileQueue* queue = - (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - - if(NULL == queue) - { - return NULL; - } - - return queue->mUploadQueue; + return NULL; + } + return queue->getUploadQueue(); + } + + virtual void log(std::string message) const + { + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", LLSD(mQueueId)); + if(NULL == queue) + { + return; } - virtual void log(std::string message) const - { - LLFloaterCompileQueue* queue = - (LLFloaterCompileQueue*) LLFloaterScriptQueue::findInstance(mQueueId); - - if(NULL == queue) - { - return; - } - - LLScrollListCtrl* list = queue->getChild("queue output"); - list->addCommentText(message.c_str()); - } + queue->getChild("queue output")->setCommentText(message); + } - private: - LLUUID mQueueId; - }; - - new_queue->mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(new_queue->getID())); - new_queue->mMono = mono; - new_queue->open(); - return new_queue; +private: + LLUUID mQueueId; +}; + +LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key) + : LLFloaterScriptQueue(key) +{ + setTitle(LLTrans::getString("CompileQueueTitle")); + setStartString(LLTrans::getString("CompileQueueStart")); + + mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID())); } -LLFloaterCompileQueue::LLFloaterCompileQueue(const std::string& name, const LLRect& rect) -: LLFloaterScriptQueue(name, rect, COMPILE_QUEUE_TITLE, COMPILE_START_STRING) -{ } - LLFloaterCompileQueue::~LLFloaterCompileQueue() { } @@ -391,7 +342,7 @@ void LLFloaterCompileQueue::handleInventory(LLViewerObject *viewer_object, for(iter = asset_item_map.begin(); iter != asset_item_map.end(); iter++) { LLInventoryItem *itemp = iter->second; - LLScriptQueueData* datap = new LLScriptQueueData(getID(), + LLScriptQueueData* datap = new LLScriptQueueData(getKey().asUUID(), itemp->getName(), viewer_object->getID(), itemp->getUUID()); @@ -419,9 +370,12 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, { llinfos << "LLFloaterCompileQueue::scriptArrived()" << llendl; LLScriptQueueData* data = (LLScriptQueueData*)user_data; - if(!data) return; - LLFloaterCompileQueue* queue = static_cast - (LLFloaterScriptQueue::findInstance(data->mQueueID)); + if(!data) + { + return; + } + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", data->mQueueID); + std::string buffer; if(queue && (0 == status)) { @@ -447,13 +401,13 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, file.read(script_data, script_size); queue->mUploadQueue->queue(filename, data->mTaskId, - data->mItemId, is_running, queue->mMono, queue->getID(), - script_data, script_size, data->mScriptName); + data->mItemId, is_running, queue->mMono, queue->getKey().asUUID(), + script_data, script_size, data->mScriptName); } else { // It's now in the file, now compile it. - buffer = std::string("Downloaded, now compiling: ") + data->mScriptName; // *TODO: Translate + buffer = LLTrans::getString("CompileQueueDownloadedCompiling") + (": ") + data->mScriptName; // Write script to local file for compilation. LLFILE *fp = LLFile::fopen(filename, "wb"); /*Flawfinder: ignore*/ @@ -492,19 +446,19 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, if( LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE == status ) { - LLChat chat(std::string("Script not found on server.")); // *TODO: Translate + LLChat chat(LLTrans::getString("CompileQueueScriptNotFound")); LLFloaterChat::addChat(chat); - buffer = std::string("Problem downloading: ") + data->mScriptName; // *TODO: Translate + buffer = LLTrans::getString("CompileQueueProblemDownloading") + (": ") + data->mScriptName; } else if (LL_ERR_INSUFFICIENT_PERMISSIONS == status) { - LLChat chat(std::string("Insufficient permissions to download a script.")); // *TODO: Translate + LLChat chat(LLTrans::getString("CompileQueueInsufficientPermDownload")); LLFloaterChat::addChat(chat); - buffer = std::string("Insufficient permissions for: ") + data->mScriptName; // *TODO: Translate + buffer = LLTrans::getString("CompileQueueInsufficientPermFor") + (": ") + data->mScriptName; } else { - buffer = std::string("Unknown failure to download ") + data->mScriptName; // *TODO: Translate + buffer = LLTrans::getString("CompileQueueUnknownFailure") + (" ") + data->mScriptName; } llwarns << "Problem downloading script asset." << llendl; @@ -512,8 +466,7 @@ void LLFloaterCompileQueue::scriptArrived(LLVFS *vfs, const LLUUID& asset_id, } if(queue && (buffer.size() > 0)) { - LLScrollListCtrl* list = queue->getChild("queue output"); - list->addCommentText(buffer); + queue->getChild("queue output")->setCommentText(buffer); } delete data; } @@ -536,8 +489,7 @@ void LLFloaterCompileQueue::onSaveBytecodeComplete(const LLUUID& asset_id, void* { llinfos << "LLFloaterCompileQueue::onSaveBytecodeComplete()" << llendl; LLCompileQueueData* data = (LLCompileQueueData*)user_data; - LLFloaterCompileQueue* queue = static_cast - (LLFloaterScriptQueue::findInstance(data->mQueueID)); + LLFloaterCompileQueue* queue = LLFloaterReg::findTypedInstance("compile_queue", data->mQueueID); if(queue && (0 == status) && data) { queue->saveItemByItemID(data->mItemId); @@ -587,7 +539,7 @@ void LLFloaterCompileQueue::compile(const std::string& filename, llinfos << "compile successful." << llendl; // Save LSL bytecode - LLCompileQueueData* data = new LLCompileQueueData(mID, item_id); + LLCompileQueueData* data = new LLCompileQueueData(getKey().asUUID(), item_id); gAssetStorage->storeAssetData(dst_filename, new_asset_id, LLAssetType::AT_LSL_BYTECODE, &LLFloaterCompileQueue::onSaveBytecodeComplete, @@ -656,23 +608,13 @@ void LLFloaterCompileQueue::saveItemByItemID(const LLUUID& asset_id) /// Class LLFloaterResetQueue ///---------------------------------------------------------------------------- -// static -LLFloaterResetQueue* LLFloaterResetQueue::create() +LLFloaterResetQueue::LLFloaterResetQueue(const LLSD& key) + : LLFloaterScriptQueue(key) { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("CompileOutputRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLFloaterResetQueue* new_queue = new LLFloaterResetQueue("queue", rect); - gFloaterView->addChild(new_queue); - new_queue->open(); - return new_queue; + setTitle(LLTrans::getString("ResetQueueTitle")); + setStartString(LLTrans::getString("ResetQueueStart")); } -LLFloaterResetQueue::LLFloaterResetQueue(const std::string& name, const LLRect& rect) -: LLFloaterScriptQueue(name, rect, RESET_QUEUE_TITLE, RESET_START_STRING) -{ } - LLFloaterResetQueue::~LLFloaterResetQueue() { } @@ -695,10 +637,9 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, if (object) { LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); - LLScrollListCtrl* list = getChild("queue output"); std::string buffer; - buffer = std::string("Resetting: ") + item->getName(); // *TODO: Translate - list->addCommentText(buffer); + buffer = getString("Resetting") + (": ") + item->getName(); + getChild("queue output")->setCommentText(buffer); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_ScriptReset); msg->nextBlockFast(_PREHASH_AgentData); @@ -719,22 +660,13 @@ void LLFloaterResetQueue::handleInventory(LLViewerObject* viewer_obj, /// Class LLFloaterRunQueue ///---------------------------------------------------------------------------- -// static -LLFloaterRunQueue* LLFloaterRunQueue::create() +LLFloaterRunQueue::LLFloaterRunQueue(const LLSD& key) + : LLFloaterScriptQueue(key) { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("CompileOutputRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLFloaterRunQueue* new_queue = new LLFloaterRunQueue("queue", rect); - new_queue->open(); /*Flawfinder: ignore*/ - return new_queue; + setTitle(LLTrans::getString("RunQueueTitle")); + setStartString(LLTrans::getString("RunQueueStart")); } -LLFloaterRunQueue::LLFloaterRunQueue(const std::string& name, const LLRect& rect) -: LLFloaterScriptQueue(name, rect, RUN_QUEUE_TITLE, RUN_START_STRING) -{ } - LLFloaterRunQueue::~LLFloaterRunQueue() { } @@ -759,8 +691,8 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); LLScrollListCtrl* list = getChild("queue output"); std::string buffer; - buffer = std::string("Running: ") + item->getName(); // *TODO: Translate - list->addCommentText(buffer); + buffer = getString("Running") + (": ") + item->getName(); + list->setCommentText(buffer); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); @@ -783,22 +715,13 @@ void LLFloaterRunQueue::handleInventory(LLViewerObject* viewer_obj, /// Class LLFloaterNotRunQueue ///---------------------------------------------------------------------------- -// static -LLFloaterNotRunQueue* LLFloaterNotRunQueue::create() +LLFloaterNotRunQueue::LLFloaterNotRunQueue(const LLSD& key) + : LLFloaterScriptQueue(key) { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("CompileOutputRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLFloaterNotRunQueue* new_queue = new LLFloaterNotRunQueue("queue", rect); - new_queue->open(); /*Flawfinder: ignore*/ - return new_queue; + setTitle(LLTrans::getString("NotRunQueueTitle")); + setStartString(LLTrans::getString("NotRunQueueStart")); } -LLFloaterNotRunQueue::LLFloaterNotRunQueue(const std::string& name, const LLRect& rect) -: LLFloaterScriptQueue(name, rect, NOT_RUN_QUEUE_TITLE, NOT_RUN_START_STRING) -{ } - LLFloaterNotRunQueue::~LLFloaterNotRunQueue() { } @@ -823,8 +746,8 @@ void LLFloaterNotRunQueue::handleInventory(LLViewerObject* viewer_obj, LLInventoryItem* item = (LLInventoryItem*)((LLInventoryObject*)(*it)); LLScrollListCtrl* list = getChild("queue output"); std::string buffer; - buffer = std::string("Not running: ") +item->getName(); // *TODO: Translate - list->addCommentText(buffer); + buffer = getString("NotRunning") + (": ") +item->getName(); + list->setCommentText(buffer); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_SetScriptRunning); diff --git a/indra/newview/llcompilequeue.h b/indra/newview/llcompilequeue.h index 51240423ba..063d573239 100644 --- a/indra/newview/llcompilequeue.h +++ b/indra/newview/llcompilequeue.h @@ -59,20 +59,20 @@ class LLFloaterScriptQueue : public LLFloater, public LLVOInventoryListener { public: + LLFloaterScriptQueue(const LLSD& key); + virtual ~LLFloaterScriptQueue(); + + /*virtual*/ BOOL postBuild(); + + void setMono(bool mono) { mMono = mono; } + // addObject() accepts an object id. void addObject(const LLUUID& id); // start() returns TRUE if the queue has started, otherwise FALSE. BOOL start(); - - // find an instance by ID. Return NULL if it does not exist. - static LLFloaterScriptQueue* findInstance(const LLUUID& id); - + protected: - LLFloaterScriptQueue(const std::string& name, const LLRect& rect, - const std::string& title, const std::string& start_string); - virtual ~LLFloaterScriptQueue(); - // This is the callback method for the viewer object currently // being worked on. /*virtual*/ void inventoryChanged(LLViewerObject* obj, @@ -94,8 +94,7 @@ protected: BOOL nextObject(); BOOL popNext(); - // Get this instances ID. - const LLUUID& getID() const { return mID; } + void setStartString(const std::string& s) { mStartString = s; } protected: // UI @@ -107,10 +106,8 @@ protected: LLUUID mCurrentObjectID; BOOL mDone; - LLUUID mID; - static LLMap sInstances; - std::string mStartString; + BOOL mMono; }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -131,20 +128,19 @@ class LLAssetUploadQueue; class LLFloaterCompileQueue : public LLFloaterScriptQueue { + friend class LLFloaterReg; public: - // Use this method to create a compile queue. Once created, it - // will be responsible for it's own destruction. - static LLFloaterCompileQueue* create(BOOL mono); - static void onSaveBytecodeComplete(const LLUUID& asset_id, void* user_data, S32 status); // remove any object in mScriptScripts with the matching uuid. void removeItemByItemID(const LLUUID& item_id); + + LLAssetUploadQueue* getUploadQueue() { return mUploadQueue; } protected: - LLFloaterCompileQueue(const std::string& name, const LLRect& rect); + LLFloaterCompileQueue(const LLSD& key); virtual ~LLFloaterCompileQueue(); // This is called by inventoryChanged @@ -173,12 +169,11 @@ protected: // find InventoryItem given item id. const LLInventoryItem* findItemByItemID(const LLUUID& item_id) const; - + protected: LLViewerInventoryItem::item_array_t mCurrentScripts; private: - BOOL mMono; // Compile to mono. LLAssetUploadQueue* mUploadQueue; }; @@ -190,20 +185,14 @@ private: class LLFloaterResetQueue : public LLFloaterScriptQueue { -public: - // Use this method to create a reset queue. Once created, it - // will be responsible for it's own destruction. - static LLFloaterResetQueue* create(); - + friend class LLFloaterReg; protected: - LLFloaterResetQueue(const std::string& name, const LLRect& rect); + LLFloaterResetQueue(const LLSD& key); virtual ~LLFloaterResetQueue(); // This is called by inventoryChanged virtual void handleInventory(LLViewerObject* viewer_obj, InventoryObjectList* inv); - -protected: }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -214,20 +203,14 @@ protected: class LLFloaterRunQueue : public LLFloaterScriptQueue { -public: - // Use this method to create a run queue. Once created, it - // will be responsible for it's own destruction. - static LLFloaterRunQueue* create(); - + friend class LLFloaterReg; protected: - LLFloaterRunQueue(const std::string& name, const LLRect& rect); + LLFloaterRunQueue(const LLSD& key); virtual ~LLFloaterRunQueue(); // This is called by inventoryChanged virtual void handleInventory(LLViewerObject* viewer_obj, InventoryObjectList* inv); - -protected: }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -238,20 +221,14 @@ protected: class LLFloaterNotRunQueue : public LLFloaterScriptQueue { -public: - // Use this method to create a not run queue. Once created, it - // will be responsible for it's own destruction. - static LLFloaterNotRunQueue* create(); - + friend class LLFloaterReg; protected: - LLFloaterNotRunQueue(const std::string& name, const LLRect& rect); + LLFloaterNotRunQueue(const LLSD& key); virtual ~LLFloaterNotRunQueue(); // This is called by inventoryChanged virtual void handleInventory(LLViewerObject* viewer_obj, InventoryObjectList* inv); - -protected: }; #endif // LL_LLCOMPILEQUEUE_H diff --git a/indra/newview/llcurrencyuimanager.cpp b/indra/newview/llcurrencyuimanager.cpp index 86821249a0..9957694727 100644 --- a/indra/newview/llcurrencyuimanager.cpp +++ b/indra/newview/llcurrencyuimanager.cpp @@ -46,6 +46,7 @@ #include "llviewchildren.h" #include "llxmlrpctransaction.h" #include "llviewernetwork.h" +#include "llpanel.h" const F64 CURRENCY_ESTIMATE_FREQUENCY = 2.0; @@ -356,8 +357,7 @@ void LLCurrencyUIManager::Impl::prepare() if (lindenAmount) { lindenAmount->setPrevalidate(LLLineEditor::prevalidateNonNegativeS32); - lindenAmount->setKeystrokeCallback(onCurrencyKey); - lindenAmount->setCallbackUserData(this); + lindenAmount->setKeystrokeCallback(onCurrencyKey, this); } } diff --git a/indra/newview/lldebugmessagebox.cpp b/indra/newview/lldebugmessagebox.cpp index 4188ecc0e2..786473eb9b 100644 --- a/indra/newview/lldebugmessagebox.cpp +++ b/indra/newview/lldebugmessagebox.cpp @@ -50,32 +50,69 @@ std::map LLDebugVarMessageBox::sInstances; LLDebugVarMessageBox::LLDebugVarMessageBox(const std::string& title, EDebugVarType var_type, void *var) : - LLFloater(std::string("msg box"), LLRect(10,160,400,10), title), + LLFloater(LLSD()), mVarType(var_type), mVarData(var), mAnimate(FALSE) { + setRect(LLRect(10,160,400,10)); + + LLSliderCtrl::Params slider_p; + slider_p.label(title); + slider_p.label_width(70); + slider_p.text_width(40); + slider_p.can_edit_text(true); + slider_p.show_text(true); + + mSlider1 = NULL; + mSlider2 = NULL; + mSlider3 = NULL; + switch(var_type) { case VAR_TYPE_F32: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), title, NULL, 70, 130, TRUE, TRUE, FALSE, NULL, NULL, *((F32*)var), -100.f, 100.f, 0.1f, LLStringUtil::null); - mSlider1->setPrecision(3); + slider_p.name("slider 1"); + slider_p.rect(LLRect(20,130,190,110)); + slider_p.initial_value(*((F32*)var)); + slider_p.min_value(-100.f); + slider_p.max_value(100.f); + slider_p.increment(0.1f); + slider_p.decimal_digits(3); + mSlider1 = LLUICtrlFactory::create(slider_p); addChild(mSlider1); - mSlider2 = NULL; - mSlider3 = NULL; break; case VAR_TYPE_S32: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,100,190,80), title, NULL, 70, 130, TRUE, TRUE, FALSE, NULL, NULL, (F32)*((S32*)var), -255.f, 255.f, 1.f, LLStringUtil::null); - mSlider1->setPrecision(0); + slider_p.name("slider 1"); + slider_p.rect(LLRect(20,100,190,80)); + slider_p.initial_value((F32)*((S32*)var)); + slider_p.min_value(-255.f); + slider_p.max_value(255.f); + slider_p.increment(1.f); + slider_p.decimal_digits(0); + mSlider1 = LLUICtrlFactory::create(slider_p); addChild(mSlider1); - mSlider2 = NULL; - mSlider3 = NULL; break; case VAR_TYPE_VEC3: - mSlider1 = new LLSliderCtrl(std::string("slider 1"), LLRect(20,130,190,110), std::string("x: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, NULL, ((LLVector3*)var)->mV[VX], -100.f, 100.f, 0.1f, LLStringUtil::null); - mSlider1->setPrecision(3); - mSlider2 = new LLSliderCtrl(std::string("slider 2"), LLRect(20,100,190,80), std::string("y: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, NULL, ((LLVector3*)var)->mV[VY], -100.f, 100.f, 0.1f, LLStringUtil::null); - mSlider2->setPrecision(3); - mSlider3 = new LLSliderCtrl(std::string("slider 3"), LLRect(20,70,190,50), std::string("z: "), NULL, 70, 130, TRUE, TRUE, FALSE, NULL, NULL, ((LLVector3*)var)->mV[VZ], -100.f, 100.f, 0.1f, LLStringUtil::null); - mSlider3->setPrecision(3); + slider_p.name("slider 1"); + slider_p.label("x: "); + slider_p.rect(LLRect(20,130,190,110)); + slider_p.initial_value(((LLVector3*)var)->mV[VX]); + slider_p.min_value(-100.f); + slider_p.max_value(100.f); + slider_p.increment(0.1f); + slider_p.decimal_digits(3); + mSlider1 = LLUICtrlFactory::create(slider_p); + + slider_p.name("slider 2"); + slider_p.label("y: "); + slider_p.rect(LLRect(20,100,190,80)); + slider_p.initial_value(((LLVector3*)var)->mV[VY]); + mSlider2 = LLUICtrlFactory::create(slider_p); + + slider_p.name("slider 3"); + slider_p.label("z: "); + slider_p.rect(LLRect(20,70,190,50)); + slider_p.initial_value(((LLVector3*)var)->mV[VZ]); + mSlider2 = LLUICtrlFactory::create(slider_p); + addChild(mSlider1); addChild(mSlider2); addChild(mSlider3); @@ -85,10 +122,18 @@ LLDebugVarMessageBox::LLDebugVarMessageBox(const std::string& title, EDebugVarTy break; } - mAnimateButton = new LLButton(std::string("Animate"), LLRect(20, 45, 180, 25), LLStringUtil::null, onAnimateClicked, this); + LLButton::Params p; + p.name(std::string("Animate")); + p.rect(LLRect(20, 45, 180, 25)); + p.click_callback.function(boost::bind(&LLDebugVarMessageBox::onAnimateClicked, this, _2)); + mAnimateButton = LLUICtrlFactory::create(p); addChild(mAnimateButton); - mText = new LLTextBox(std::string("value"), LLRect(20,20,190,0)); + LLTextBox::Params params; + params.name("value"); + params.text(params.name); + params.rect(LLRect(20,20,190,0)); + mText = LLUICtrlFactory::create (params); addChild(mText); //disable hitting enter closes dialog @@ -112,8 +157,7 @@ void LLDebugVarMessageBox::show(const std::string& title, F32 *var, F32 max_valu { box->mSlider1->setValue(*var); } - box->mSlider1->setCommitCallback(slider_changed); - box->mSlider1->setCallbackUserData(box); + box->mSlider1->setCommitCallback(boost::bind(&LLDebugVarMessageBox::sliderChanged, box, _2)); #endif } @@ -129,8 +173,7 @@ void LLDebugVarMessageBox::show(const std::string& title, S32 *var, S32 max_valu { box->mSlider1->setValue((F32)*var); } - box->mSlider1->setCommitCallback(slider_changed); - box->mSlider1->setCallbackUserData(box); + box->mSlider1->setCommitCallback(boost::bind(&LLDebugVarMessageBox::sliderChanged, box, _2)); #endif } @@ -142,20 +185,17 @@ void LLDebugVarMessageBox::show(const std::string& title, LLVector3 *var, LLVect box->mSlider1->setMaxValue(max_value.mV[VX]); box->mSlider1->setMinValue(-max_value.mV[VX]); box->mSlider1->setIncrement(increment.mV[VX]); - box->mSlider1->setCommitCallback(slider_changed); - box->mSlider1->setCallbackUserData(box); + box->mSlider1->setCommitCallback(boost::bind(&LLDebugVarMessageBox::sliderChanged, box, _2)); box->mSlider2->setMaxValue(max_value.mV[VX]); box->mSlider2->setMinValue(-max_value.mV[VX]); box->mSlider2->setIncrement(increment.mV[VX]); - box->mSlider2->setCommitCallback(slider_changed); - box->mSlider2->setCallbackUserData(box); + box->mSlider2->setCommitCallback(boost::bind(&LLDebugVarMessageBox::sliderChanged, box, _2)); box->mSlider3->setMaxValue(max_value.mV[VX]); box->mSlider3->setMinValue(-max_value.mV[VX]); box->mSlider3->setIncrement(increment.mV[VX]); - box->mSlider3->setCommitCallback(slider_changed); - box->mSlider3->setCallbackUserData(box); + box->mSlider3->setCommitCallback(boost::bind(&LLDebugVarMessageBox::sliderChanged, box, _2)); #endif } @@ -170,50 +210,44 @@ LLDebugVarMessageBox* LLDebugVarMessageBox::show(const std::string& title, EDebu sInstances[title_string] = box; gFloaterView->addChild(box); box->reshape(200,150); - box->open(); /*Flawfinder: ignore*/ + box->openFloater(); box->mTitle = title_string; } return box; } -void LLDebugVarMessageBox::slider_changed(LLUICtrl* ctrl, void* user_data) +void LLDebugVarMessageBox::sliderChanged(const LLSD& data) { - LLDebugVarMessageBox *msg_box = (LLDebugVarMessageBox*)user_data; - if (!msg_box || !msg_box->mVarData) return; + if (!mVarData) + return; - switch(msg_box->mVarType) + switch(mVarType) { case VAR_TYPE_F32: - *((F32*)msg_box->mVarData) = (F32)msg_box->mSlider1->getValue().asReal(); + *((F32*)mVarData) = (F32)mSlider1->getValue().asReal(); break; case VAR_TYPE_S32: - *((S32*)msg_box->mVarData) = (S32)msg_box->mSlider1->getValue().asInteger(); + *((S32*)mVarData) = (S32)mSlider1->getValue().asInteger(); break; case VAR_TYPE_VEC3: { - LLVector3* vec_p = (LLVector3*)msg_box->mVarData; - vec_p->setVec((F32)msg_box->mSlider1->getValue().asReal(), - (F32)msg_box->mSlider2->getValue().asReal(), - (F32)msg_box->mSlider3->getValue().asReal()); + LLVector3* vec_p = (LLVector3*)mVarData; + vec_p->setVec((F32)mSlider1->getValue().asReal(), + (F32)mSlider2->getValue().asReal(), + (F32)mSlider3->getValue().asReal()); break; } default: - llwarns << "Unhandled var type " << msg_box->mVarType << llendl; + llwarns << "Unhandled var type " << mVarType << llendl; break; } } -void LLDebugVarMessageBox::onAnimateClicked(void* user_data) +void LLDebugVarMessageBox::onAnimateClicked(const LLSD& data) { - LLDebugVarMessageBox* msg_boxp = (LLDebugVarMessageBox*)user_data; - msg_boxp->mAnimate = !msg_boxp->mAnimate; - msg_boxp->mAnimateButton->setToggleState(msg_boxp->mAnimate); -} - -void LLDebugVarMessageBox::onClose(bool app_quitting) -{ - setVisible(FALSE); + mAnimate = !mAnimate; + mAnimateButton->setToggleState(mAnimate); } void LLDebugVarMessageBox::draw() @@ -245,16 +279,16 @@ void LLDebugVarMessageBox::draw() { F32 animated_val = clamp_rescale(fmodf((F32)LLFrameTimer::getElapsedSeconds() / 5.f, 1.f), 0.f, 1.f, 0.f, mSlider1->getMaxValue()); mSlider1->setValue(animated_val); - slider_changed(mSlider1, this); + sliderChanged(LLSD()); if (mSlider2) { mSlider2->setValue(animated_val); - slider_changed(mSlider2, this); + sliderChanged(LLSD()); } if (mSlider3) { mSlider3->setValue(animated_val); - slider_changed(mSlider3, this); + sliderChanged(LLSD()); } } } diff --git a/indra/newview/lldebugmessagebox.h b/indra/newview/lldebugmessagebox.h index 07062218ac..0def0ee7af 100644 --- a/indra/newview/lldebugmessagebox.h +++ b/indra/newview/lldebugmessagebox.h @@ -66,8 +66,8 @@ protected: ~LLDebugVarMessageBox(); static LLDebugVarMessageBox* show(const std::string& title, EDebugVarType var_type, void *var); - static void slider_changed(LLUICtrl* ctrl, void* user_data); - static void onAnimateClicked(void* user_data); + void sliderChanged(const LLSD& data); + void onAnimateClicked(const LLSD& data); public: static void show(const std::string& title, F32 *var, F32 max_value = 100.f, F32 increment = 0.1f); @@ -76,7 +76,6 @@ public: static void show(const std::string& title, LLVector3 *var, LLVector3 max_value = LLVector3(100.f, 100.f, 100.f), LLVector3 increment = LLVector3(0.1f, 0.1f, 0.1f)); //static void show(const std::string& title, LLVector4 *var, LLVector4 max_value = LLVector4(100.f, 100.f, 100.f, 100.f), LLVector4 increment = LLVector4(0.1f, 0.1f, 0.1f, 0.1f)); - virtual void onClose(bool app_quitting); virtual void draw(); protected: diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp index 40f5202067..bd5b9c30a2 100644 --- a/indra/newview/lldebugview.cpp +++ b/indra/newview/lldebugview.cpp @@ -35,16 +35,16 @@ #include "lldebugview.h" // library includes -#include "llframestatview.h" #include "llfasttimerview.h" #include "llmemoryview.h" #include "llconsole.h" #include "lltextureview.h" #include "llresmgr.h" #include "imageids.h" -#include "llvelocitybar.h" +#include "llviewercontrol.h" #include "llviewerwindow.h" -#include "llfloaterstats.h" +#include "llappviewer.h" +#include "llmemoryview.h" // // Globals @@ -56,57 +56,52 @@ LLDebugView* gDebugView = NULL; // Methods // -LLDebugView::LLDebugView(const std::string& name, const LLRect &rect) -: LLView(name, rect, FALSE) +LLDebugView::LLDebugView(const LLDebugView::Params& p) +: LLView(p) { LLRect r; + LLRect rect(p.rect); r.set(10, rect.getHeight() - 100, rect.getWidth()/2, 100); - mDebugConsolep = new LLConsole("debug console", 20, r, -1, 0.f ); - mDebugConsolep->setFollowsBottom(); - mDebugConsolep->setFollowsLeft(); - mDebugConsolep->setVisible( FALSE ); + LLConsole::Params cp; + cp.name("debug console"); + cp.max_lines(20); + cp.rect(r); + cp.font(LLFontGL::getFontMonospace()); + cp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_LEFT); + cp.visible(false); + mDebugConsolep = LLUICtrlFactory::create(cp); addChild(mDebugConsolep); r.set(150 - 25, rect.getHeight() - 50, rect.getWidth()/2 - 25, rect.getHeight() - 450); - mFrameStatView = new LLFrameStatView("frame stat", r); - mFrameStatView->setFollowsTop(); - mFrameStatView->setFollowsLeft(); - mFrameStatView->setVisible(FALSE); // start invisible - addChild(mFrameStatView); r.set(25, rect.getHeight() - 50, (S32) (gViewerWindow->getVirtualWindowRect().getWidth() * 0.75f), (S32) (gViewerWindow->getVirtualWindowRect().getHeight() * 0.75f)); - mFastTimerView = new LLFastTimerView("fast timers", r); + mFastTimerView = new LLFastTimerView(r); mFastTimerView->setFollowsTop(); mFastTimerView->setFollowsLeft(); mFastTimerView->setVisible(FALSE); // start invisible addChild(mFastTimerView); - r.set(25, rect.getHeight() - 50, rect.getWidth()/2, rect.getHeight() - 450); - mMemoryView = new LLMemoryView("memory", r); - mMemoryView->setFollowsTop(); - mMemoryView->setFollowsLeft(); - mMemoryView->setVisible(FALSE); // start invisible + r.set(25, rect.getHeight() - 50, (S32) (gViewerWindow->getVirtualWindowRect().getWidth() * 0.75f), + (S32) (gViewerWindow->getVirtualWindowRect().getHeight() * 0.75f)); + LLMemoryView::Params mp; + mp.name("memory"); + mp.rect(r); + mp.follows.flags(FOLLOWS_TOP | FOLLOWS_LEFT); + mp.visible(false); + mMemoryView = LLUICtrlFactory::create(mp); addChild(mMemoryView); r.set(150, rect.getHeight() - 50, 820, 100); - gTextureView = new LLTextureView("gTextureView", r); - gTextureView->setRect(r); - gTextureView->setFollowsBottom(); - gTextureView->setFollowsLeft(); + LLTextureView::Params tvp; + tvp.name("gTextureView"); + tvp.rect(r); + tvp.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT); + tvp.visible(false); + gTextureView = LLUICtrlFactory::create(tvp); addChild(gTextureView); //gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE); - - const S32 VELOCITY_LEFT = 10; // 370; - const S32 VELOCITY_WIDTH = 500; - const S32 VELOCITY_TOP = 140; - const S32 VELOCITY_HEIGHT = 45; - r.setLeftTopAndSize( VELOCITY_LEFT, VELOCITY_TOP, VELOCITY_WIDTH, VELOCITY_HEIGHT ); - gVelocityBar = new LLVelocityBar("Velocity Bar", r); - gVelocityBar->setFollowsBottom(); - gVelocityBar->setFollowsLeft(); - addChild(gVelocityBar); } diff --git a/indra/newview/lldebugview.h b/indra/newview/lldebugview.h index 189efd3a3f..9cf2a59a0a 100644 --- a/indra/newview/lldebugview.h +++ b/indra/newview/lldebugview.h @@ -40,9 +40,7 @@ // declarations class LLButton; -class LLToolView; class LLStatusPanel; -class LLFrameStatView; class LLFastTimerView; class LLMemoryView; class LLConsole; @@ -52,10 +50,18 @@ class LLFloaterStats; class LLDebugView : public LLView { public: - LLDebugView(const std::string& name, const LLRect &rect); + struct Params : public LLInitParam::Block + { + Params() + { + mouse_opaque = false; + } + }; + LLDebugView(const Params&); ~LLDebugView(); - LLFrameStatView* mFrameStatView; + void setStatsVisible(BOOL visible); + LLFastTimerView* mFastTimerView; LLMemoryView* mMemoryView; LLConsole* mDebugConsolep; diff --git a/indra/newview/lldirpicker.cpp b/indra/newview/lldirpicker.cpp index 8b0ed39eb0..a720dc46b5 100644 --- a/indra/newview/lldirpicker.cpp +++ b/indra/newview/lldirpicker.cpp @@ -40,6 +40,7 @@ #include "lldir.h" #include "llframetimer.h" #include "lltrans.h" +#include "llwindow.h" // beforeDialog() #if LL_LINUX || LL_SOLARIS # include "llfilepicker.h" diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index cb368974ae..7cc78aff92 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -60,6 +60,9 @@ const F32 MAX_INTERPOLATE_DISTANCE_SQUARED = 10.f * 10.f; const F32 OBJECT_DAMPING_TIME_CONSTANT = 0.06f; const F32 MIN_SHADOW_CASTER_RADIUS = 2.0f; +static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); + + //////////////////////// // // Inline implementations. @@ -188,7 +191,7 @@ BOOL LLDrawable::isLight() const void LLDrawable::cleanupReferences() { - LLFastTimer t(LLFastTimer::FTM_PIPELINE); + LLFastTimer t(FTM_PIPELINE); std::for_each(mFaces.begin(), mFaces.end(), DeletePointer()); mFaces.clear(); @@ -229,7 +232,7 @@ S32 LLDrawable::findReferences(LLDrawable *drawablep) return count; } -LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerImage *texturep) +LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerTexture *texturep) { LLMemType mt(LLMemType::MTYPE_DRAWABLE); @@ -253,7 +256,7 @@ LLFace* LLDrawable::addFace(LLFacePool *poolp, LLViewerImage *texturep) return face; } -LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerImage *texturep) +LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep) { LLMemType mt(LLMemType::MTYPE_DRAWABLE); @@ -275,7 +278,7 @@ LLFace* LLDrawable::addFace(const LLTextureEntry *te, LLViewerImage *texturep) } -void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep) +void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) { if (newFaces == (S32)mFaces.size()) { @@ -298,7 +301,7 @@ void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerImag llassert_always(mFaces.size() == newFaces); } -void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerImage *texturep) +void LLDrawable::setNumFacesFast(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep) { if (newFaces <= (S32)mFaces.size() && newFaces >= (S32)mFaces.size()/2) { @@ -1033,7 +1036,7 @@ void LLSpatialBridge::updateSpatialExtents() LLSpatialGroup* root = (LLSpatialGroup*) mOctree->getListener(0); { - LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); + LLFastTimer ftm(FTM_CULL_REBOUND); root->rebound(); } diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h index 6e0b6e81d6..c765980c30 100644 --- a/indra/newview/lldrawable.h +++ b/indra/newview/lldrawable.h @@ -46,7 +46,6 @@ #include "llmemtype.h" #include "llprimitive.h" #include "lldarray.h" -#include "llstat.h" #include "llviewerobject.h" #include "llrect.h" #include "llappviewer.h" // for gFrameTimeSeconds @@ -59,12 +58,11 @@ class LLSpatialGroup; class LLSpatialBridge; class LLSpatialPartition; class LLVOVolume; -class LLViewerImage; +class LLViewerTexture; // Can have multiple silhouettes for each object const U32 SILHOUETTE_HIGHLIGHT = 0; - // All data for new renderer goes into this class. class LLDrawable : public LLRefCount { @@ -126,11 +124,11 @@ public: inline S32 getNumFaces() const; //void removeFace(const S32 i); // SJB: Avoid using this, it's slow - LLFace* addFace(LLFacePool *poolp, LLViewerImage *texturep); - LLFace* addFace(const LLTextureEntry *te, LLViewerImage *texturep); + LLFace* addFace(LLFacePool *poolp, LLViewerTexture *texturep); + LLFace* addFace(const LLTextureEntry *te, LLViewerTexture *texturep); void deleteFaces(S32 offset, S32 count); - void setNumFaces(const S32 numFaces, LLFacePool *poolp, LLViewerImage *texturep); - void setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerImage *texturep); + void setNumFaces(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep); + void setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep); void mergeFaces(LLDrawable* src); void init(); diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 9f05ce3c46..3a064a4e7d 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -60,7 +60,7 @@ S32 LLDrawPool::sNumDrawPools = 0; //============================= // Draw Pool Implementation //============================= -LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerImage *tex0) +LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) { LLDrawPool *poolp = NULL; switch (type) @@ -129,7 +129,7 @@ LLDrawPool::~LLDrawPool() } -LLViewerImage *LLDrawPool::getDebugTexture() +LLViewerTexture *LLDrawPool::getDebugTexture() { return NULL; } @@ -244,7 +244,7 @@ void LLFacePool::destroy() } } -void LLFacePool::dirtyTextures(const std::set& textures) +void LLFacePool::dirtyTextures(const std::set& textures) { } @@ -279,7 +279,7 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage) iter != face_list.end(); iter++) { LLFace *facep = *iter; - gGL.getTexUnit(stage)->bind(facep->getTexture()); + gGL.getTexUnit(stage)->bind(facep->getTexture()) ; gGL.getTexUnit(0)->activate(); res += facep->renderIndexed(); } @@ -295,13 +295,6 @@ void LLFacePool::drawLoop() } } -void LLFacePool::renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) -{ -} - void LLFacePool::enqueue(LLFace* facep) { mDrawFace.push_back(facep); @@ -330,7 +323,7 @@ void LLFacePool::resetDrawOrders() mDrawFace.resize(0); } -LLViewerImage *LLFacePool::getTexture() +LLViewerTexture *LLFacePool::getTexture() { return NULL; } @@ -481,7 +474,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) { if (params.mTexture.notNull()) { - gGL.getTexUnit(0)->bind(params.mTexture.get()); + gGL.getTexUnit(0)->bind(params.mTexture) ; if (params.mTextureMatrix) { glMatrixMode(GL_TEXTURE); diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 87c3ccaffe..966de41df3 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -39,8 +39,8 @@ #include "llvertexbuffer.h" class LLFace; -class LLImageGL; -class LLViewerImage; +class LLViewerTexture; +class LLViewerFetchedTexture; class LLSpatialGroup; class LLDrawInfo; @@ -77,7 +77,7 @@ public: S32 getId() const { return mId; } U32 getType() const { return mType; } - virtual LLViewerImage *getDebugTexture(); + virtual LLViewerTexture *getDebugTexture(); virtual void beginRenderPass( S32 pass ); virtual void endRenderPass( S32 pass ); virtual S32 getNumPasses(); @@ -103,9 +103,9 @@ public: virtual BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct! virtual S32 getVertexShaderLevel() const { return mVertexShaderLevel; } - static LLDrawPool* createPool(const U32 type, LLViewerImage *tex0 = NULL); + static LLDrawPool* createPool(const U32 type, LLViewerTexture *tex0 = NULL); virtual LLDrawPool *instancePool() = 0; // Create an empty new instance of the pool. - virtual LLViewerImage* getTexture() = 0; + virtual LLViewerTexture* getTexture() = 0; virtual BOOL isFacePool() { return FALSE; } virtual void resetDrawOrders() = 0; @@ -139,8 +139,8 @@ public: LLRenderPass(const U32 type); virtual ~LLRenderPass(); /*virtual*/ LLDrawPool* instancePool(); - /*virtual*/ LLViewerImage* getDebugTexture() { return NULL; } - LLViewerImage* getTexture() { return NULL; } + /*virtual*/ LLViewerTexture* getDebugTexture() { return NULL; } + LLViewerTexture* getTexture() { return NULL; } BOOL isDead() { return FALSE; } void resetDrawOrders() { } @@ -169,11 +169,9 @@ public: virtual void renderForSelect() = 0; BOOL isDead() { return mReferences.empty(); } - virtual void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); - - virtual LLViewerImage *getTexture(); - virtual void dirtyTextures(const std::set& textures); + + virtual LLViewerTexture *getTexture(); + virtual void dirtyTextures(const std::set& textures); virtual void enqueue(LLFace *face); virtual BOOL addFace(LLFace *face); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 7e470bd01f..88f79fc1b9 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -42,11 +42,10 @@ #include "llcubemap.h" #include "llsky.h" -#include "llagent.h" #include "lldrawable.h" #include "llface.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" // For debugging +#include "llviewertexturelist.h" // For debugging #include "llviewerobjectlist.h" // For debugging #include "llviewerwindow.h" #include "pipeline.h" @@ -90,7 +89,7 @@ void LLDrawPoolAlpha::endDeferredPass(S32 pass) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.4f); { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); gDeferredTreeProgram.bind(); LLGLEnable test(GL_ALPHA_TEST); //render alpha masked objects @@ -112,7 +111,7 @@ S32 LLDrawPoolAlpha::getNumPostDeferredPasses() void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); simple_shader = &gDeferredAlphaProgram; fullbright_shader = &gDeferredFullbrightProgram; @@ -139,7 +138,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) void LLDrawPoolAlpha::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); if (LLPipeline::sUnderWaterRender) { @@ -163,7 +162,7 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass) void LLDrawPoolAlpha::endRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); LLRenderPass::endRenderPass(pass); if(gPipeline.canUseWindLightShaders()) @@ -174,7 +173,7 @@ void LLDrawPoolAlpha::endRenderPass( S32 pass ) void LLDrawPoolAlpha::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_ALPHA); + LLFastTimer t(FTM_RENDER_ALPHA); LLGLSPipelineAlpha gls_pipeline_alpha; @@ -218,8 +217,8 @@ void LLDrawPoolAlpha::render(S32 pass) } gPipeline.enableLightsFullbright(LLColor4(1,1,1,1)); glColor4f(1,0,0,1); - LLViewerImage::sSmokeImagep->addTextureStats(1024.f*1024.f); - gGL.getTexUnit(0)->bind(LLViewerImage::sSmokeImagep.get()); + LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep) ; renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); } @@ -294,7 +293,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask) if (params.mTexture.notNull()) { gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->bind(params.mTexture.get()); + gGL.getTexUnit(0)->bind(params.mTexture) ; params.mTexture->addTextureStats(params.mVSize); if (params.mTextureMatrix) { diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 80c7d73e6a..565f906a3b 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -38,7 +38,6 @@ #include "llvoavatar.h" #include "m3math.h" -#include "llagent.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" @@ -89,17 +88,16 @@ S32 AVATAR_OFFSET_TEX0 = 32; S32 AVATAR_OFFSET_TEX1 = 40; S32 AVATAR_VERTEX_BYTES = 48; - BOOL gAvatarEmbossBumpMap = FALSE; static BOOL sRenderingSkinned = FALSE; S32 normal_channel = -1; S32 specular_channel = -1; -LLDrawPoolAvatar::LLDrawPoolAvatar() : -LLFacePool(POOL_AVATAR) +static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow"); + +LLDrawPoolAvatar::LLDrawPoolAvatar() : + LLFacePool(POOL_AVATAR) { - //LLDebugVarMessageBox::show("acceleration", &CLOTHING_ACCEL_FORCE_FACTOR, 10.f, 0.1f); - //LLDebugVarMessageBox::show("gravity", &CLOTHING_GRAVITY_EFFECT, 10.f, 0.1f); } //----------------------------------------------------------------------------- @@ -110,7 +108,6 @@ LLDrawPool *LLDrawPoolAvatar::instancePool() return new LLDrawPoolAvatar(); } -BOOL gRenderAvatar = TRUE; S32 LLDrawPoolAvatar::getVertexShaderLevel() const { @@ -157,7 +154,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses() void LLDrawPoolAvatar::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { @@ -181,7 +178,7 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass) void LLDrawPoolAvatar::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { @@ -251,7 +248,7 @@ S32 LLDrawPoolAvatar::getNumShadowPasses() void LLDrawPoolAvatar::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); + LLFastTimer t(FTM_SHADOW_AVATAR); sVertexProgram = &gDeferredAvatarShadowProgram; if (sShaderLevel > 0) @@ -273,7 +270,7 @@ void LLDrawPoolAvatar::beginShadowPass(S32 pass) void LLDrawPoolAvatar::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); + LLFastTimer t(FTM_SHADOW_AVATAR); if (sShaderLevel > 0) { @@ -287,11 +284,7 @@ void LLDrawPoolAvatar::endShadowPass(S32 pass) void LLDrawPoolAvatar::renderShadow(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_AVATAR); - if (!gRenderAvatar) - { - return; - } + LLFastTimer t(FTM_SHADOW_AVATAR); if (mDrawFace.empty()) { @@ -327,7 +320,7 @@ S32 LLDrawPoolAvatar::getNumPasses() void LLDrawPoolAvatar::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { renderAvatars(NULL, 2); @@ -339,7 +332,7 @@ void LLDrawPoolAvatar::render(S32 pass) void LLDrawPoolAvatar::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); //reset vertex buffer mappings LLVertexBuffer::unbind(); @@ -365,7 +358,7 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass) void LLDrawPoolAvatar::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_CHARACTERS); + LLFastTimer t(FTM_RENDER_CHARACTERS); if (LLPipeline::sImpostorRender) { @@ -609,13 +602,6 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) return; } - - - if (!gRenderAvatar) - { - return; - } - if (mDrawFace.empty() && !single_avatar) { return; @@ -647,7 +633,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) if (pass==1 && (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) || LLViewerPartSim::getMaxPartCount() <= 0)) { // debug code to draw a sphere in place of avatar - gGL.getTexUnit(0)->bind(LLViewerImage::sWhiteImagep.get()); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep); gGL.setColorMask(true, true); LLVector3 pos = avatarp->getPositionAgent(); gGL.color4f(1.0f, 1.0f, 1.0f, 0.7f); @@ -761,10 +747,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass) //----------------------------------------------------------------------------- void LLDrawPoolAvatar::renderForSelect() { - if (!gRenderAvatar) - { - return; - } + if (mDrawFace.empty()) { @@ -836,7 +819,7 @@ void LLDrawPoolAvatar::renderForSelect() //----------------------------------------------------------------------------- // getDebugTexture() //----------------------------------------------------------------------------- -LLViewerImage *LLDrawPoolAvatar::getDebugTexture() +LLViewerTexture *LLDrawPoolAvatar::getDebugTexture() { if (mReferences.empty()) { diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h index 1e2630e1fb..6a2b7fc218 100644 --- a/indra/newview/lldrawpoolavatar.h +++ b/indra/newview/lldrawpoolavatar.h @@ -105,7 +105,7 @@ public: void endDeferredRigid(); void endDeferredSkinned(); - /*virtual*/ LLViewerImage *getDebugTexture(); + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null. diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index b11dcc1608..331ba67d36 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -37,21 +37,19 @@ #include "llstl.h" #include "llviewercontrol.h" #include "lldir.h" -#include "llimagegl.h" #include "m3math.h" #include "m4math.h" #include "v4math.h" #include "llglheaders.h" #include "llrender.h" -#include "llagent.h" #include "llcubemap.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" #include "lltextureentry.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "pipeline.h" #include "llspatialpartition.h" #include "llviewershadermgr.h" @@ -75,6 +73,7 @@ const U32 VERTEX_MASK_BUMP = LLVertexBuffer::MAP_VERTEX |LLVertexBuffer::MAP_TEX U32 LLDrawPoolBump::sVertexMask = VERTEX_MASK_SHINY; + static LLGLSLShader* shader = NULL; static S32 cube_channel = -1; static S32 diffuse_channel = -1; @@ -127,9 +126,9 @@ void LLStandardBumpmap::restoreGL() { // *NOTE: This buffer size is hard coded into scanf() below. char label[2048] = ""; /* Flawfinder: ignore */ - char bump_file[2048] = ""; /* Flawfinder: ignore */ + char bump_image_id[2048] = ""; /* Flawfinder: ignore */ fields_read = fscanf( /* Flawfinder: ignore */ - file, "\n%2047s %2047s", label, bump_file); + file, "\n%2047s %2047s", label, bump_image_id); if( EOF == fields_read ) { break; @@ -140,12 +139,13 @@ void LLStandardBumpmap::restoreGL() return; } -// llinfos << "Loading bumpmap: " << bump_file << " from viewerart" << llendl; +// llinfos << "Loading bumpmap: " << bump_image_id << " from viewerart" << llendl; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label; gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = - gImageList.getImageFromFile(bump_file, + LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id), TRUE, FALSE, + LLViewerTexture::LOD_TEXTURE, 0, 0); gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL ); @@ -220,7 +220,7 @@ S32 LLDrawPoolBump::getNumPasses() void LLDrawPoolBump::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -247,7 +247,7 @@ void LLDrawPoolBump::beginRenderPass(S32 pass) void LLDrawPoolBump::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); if (!gPipeline.hasRenderType(LLDrawPool::POOL_SIMPLE)) { @@ -280,7 +280,7 @@ void LLDrawPoolBump::render(S32 pass) void LLDrawPoolBump::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); switch( pass ) { case 0: @@ -308,7 +308,7 @@ void LLDrawPoolBump::endRenderPass(S32 pass) //static void LLDrawPoolBump::beginShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) { @@ -383,7 +383,7 @@ void LLDrawPoolBump::beginShiny(bool invisible) void LLDrawPoolBump::renderShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) { @@ -410,7 +410,7 @@ void LLDrawPoolBump::renderShiny(bool invisible) void LLDrawPoolBump::endShiny(bool invisible) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY)|| invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)) { @@ -450,7 +450,7 @@ void LLDrawPoolBump::endShiny(bool invisible) void LLDrawPoolBump::beginFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -499,7 +499,7 @@ void LLDrawPoolBump::beginFullbrightShiny() void LLDrawPoolBump::renderFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -514,7 +514,7 @@ void LLDrawPoolBump::renderFullbrightShiny() void LLDrawPoolBump::endFullbrightShiny() { - LLFastTimer t(LLFastTimer::FTM_RENDER_SHINY); + LLFastTimer t(FTM_RENDER_SHINY); if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_FULLBRIGHT_SHINY)) { return; @@ -569,22 +569,23 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL // static BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel) { - LLImageGL* bump = NULL; + LLViewerTexture* bump = NULL; U8 bump_code = params.mBump; - LLViewerImage* tex = params.mTexture; + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params.mTexture) ; + if(!tex) + { + //if the texture is not a fetched texture + return FALSE; + } switch( bump_code ) { - case BE_NO_BUMP: - bump = NULL; + case BE_NO_BUMP: break; case BE_BRIGHTNESS: case BE_DARKNESS: - if( tex ) - { - bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); - } + bump = gBumpImageList.getBrightnessDarknessImage( tex, bump_code ); break; default: @@ -623,7 +624,7 @@ void LLDrawPoolBump::beginBump() } sVertexMask = VERTEX_MASK_BUMP; - LLFastTimer t(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer t(FTM_RENDER_BUMP); // Optional second pass: emboss bump map stop_glerror(); @@ -667,7 +668,7 @@ void LLDrawPoolBump::renderBump() return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); LLGLDisable fog(GL_FOG); LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_LEQUAL); LLGLEnable blend(GL_BLEND); @@ -704,7 +705,7 @@ void LLDrawPoolBump::beginDeferredPass(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); mShiny = TRUE; gDeferredBumpProgram.bind(); diffuse_channel = gDeferredBumpProgram.enableTexture(LLViewerShaderMgr::DIFFUSE_MAP); @@ -719,7 +720,7 @@ void LLDrawPoolBump::endDeferredPass(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); mShiny = FALSE; gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP); gDeferredBumpProgram.disableTexture(LLViewerShaderMgr::BUMP_MAP); @@ -733,7 +734,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BUMP); + LLFastTimer ftm(FTM_RENDER_BUMP); U32 type = LLRenderPass::PASS_BUMP; LLCullResult::drawinfo_list_t::iterator begin = gPipeline.beginRenderMap(type); @@ -812,7 +813,7 @@ LLBumpImageList::~LLBumpImageList() void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size) { bump &= TEM_BUMP_MASK; - LLViewerImage* bump_image = gStandardBumpmapList[bump].mImage; + LLViewerFetchedTexture* bump_image = gStandardBumpmapList[bump].mImage; if( bump_image ) { bump_image->addTextureStats(virtual_size); @@ -826,11 +827,11 @@ void LLBumpImageList::updateImages() for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); ) { bump_image_map_t::iterator curiter = iter++; - LLImageGL* image = curiter->second; + LLViewerTexture* image = curiter->second; if( image ) { BOOL destroy = TRUE; - if( image->getHasGLTexture()) + if( image->hasValidGLTexture()) { if( image->getBoundRecently() ) { @@ -853,11 +854,11 @@ void LLBumpImageList::updateImages() for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); ) { bump_image_map_t::iterator curiter = iter++; - LLImageGL* image = curiter->second; + LLViewerTexture* image = curiter->second; if( image ) { BOOL destroy = TRUE; - if( image->getHasGLTexture()) + if( image->hasValidGLTexture()) { if( image->getBoundRecently() ) { @@ -881,16 +882,16 @@ void LLBumpImageList::updateImages() // Note: the caller SHOULD NOT keep the pointer that this function returns. It may be updated as more data arrives. -LLImageGL* LLBumpImageList::getBrightnessDarknessImage(LLViewerImage* src_image, U8 bump_code ) +LLViewerTexture* LLBumpImageList::getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code ) { llassert( (bump_code == BE_BRIGHTNESS) || (bump_code == BE_DARKNESS) ); - LLImageGL* bump = NULL; + LLViewerTexture* bump = NULL; const F32 BRIGHTNESS_DARKNESS_PIXEL_AREA_THRESHOLD = 1000; - if( src_image->mMaxVirtualSize > BRIGHTNESS_DARKNESS_PIXEL_AREA_THRESHOLD ) + if( src_image->getMaxVirtualSize() > BRIGHTNESS_DARKNESS_PIXEL_AREA_THRESHOLD ) { bump_image_map_t* entries_list = NULL; - void (*callback_func)( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL; + void (*callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) = NULL; switch( bump_code ) { @@ -917,14 +918,8 @@ LLImageGL* LLBumpImageList::getBrightnessDarknessImage(LLViewerImage* src_image, LLPointer raw = new LLImageRaw(1,1,1); raw->clear(0x77, 0x77, 0x77, 0xFF); - //------------------------------ - bump = new LLImageGL( raw, TRUE); - //immediately assign bump to a global smart pointer in case some local smart pointer - //accidently releases it. - (*entries_list)[src_image->getID()] = bump; - //------------------------------ - - bump->setExplicitFormat(GL_ALPHA8, GL_ALPHA); + (*entries_list)[src_image->getID()] = LLViewerTextureManager::getLocalTexture( raw.get(), TRUE); + (*entries_list)[src_image->getID()]->setExplicitFormat(GL_ALPHA8, GL_ALPHA); // Note: this may create an LLImageGL immediately src_image->setLoadedCallback( callback_func, 0, TRUE, FALSE, new LLUUID(src_image->getID()) ); @@ -940,7 +935,7 @@ LLImageGL* LLBumpImageList::getBrightnessDarknessImage(LLViewerImage* src_image, // static -void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { LLUUID* source_asset_id = (LLUUID*)userdata; LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_BRIGHTNESS ); @@ -951,7 +946,7 @@ void LLBumpImageList::onSourceBrightnessLoaded( BOOL success, LLViewerImage *src } // static -void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { LLUUID* source_asset_id = (LLUUID*)userdata; LLBumpImageList::onSourceLoaded( success, src_vi, src, *source_asset_id, BE_DARKNESS ); @@ -961,7 +956,7 @@ void LLBumpImageList::onSourceDarknessLoaded( BOOL success, LLViewerImage *src_v } } -void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerImage* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +void LLBumpImageList::onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture* src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { if (success && LLPipeline::sRenderDeferred) { @@ -1028,7 +1023,7 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr } // static -void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) +void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump_code ) { if( success ) { @@ -1147,7 +1142,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLIma //--------------------------------------------------- //immediately assign bump to a global smart pointer in case some local smart pointer //accidently releases it. - LLPointer bump = new LLImageGL( TRUE); + LLPointer bump = LLViewerTextureManager::getLocalTexture( TRUE); if (!LLPipeline::sRenderDeferred) { @@ -1220,7 +1215,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) { if (params.mTexture.notNull()) { - gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get()); + gGL.getTexUnit(diffuse_channel)->bind(params.mTexture) ; params.mTexture->addTextureStats(params.mVSize); } else @@ -1255,7 +1250,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture) void LLDrawPoolInvisible::render(S32 pass) { //render invisiprims - LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE); + LLFastTimer t(FTM_RENDER_INVISIBLE); U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; glStencilMask(0); @@ -1284,7 +1279,7 @@ void LLDrawPoolInvisible::endDeferredPass( S32 pass ) void LLDrawPoolInvisible::renderDeferred( S32 pass ) { //render invisiprims; this doesn't work becaue it also blocks all the post-deferred stuff - LLFastTimer t(LLFastTimer::FTM_RENDER_INVISIBLE); + LLFastTimer t(FTM_RENDER_INVISIBLE); U32 invisi_mask = LLVertexBuffer::MAP_VERTEX; glStencilMask(0); diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 34c1e9c29f..bf940cf1e4 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -41,6 +41,7 @@ class LLImageRaw; class LLSpatialGroup; class LLDrawInfo; +class LLViewerFetchedTexture; class LLDrawPoolBump : public LLRenderPass { @@ -110,7 +111,7 @@ public: LLStandardBumpmap( const std::string& label ) : mLabel(label) {} std::string mLabel; - LLPointer mImage; + LLPointer mImage; static U32 sStandardBumpmapCount; // Number of valid values in gStandardBumpmapList[] @@ -140,21 +141,20 @@ public: void updateImages(); - LLImageGL* getBrightnessDarknessImage(LLViewerImage* src_image, U8 bump_code); -// LLImageGL* getTestImage(); + LLViewerTexture* getBrightnessDarknessImage(LLViewerFetchedTexture* src_image, U8 bump_code); void addTextureStats(U8 bump, const LLUUID& base_image_id, F32 virtual_size); - static void onSourceBrightnessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); - static void onSourceDarknessLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); - static void onSourceStandardLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); + static void onSourceBrightnessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); + static void onSourceDarknessLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); + static void onSourceStandardLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); static void generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nrm_image); private: - static void onSourceLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump ); + static void onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLImageRaw* src, LLUUID& source_asset_id, EBumpEffect bump ); private: - typedef std::map > bump_image_map_t; + typedef std::map > bump_image_map_t; bump_image_map_t mBrightnessEntries; bump_image_map_t mDarknessEntries; }; diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp index 1fdf87f6d2..331536fdca 100644 --- a/indra/newview/lldrawpoolsimple.cpp +++ b/indra/newview/lldrawpoolsimple.cpp @@ -35,7 +35,6 @@ #include "lldrawpoolsimple.h" #include "llviewercamera.h" -#include "llagent.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" @@ -50,7 +49,7 @@ static LLGLSLShader* fullbright_shader = NULL; void LLDrawPoolGlow::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GLOW); + LLFastTimer t(FTM_RENDER_GLOW); LLGLEnable blend(GL_BLEND); LLGLDisable test(GL_ALPHA_TEST); gGL.setSceneBlendType(LLRender::BT_ADD); @@ -98,7 +97,7 @@ void LLDrawPoolSimple::prerender() void LLDrawPoolSimple::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); if (LLPipeline::sUnderWaterRender) { @@ -125,7 +124,7 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass) void LLDrawPoolSimple::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); LLRenderPass::endRenderPass(pass); if (mVertexShaderLevel > 0){ @@ -140,7 +139,7 @@ void LLDrawPoolSimple::render(S32 pass) LLGLDisable alpha_test(GL_ALPHA_TEST); { //render simple - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); gPipeline.enableLightsDynamic(); renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); @@ -157,13 +156,13 @@ void LLDrawPoolSimple::render(S32 pass) void LLDrawPoolSimple::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); gDeferredDiffuseProgram.bind(); } void LLDrawPoolSimple::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); LLRenderPass::endRenderPass(pass); gDeferredDiffuseProgram.unbind(); @@ -175,7 +174,7 @@ void LLDrawPoolSimple::renderDeferred(S32 pass) LLGLDisable alpha_test(GL_ALPHA_TEST); { //render simple - LLFastTimer t(LLFastTimer::FTM_RENDER_SIMPLE); + LLFastTimer t(FTM_RENDER_SIMPLE); renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask()); } } @@ -195,7 +194,7 @@ void LLDrawPoolGrass::prerender() void LLDrawPoolGrass::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); if (LLPipeline::sUnderWaterRender) { @@ -222,7 +221,7 @@ void LLDrawPoolGrass::beginRenderPass(S32 pass) void LLDrawPoolGrass::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); LLRenderPass::endRenderPass(pass); if (mVertexShaderLevel > 0) @@ -237,7 +236,7 @@ void LLDrawPoolGrass::render(S32 pass) gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); LLGLEnable test(GL_ALPHA_TEST); gGL.setSceneBlendType(LLRender::BT_ALPHA); //render grass @@ -262,7 +261,7 @@ void LLDrawPoolGrass::renderDeferred(S32 pass) gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); { - LLFastTimer t(LLFastTimer::FTM_RENDER_GRASS); + LLFastTimer t(FTM_RENDER_GRASS); gDeferredTreeProgram.bind(); LLGLEnable test(GL_ALPHA_TEST); //render grass @@ -286,7 +285,7 @@ void LLDrawPoolFullbright::prerender() void LLDrawPoolFullbright::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); if (LLPipeline::sUnderWaterRender) { @@ -300,7 +299,7 @@ void LLDrawPoolFullbright::beginRenderPass(S32 pass) void LLDrawPoolFullbright::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); LLRenderPass::endRenderPass(pass); if (mVertexShaderLevel > 0) @@ -311,7 +310,7 @@ void LLDrawPoolFullbright::endRenderPass(S32 pass) void LLDrawPoolFullbright::render(S32 pass) { //render fullbright - LLFastTimer t(LLFastTimer::FTM_RENDER_FULLBRIGHT); + LLFastTimer t(FTM_RENDER_FULLBRIGHT); if (mVertexShaderLevel > 0) { fullbright_shader->bind(); diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp index f0ed38057b..8428be194f 100644 --- a/indra/newview/lldrawpoolsky.cpp +++ b/indra/newview/lldrawpoolsky.cpp @@ -41,9 +41,8 @@ #include "llface.h" #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" -#include "llviewerwindow.h" #include "llvosky.h" #include "llworld.h" // To get water height #include "pipeline.h" diff --git a/indra/newview/lldrawpoolterrain.cpp b/indra/newview/lldrawpoolterrain.cpp index 2c644b0fd5..345dd6bb84 100644 --- a/indra/newview/lldrawpoolterrain.cpp +++ b/indra/newview/lldrawpoolterrain.cpp @@ -49,7 +49,7 @@ #include "llviewerparceloverlay.h" #include "llvosurfacepatch.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" // To get alpha gradients +#include "llviewertexturelist.h" // To get alpha gradients #include "llworld.h" #include "pipeline.h" #include "llviewershadermgr.h" @@ -61,29 +61,35 @@ int DebugDetailMap = 0; S32 LLDrawPoolTerrain::sDetailMode = 1; F32 LLDrawPoolTerrain::sDetailScale = DETAIL_SCALE; static LLGLSLShader* sShader = NULL; +static LLFastTimer::DeclareTimer FTM_SHADOW_TERRAIN("Terrain Shadow"); -LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerImage *texturep) : + +LLDrawPoolTerrain::LLDrawPoolTerrain(LLViewerTexture *texturep) : LLFacePool(POOL_TERRAIN), mTexturep(texturep) { // Hack! sDetailScale = 1.f/gSavedSettings.getF32("RenderTerrainScale"); sDetailMode = gSavedSettings.getS32("RenderTerrainDetail"); - mAlphaRampImagep = gImageList.getImageFromFile("alpha_gradient.tga", - TRUE, TRUE, GL_ALPHA8, GL_ALPHA, + mAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient.tga", + TRUE, TRUE, + LLViewerTexture::FETCHED_TEXTURE, + GL_ALPHA8, GL_ALPHA, LLUUID("e97cf410-8e61-7005-ec06-629eba4cd1fb")); - gGL.getTexUnit(0)->bind(mAlphaRampImagep.get()); + gGL.getTexUnit(0)->bind(mAlphaRampImagep); mAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP); - m2DAlphaRampImagep = gImageList.getImageFromFile("alpha_gradient_2d.j2c", - TRUE, TRUE, GL_ALPHA8, GL_ALPHA, + m2DAlphaRampImagep = LLViewerTextureManager::getFetchedTextureFromFile("alpha_gradient_2d.j2c", + TRUE, TRUE, + LLViewerTexture::FETCHED_TEXTURE, + GL_ALPHA8, GL_ALPHA, LLUUID("38b86f85-2575-52a9-a531-23108d8da837")); - gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(0)->bind(m2DAlphaRampImagep); m2DAlphaRampImagep->setAddressMode(LLTexUnit::TAM_CLAMP); - mTexturep->setBoostLevel(LLViewerImage::BOOST_TERRAIN); + mTexturep->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } @@ -127,7 +133,7 @@ void LLDrawPoolTerrain::prerender() void LLDrawPoolTerrain::beginRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = LLPipeline::sUnderWaterRender ? @@ -142,7 +148,7 @@ void LLDrawPoolTerrain::beginRenderPass( S32 pass ) void LLDrawPoolTerrain::endRenderPass( S32 pass ) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::endRenderPass(pass); if (mVertexShaderLevel > 1 && sShader->mShaderLevel > 0) { @@ -158,7 +164,7 @@ S32 LLDrawPoolTerrain::getDetailMode() void LLDrawPoolTerrain::render(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { @@ -170,7 +176,7 @@ void LLDrawPoolTerrain::render(S32 pass) LLVLComposition *compp = regionp->getComposition(); for (S32 i = 0; i < 4; i++) { - compp->mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); + compp->mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); compp->mDetailTextures[i]->addTextureStats(1024.f*1024.f); // assume large pixel area } @@ -231,7 +237,7 @@ void LLDrawPoolTerrain::render(S32 pass) void LLDrawPoolTerrain::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::beginRenderPass(pass); sShader = &gDeferredTerrainProgram; @@ -241,14 +247,14 @@ void LLDrawPoolTerrain::beginDeferredPass(S32 pass) void LLDrawPoolTerrain::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); LLFacePool::endRenderPass(pass); sShader->unbind(); } void LLDrawPoolTerrain::renderDeferred(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TERRAIN); + LLFastTimer t(FTM_RENDER_TERRAIN); if (mDrawFace.empty()) { return; @@ -258,7 +264,7 @@ void LLDrawPoolTerrain::renderDeferred(S32 pass) void LLDrawPoolTerrain::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); LLFacePool::beginRenderPass(pass); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gDeferredShadowProgram.bind(); @@ -266,14 +272,14 @@ void LLDrawPoolTerrain::beginShadowPass(S32 pass) void LLDrawPoolTerrain::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); LLFacePool::endRenderPass(pass); gDeferredShadowProgram.unbind(); } void LLDrawPoolTerrain::renderShadow(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TERRAIN); + LLFastTimer t(FTM_SHADOW_TERRAIN); if (mDrawFace.empty()) { return; @@ -289,10 +295,10 @@ void LLDrawPoolTerrain::renderFullShader() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; - LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; - LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; - LLViewerImage *detail_texture3p = compp->mDetailTextures[3]; + LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; + LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; + LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; + LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -363,7 +369,7 @@ void LLDrawPoolTerrain::renderFullShader() // Alpha Ramp // S32 alpha_ramp = sShader->enableTexture(LLViewerShaderMgr::TERRAIN_ALPHARAMP); - gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(alpha_ramp)->bind(m2DAlphaRampImagep); // GL_BLEND disabled by default drawLoop(); @@ -429,10 +435,10 @@ void LLDrawPoolTerrain::renderFull4TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; - LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; - LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; - LLViewerImage *detail_texture3p = compp->mDetailTextures[3]; + LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; + LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; + LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; + LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -527,7 +533,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 1: Generate alpha ramp for detail2/detail3 transition // - gGL.getTexUnit(1)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(1)->bind(m2DAlphaRampImagep); gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(1)->activate(); @@ -559,7 +565,7 @@ void LLDrawPoolTerrain::renderFull4TU() // // Stage 3: Generate alpha ramp for detail1/detail2 transition // - gGL.getTexUnit(3)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(3)->bind(m2DAlphaRampImagep); gGL.getTexUnit(3)->enable(LLTexUnit::TT_TEXTURE); gGL.getTexUnit(3)->activate(); @@ -630,10 +636,10 @@ void LLDrawPoolTerrain::renderFull2TU() // Hack! Get the region that this draw pool is rendering from! LLViewerRegion *regionp = mDrawFace[0]->getDrawable()->getVObj()->getRegion(); LLVLComposition *compp = regionp->getComposition(); - LLViewerImage *detail_texture0p = compp->mDetailTextures[0]; - LLViewerImage *detail_texture1p = compp->mDetailTextures[1]; - LLViewerImage *detail_texture2p = compp->mDetailTextures[2]; - LLViewerImage *detail_texture3p = compp->mDetailTextures[3]; + LLViewerTexture *detail_texture0p = compp->mDetailTextures[0]; + LLViewerTexture *detail_texture1p = compp->mDetailTextures[1]; + LLViewerTexture *detail_texture2p = compp->mDetailTextures[2]; + LLViewerTexture *detail_texture3p = compp->mDetailTextures[3]; LLVector3d region_origin_global = gAgent.getRegion()->getOriginGlobal(); F32 offset_x = (F32)fmod(region_origin_global.mdV[VX], 1.0/(F64)sDetailScale)*sDetailScale; @@ -671,7 +677,7 @@ void LLDrawPoolTerrain::renderFull2TU() // // Stage 0: Generate alpha ramp for detail0/detail1 transition // - gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(0)->bind(m2DAlphaRampImagep); glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); @@ -709,7 +715,7 @@ void LLDrawPoolTerrain::renderFull2TU() // // Stage 0: Generate alpha ramp for detail1/detail2 transition // - gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(0)->bind(m2DAlphaRampImagep); // Set the texture matrix glMatrixMode(GL_TEXTURE); @@ -749,7 +755,7 @@ void LLDrawPoolTerrain::renderFull2TU() // Stage 0: Generate alpha ramp for detail2/detail3 transition // gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->bind(m2DAlphaRampImagep.get()); + gGL.getTexUnit(0)->bind(m2DAlphaRampImagep); // Set the texture matrix glMatrixMode(GL_TEXTURE); glLoadIdentity(); @@ -822,7 +828,7 @@ void LLDrawPoolTerrain::renderSimple() gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(0)->bind(mTexturep.get()); + gGL.getTexUnit(0)->bind(mTexturep); LLVector3 origin_agent = mDrawFace[0]->getDrawable()->getVObj()->getRegion()->getOriginAgent(); F32 tscale = 1.f/256.f; @@ -872,7 +878,7 @@ void LLDrawPoolTerrain::renderOwnership() LLSurface *surfacep = surface_patchp->getSurface(); LLViewerRegion *regionp = surfacep->getRegion(); LLViewerParcelOverlay *overlayp = regionp->getParcelOverlay(); - LLImageGL *texturep = overlayp->getTexture(); + LLViewerTexture *texturep = overlayp->getTexture(); gGL.getTexUnit(0)->bind(texturep); @@ -920,9 +926,10 @@ void LLDrawPoolTerrain::renderForSelect() } } -void LLDrawPoolTerrain::dirtyTextures(const std::set& textures) +void LLDrawPoolTerrain::dirtyTextures(const std::set& textures) { - if (textures.find(mTexturep) != textures.end()) + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(mTexturep) ; + if (tex && textures.find(tex) != textures.end()) { for (std::vector::iterator iter = mReferences.begin(); iter != mReferences.end(); iter++) @@ -933,12 +940,12 @@ void LLDrawPoolTerrain::dirtyTextures(const std::set& textures) } } -LLViewerImage *LLDrawPoolTerrain::getTexture() +LLViewerTexture *LLDrawPoolTerrain::getTexture() { return mTexturep; } -LLViewerImage *LLDrawPoolTerrain::getDebugTexture() +LLViewerTexture *LLDrawPoolTerrain::getDebugTexture() { return mTexturep; } diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 19d09e2feb..2e2a36d533 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -37,7 +37,7 @@ class LLDrawPoolTerrain : public LLFacePool { - LLPointer mTexturep; + LLPointer mTexturep; public: enum { @@ -53,7 +53,7 @@ public: virtual U32 getVertexDataMask(); static S32 getDetailMode(); - LLDrawPoolTerrain(LLViewerImage *texturep); + LLDrawPoolTerrain(LLViewerTexture *texturep); virtual ~LLDrawPoolTerrain(); /*virtual*/ LLDrawPool *instancePool(); @@ -73,14 +73,14 @@ public: /*virtual*/ void beginRenderPass( S32 pass ); /*virtual*/ void endRenderPass( S32 pass ); /*virtual*/ void renderForSelect(); - /*virtual*/ void dirtyTextures(const std::set& textures); - /*virtual*/ LLViewerImage *getTexture(); - /*virtual*/ LLViewerImage *getDebugTexture(); + /*virtual*/ void dirtyTextures(const std::set& textures); + /*virtual*/ LLViewerTexture *getTexture(); + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display - LLPointer mAlphaRampImagep; - LLPointer m2DAlphaRampImagep; - LLPointer mAlphaNoiseImagep; + LLPointer mAlphaRampImagep; + LLPointer m2DAlphaRampImagep; + LLPointer mAlphaNoiseImagep; static S32 sDetailMode; static F32 sDetailScale; // meters per texture diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp index 2f2b07232a..5cb1fcb635 100644 --- a/indra/newview/lldrawpooltree.cpp +++ b/indra/newview/lldrawpooltree.cpp @@ -37,7 +37,6 @@ #include "lldrawable.h" #include "llface.h" #include "llsky.h" -#include "llviewerwindow.h" #include "llvotree.h" #include "pipeline.h" #include "llviewercamera.h" @@ -47,12 +46,13 @@ S32 LLDrawPoolTree::sDiffTex = 0; static LLGLSLShader* shader = NULL; +static LLFastTimer::DeclareTimer FTM_SHADOW_TREE("Tree Shadow"); -LLDrawPoolTree::LLDrawPoolTree(LLViewerImage *texturep) : +LLDrawPoolTree::LLDrawPoolTree(LLViewerTexture *texturep) : LLFacePool(POOL_TREE), mTexturep(texturep) { - gGL.getTexUnit(0)->bind(mTexturep.get()); + gGL.getTexUnit(0)->bind(mTexturep); mTexturep->setAddressMode(LLTexUnit::TAM_WRAP); } @@ -68,7 +68,7 @@ void LLDrawPoolTree::prerender() void LLDrawPoolTree::beginRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); if (LLPipeline::sUnderWaterRender) @@ -92,7 +92,7 @@ void LLDrawPoolTree::beginRenderPass(S32 pass) void LLDrawPoolTree::render(S32 pass) { - LLFastTimer t(LLPipeline::sShadowRender ? LLFastTimer::FTM_SHADOW_TREE : LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(LLPipeline::sShadowRender ? FTM_SHADOW_TREE : FTM_RENDER_TREES); if (mDrawFace.empty()) { @@ -123,7 +123,7 @@ void LLDrawPoolTree::render(S32 pass) void LLDrawPoolTree::endRenderPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); if (gPipeline.canUseWindLightShadersOnObjects()) @@ -137,7 +137,7 @@ void LLDrawPoolTree::endRenderPass(S32 pass) //============================================ void LLDrawPoolTree::beginDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); shader = &gDeferredTreeProgram; @@ -151,7 +151,7 @@ void LLDrawPoolTree::renderDeferred(S32 pass) void LLDrawPoolTree::endDeferredPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_RENDER_TREES); + LLFastTimer t(FTM_RENDER_TREES); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); shader->unbind(); @@ -162,7 +162,7 @@ void LLDrawPoolTree::endDeferredPass(S32 pass) //============================================ void LLDrawPoolTree::beginShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); + LLFastTimer t(FTM_SHADOW_TREE); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); gDeferredShadowProgram.bind(); } @@ -174,7 +174,7 @@ void LLDrawPoolTree::renderShadow(S32 pass) void LLDrawPoolTree::endShadowPass(S32 pass) { - LLFastTimer t(LLFastTimer::FTM_SHADOW_TREE); + LLFastTimer t(FTM_SHADOW_TREE); gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gDeferredShadowProgram.unbind(); } @@ -247,7 +247,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting) LLGLState normalize(GL_NORMALIZE, TRUE); // Bind the texture for this tree. - gGL.getTexUnit(sDiffTex)->bind(mTexturep.get()); + gGL.getTexUnit(sDiffTex)->bind(mTexturep); U32 indices_drawn = 0; @@ -377,12 +377,12 @@ BOOL LLDrawPoolTree::verify() const return TRUE; } -LLViewerImage *LLDrawPoolTree::getTexture() +LLViewerTexture *LLDrawPoolTree::getTexture() { return mTexturep; } -LLViewerImage *LLDrawPoolTree::getDebugTexture() +LLViewerTexture *LLDrawPoolTree::getDebugTexture() { return mTexturep; } diff --git a/indra/newview/lldrawpooltree.h b/indra/newview/lldrawpooltree.h index 80c4fdfffe..bc7711d4e8 100644 --- a/indra/newview/lldrawpooltree.h +++ b/indra/newview/lldrawpooltree.h @@ -37,7 +37,7 @@ class LLDrawPoolTree : public LLFacePool { - LLPointer mTexturep; + LLPointer mTexturep; public: enum { @@ -48,7 +48,7 @@ public: virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } - LLDrawPoolTree(LLViewerImage *texturep); + LLDrawPoolTree(LLViewerTexture *texturep); /*virtual*/ LLDrawPool *instancePool(); @@ -70,8 +70,8 @@ public: /*virtual*/ S32 getNumPasses() { return 1; } /*virtual*/ void renderForSelect(); /*virtual*/ BOOL verify() const; - /*virtual*/ LLViewerImage *getTexture(); - /*virtual*/ LLViewerImage *getDebugTexture(); + /*virtual*/ LLViewerTexture *getTexture(); + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display static S32 sDiffTex; diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index ce3425dd9e..fd4dc123d5 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -45,8 +45,7 @@ #include "lldrawable.h" #include "llface.h" #include "llsky.h" -#include "llviewercamera.h" // to get OGL_TO_CFR_ROTATION -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "llvosky.h" #include "llvowater.h" @@ -70,17 +69,17 @@ LLVector3 LLDrawPoolWater::sLightDir; LLDrawPoolWater::LLDrawPoolWater() : LLFacePool(POOL_WATER) { - mHBTex[0] = gImageList.getImage(gSunTextureID, TRUE, TRUE); - gGL.getTexUnit(0)->bind(mHBTex[0].get()); + mHBTex[0] = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, TRUE); + gGL.getTexUnit(0)->bind(mHBTex[0]) ; mHBTex[0]->setAddressMode(LLTexUnit::TAM_CLAMP); - mHBTex[1] = gImageList.getImage(gMoonTextureID, TRUE, TRUE); - gGL.getTexUnit(0)->bind(mHBTex[1].get()); + mHBTex[1] = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, TRUE); + gGL.getTexUnit(0)->bind(mHBTex[1]); mHBTex[1]->setAddressMode(LLTexUnit::TAM_CLAMP); - mWaterImagep = gImageList.getImage(WATER_TEST); + mWaterImagep = LLViewerTextureManager::getFetchedTexture(WATER_TEST); mWaterImagep->setNoDelete() ; - mWaterNormp = gImageList.getImage(DEFAULT_WATER_NORMAL); + mWaterNormp = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL); mWaterNormp->setNoDelete() ; restoreGL(); @@ -139,7 +138,7 @@ void LLDrawPoolWater::endPostDeferredPass(S32 pass) void LLDrawPoolWater::render(S32 pass) { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_WATER); + LLFastTimer ftm(FTM_RENDER_WATER); if (mDrawFace.empty() || LLDrawable::getCurrentFrame() <= 1) { return; @@ -185,7 +184,7 @@ void LLDrawPoolWater::render(S32 pass) mWaterImagep->addTextureStats(1024.f*1024.f); gGL.getTexUnit(1)->activate(); gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(1)->bind(mWaterImagep.get()); + gGL.getTexUnit(1)->bind(mWaterImagep) ; LLVector3 camera_up = LLViewerCamera::getInstance()->getUpAxis(); F32 up_dot = camera_up * LLVector3::z_axis; @@ -330,7 +329,7 @@ void LLDrawPoolWater::renderReflection(LLFace* face) LLGLSNoFog noFog; - gGL.getTexUnit(0)->bind(mHBTex[dr].get()); + gGL.getTexUnit(0)->bind(mHBTex[dr]); LLOverrideFaceColor override(this, face->getFaceColor().mV); face->renderIndexed(); @@ -420,11 +419,11 @@ void LLDrawPoolWater::shade() // change mWaterNormp if needed if (mWaterNormp->getID() != param_mgr->getNormalMapID()) { - mWaterNormp = gImageList.getImage(param_mgr->getNormalMapID()); + mWaterNormp = LLViewerTextureManager::getFetchedTexture(param_mgr->getNormalMapID()); } mWaterNormp->addTextureStats(1024.f*1024.f); - gGL.getTexUnit(bumpTex)->bind(mWaterNormp.get()); + gGL.getTexUnit(bumpTex)->bind(mWaterNormp) ; if (gSavedSettings.getBOOL("RenderWaterMipNormal")) { mWaterNormp->setFilteringOption(LLTexUnit::TFO_ANISOTROPIC); @@ -588,20 +587,9 @@ void LLDrawPoolWater::renderForSelect() return; } - -void LLDrawPoolWater::renderFaceSelected(LLFace *facep, - LLImageGL *image, - const LLColor4 &color, - const S32 index_offset, const S32 index_count) +LLViewerTexture *LLDrawPoolWater::getDebugTexture() { - // Can't select water - return; -} - - -LLViewerImage *LLDrawPoolWater::getDebugTexture() -{ - return LLViewerImage::sSmokeImagep; + return LLViewerFetchedTexture::sSmokeImagep; } LLColor3 LLDrawPoolWater::getDebugColor() const diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 6351041140..e28ac1cfab 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -43,9 +43,9 @@ class LLWaterSurface; class LLDrawPoolWater: public LLFacePool { protected: - LLPointer mHBTex[2]; - LLPointer mWaterImagep; - LLPointer mWaterNormp; + LLPointer mHBTex[2]; + LLPointer mWaterImagep; + LLPointer mWaterNormp; const LLWaterSurface *mWaterSurface; public: @@ -78,12 +78,10 @@ public: /*virtual*/ S32 getNumPasses(); /*virtual*/ void render(S32 pass = 0); - /*virtual*/ void renderFaceSelected(LLFace *facep, LLImageGL *image, const LLColor4 &color, - const S32 index_offset = 0, const S32 index_count = 0); /*virtual*/ void prerender(); /*virtual*/ void renderForSelect(); - /*virtual*/ LLViewerImage *getDebugTexture(); + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display void renderReflection(LLFace* face); diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp index 6ff65c7ed0..c14ca2473b 100644 --- a/indra/newview/lldrawpoolwlsky.cpp +++ b/indra/newview/lldrawpoolwlsky.cpp @@ -42,12 +42,11 @@ #include "llwlparammanager.h" #include "llsky.h" #include "llvowlsky.h" -#include "llagent.h" #include "llviewerregion.h" #include "llface.h" #include "llrender.h" -LLPointer LLDrawPoolWLSky::sCloudNoiseTexture = NULL; +LLPointer LLDrawPoolWLSky::sCloudNoiseTexture = NULL; LLPointer LLDrawPoolWLSky::sCloudNoiseRawImage = NULL; @@ -71,7 +70,7 @@ LLDrawPoolWLSky::LLDrawPoolWLSky(void) : cloudNoiseFile->decode(sCloudNoiseRawImage, 0.0f); - LLImageGL::create(sCloudNoiseTexture, sCloudNoiseRawImage, TRUE); + sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE); LLWLParamManager::instance()->propagateParameters(); } @@ -83,7 +82,7 @@ LLDrawPoolWLSky::~LLDrawPoolWLSky() sCloudNoiseRawImage = NULL; } -LLViewerImage *LLDrawPoolWLSky::getDebugTexture() +LLViewerTexture *LLDrawPoolWLSky::getDebugTexture() { return NULL; } @@ -224,7 +223,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() LLFace * face = gSky.mVOSkyp->mFace[LLVOSky::FACE_SUN]; if (gSky.mVOSkyp->getSun().getDraw() && face->getGeomCount()) { - LLImageGL * tex = face->getTexture(); + LLViewerTexture * tex = face->getTexture(); gGL.getTexUnit(0)->bind(tex); LLColor4 color(gSky.mVOSkyp->getSun().getInterpColor()); LLFacePool::LLOverrideFaceColor color_override(this, color); @@ -239,8 +238,7 @@ void LLDrawPoolWLSky::renderHeavenlyBodies() // *NOTE: even though we already bound this texture above for the // stars register combiners, we bind again here for defensive reasons, // since LLImageGL::bind detects that it's a noop, and optimizes it out. - LLImageGL * tex = face->getTexture(); - gGL.getTexUnit(0)->bind(tex); + gGL.getTexUnit(0)->bind(face->getTexture()); LLColor4 color(gSky.mVOSkyp->getMoon().getInterpColor()); F32 a = gSky.mVOSkyp->getMoon().getDirection().mV[2]; if (a > 0.f) @@ -261,7 +259,7 @@ void LLDrawPoolWLSky::render(S32 pass) { return; } - LLFastTimer ftm(LLFastTimer::FTM_RENDER_WL_SKY); + LLFastTimer ftm(FTM_RENDER_WL_SKY); const F32 camHeightLocal = LLWLParamManager::instance()->getDomeOffset() * LLWLParamManager::instance()->getDomeRadius(); @@ -280,9 +278,8 @@ void LLDrawPoolWLSky::render(S32 pass) // *NOTE: have to bind a texture here since register combiners blending in // renderStars() requires something to be bound and we might as well only - // bind the moon's texture once. - LLImageGL * tex = gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture(); - gGL.getTexUnit(0)->bind(tex); + // bind the moon's texture once. + gGL.getTexUnit(0)->bind(gSky.mVOSkyp->mFace[LLVOSky::FACE_MOON]->getTexture()); renderHeavenlyBodies(); @@ -306,7 +303,7 @@ LLDrawPoolWLSky *LLDrawPoolWLSky::instancePool() return new LLDrawPoolWLSky(); } -LLViewerImage* LLDrawPoolWLSky::getTexture() +LLViewerTexture* LLDrawPoolWLSky::getTexture() { return NULL; } @@ -324,5 +321,5 @@ void LLDrawPoolWLSky::cleanupGL() //static void LLDrawPoolWLSky::restoreGL() { - LLImageGL::create(sCloudNoiseTexture, sCloudNoiseRawImage, TRUE); + sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE); } diff --git a/indra/newview/lldrawpoolwlsky.h b/indra/newview/lldrawpoolwlsky.h index c7a1f3fe27..7ff760ac39 100644 --- a/indra/newview/lldrawpoolwlsky.h +++ b/indra/newview/lldrawpoolwlsky.h @@ -55,7 +55,7 @@ public: /*virtual*/ void endPostDeferredPass(S32 pass) { endRenderPass(pass); } /*virtual*/ void renderPostDeferred(S32 pass) { render(pass); } - /*virtual*/ LLViewerImage *getDebugTexture(); + /*virtual*/ LLViewerTexture *getDebugTexture(); /*virtual*/ void beginRenderPass( S32 pass ); /*virtual*/ void endRenderPass( S32 pass ); /*virtual*/ S32 getNumPasses() { return 1; } @@ -65,11 +65,11 @@ public: /*virtual*/ BOOL verify() const { return TRUE; } // Verify that all data in the draw pool is correct! /*virtual*/ S32 getVertexShaderLevel() const { return mVertexShaderLevel; } - //static LLDrawPool* createPool(const U32 type, LLViewerImage *tex0 = NULL); + //static LLDrawPool* createPool(const U32 type, LLViewerTexture *tex0 = NULL); // Create an empty new instance of the pool. /*virtual*/ LLDrawPoolWLSky *instancePool(); ///< covariant override - /*virtual*/ LLViewerImage* getTexture(); + /*virtual*/ LLViewerTexture* getTexture(); /*virtual*/ BOOL isFacePool() { return FALSE; } /*virtual*/ void resetDrawOrders(); @@ -83,7 +83,7 @@ private: void renderHeavenlyBodies(); private: - static LLPointer sCloudNoiseTexture; + static LLPointer sCloudNoiseTexture; static LLPointer sCloudNoiseRawImage; }; diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index 62fcf60e7f..0bb5edf3f9 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -1,6 +1,6 @@ /** * @file lldynamictexture.cpp - * @brief Implementation of LLDynamicTexture class + * @brief Implementation of LLViewerDynamicTexture class * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -33,28 +33,29 @@ #include "llviewerprecompiledheaders.h" #include "lldynamictexture.h" + +// Linden library includes #include "llglheaders.h" +#include "llwindow.h" // getPosition() + +// Viewer includes #include "llviewerwindow.h" #include "llviewercamera.h" #include "llviewercontrol.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llvertexbuffer.h" #include "llviewerdisplay.h" #include "llrender.h" // static -LLDynamicTexture::instance_list_t LLDynamicTexture::sInstances[ LLDynamicTexture::ORDER_COUNT ]; -S32 LLDynamicTexture::sNumRenders = 0; +LLViewerDynamicTexture::instance_list_t LLViewerDynamicTexture::sInstances[ LLViewerDynamicTexture::ORDER_COUNT ]; +S32 LLViewerDynamicTexture::sNumRenders = 0; //----------------------------------------------------------------------------- -// LLDynamicTexture() +// LLViewerDynamicTexture() //----------------------------------------------------------------------------- -LLDynamicTexture::LLDynamicTexture(S32 width, S32 height, S32 components, EOrder order, BOOL clamp) : - mWidth(width), - mHeight(height), - mComponents(components), - mTexture(NULL), - mLastBindTime(0), +LLViewerDynamicTexture::LLViewerDynamicTexture(S32 width, S32 height, S32 components, EOrder order, BOOL clamp) : + LLViewerTexture(width, height, components, FALSE), mClamp(clamp) { llassert((1 <= components) && (components <= 4)); @@ -62,64 +63,56 @@ LLDynamicTexture::LLDynamicTexture(S32 width, S32 height, S32 components, EOrder generateGLTexture(); llassert( 0 <= order && order < ORDER_COUNT ); - LLDynamicTexture::sInstances[ order ].insert(this); + LLViewerDynamicTexture::sInstances[ order ].insert(this); } //----------------------------------------------------------------------------- -// LLDynamicTexture() +// LLViewerDynamicTexture() //----------------------------------------------------------------------------- -LLDynamicTexture::~LLDynamicTexture() +LLViewerDynamicTexture::~LLViewerDynamicTexture() { - releaseGLTexture(); for( S32 order = 0; order < ORDER_COUNT; order++ ) { - LLDynamicTexture::sInstances[order].erase(this); // will fail in all but one case. + LLViewerDynamicTexture::sInstances[order].erase(this); // will fail in all but one case. } } -//----------------------------------------------------------------------------- -// releaseGLTexture() -//----------------------------------------------------------------------------- -void LLDynamicTexture::releaseGLTexture() +//virtual +S8 LLViewerDynamicTexture::getType() const { - if (mTexture.notNull()) - { -// llinfos << "RELEASING " << (mWidth*mHeight*mComponents)/1024 << "K" << llendl; - mTexture = NULL; - } + return LLViewerTexture::DYNAMIC_TEXTURE ; } //----------------------------------------------------------------------------- // generateGLTexture() //----------------------------------------------------------------------------- -void LLDynamicTexture::generateGLTexture() +void LLViewerDynamicTexture::generateGLTexture() { + LLViewerTexture::generateGLTexture() ; generateGLTexture(-1, 0, 0, FALSE); } -void LLDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) +void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) { if (mComponents < 1 || mComponents > 4) { llerrs << "Bad number of components in dynamic texture: " << mComponents << llendl; } - releaseGLTexture(); - LLPointer raw_image = new LLImageRaw(mWidth, mHeight, mComponents); - mTexture = new LLViewerImage(mWidth, mHeight, mComponents, FALSE); + + LLPointer raw_image = new LLImageRaw(mFullWidth, mFullHeight, mComponents); if (internal_format >= 0) { - mTexture->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes); + setExplicitFormat(internal_format, primary_format, type_format, swap_bytes); } -// llinfos << "ALLOCATING " << (mWidth*mHeight*mComponents)/1024 << "K" << llendl; - mTexture->createGLTexture(0, raw_image); - mTexture->setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP); - mTexture->setGLTextureCreated(false); + createGLTexture(0, raw_image); + setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP); + mGLTexturep->setGLTextureCreated(false); } //----------------------------------------------------------------------------- // render() //----------------------------------------------------------------------------- -BOOL LLDynamicTexture::render() +BOOL LLViewerDynamicTexture::render() { return FALSE; } @@ -127,13 +120,13 @@ BOOL LLDynamicTexture::render() //----------------------------------------------------------------------------- // preRender() //----------------------------------------------------------------------------- -void LLDynamicTexture::preRender(BOOL clear_depth) +void LLViewerDynamicTexture::preRender(BOOL clear_depth) { { // force rendering to on-screen portion of frame buffer LLCoordScreen window_pos; gViewerWindow->getWindow()->getPosition( &window_pos ); - mOrigin.set(0, gViewerWindow->getWindowDisplayHeight() - mHeight); // top left corner + mOrigin.set(0, gViewerWindow->getWindowDisplayHeight() - mFullHeight); // top left corner if (window_pos.mX < 0) { @@ -154,7 +147,7 @@ void LLDynamicTexture::preRender(BOOL clear_depth) mCamera.setView(LLViewerCamera::getInstance()->getView()); mCamera.setNear(LLViewerCamera::getInstance()->getNear()); - glViewport(mOrigin.mX, mOrigin.mY, mWidth, mHeight); + glViewport(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); if (clear_depth) { glClear(GL_DEPTH_BUFFER_BIT); @@ -164,17 +157,21 @@ void LLDynamicTexture::preRender(BOOL clear_depth) //----------------------------------------------------------------------------- // postRender() //----------------------------------------------------------------------------- -void LLDynamicTexture::postRender(BOOL success) +void LLViewerDynamicTexture::postRender(BOOL success) { { if (success) { - success = mTexture->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mWidth, mHeight); + if(mGLTexturep.isNull()) + { + generateGLTexture() ; + } + success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); } } // restore viewport - gViewerWindow->setupViewport(); + gViewerWindow->setup2DViewport(); // restore camera LLViewerCamera::getInstance()->setOrigin(mCamera); @@ -189,7 +186,7 @@ void LLDynamicTexture::postRender(BOOL success) // updateDynamicTextures() // Calls update on each dynamic texture. Calls each group in order: "first," then "middle," then "last." //----------------------------------------------------------------------------- -BOOL LLDynamicTexture::updateAllInstances() +BOOL LLViewerDynamicTexture::updateAllInstances() { sNumRenders = 0; if (gGLManager.mIsDisabled) @@ -201,10 +198,10 @@ BOOL LLDynamicTexture::updateAllInstances() BOOL ret = FALSE ; for( S32 order = 0; order < ORDER_COUNT; order++ ) { - for (instance_list_t::iterator iter = LLDynamicTexture::sInstances[order].begin(); - iter != LLDynamicTexture::sInstances[order].end(); ++iter) + for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin(); + iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter) { - LLDynamicTexture *dynamicTexture = *iter; + LLViewerDynamicTexture *dynamicTexture = *iter; if (dynamicTexture->needsRender()) { glClear(GL_DEPTH_BUFFER_BIT); @@ -231,30 +228,18 @@ BOOL LLDynamicTexture::updateAllInstances() return ret; } -//virtual -void LLDynamicTexture::restoreGLTexture() -{ - generateGLTexture() ; -} - -//virtual -void LLDynamicTexture::destroyGLTexture() -{ - releaseGLTexture() ; -} - //----------------------------------------------------------------------------- // static // destroyGL() //----------------------------------------------------------------------------- -void LLDynamicTexture::destroyGL() +void LLViewerDynamicTexture::destroyGL() { for( S32 order = 0; order < ORDER_COUNT; order++ ) { - for (instance_list_t::iterator iter = LLDynamicTexture::sInstances[order].begin(); - iter != LLDynamicTexture::sInstances[order].end(); ++iter) + for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin(); + iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter) { - LLDynamicTexture *dynamicTexture = *iter; + LLViewerDynamicTexture *dynamicTexture = *iter; dynamicTexture->destroyGLTexture() ; } } @@ -264,7 +249,7 @@ void LLDynamicTexture::destroyGL() // static // restoreGL() //----------------------------------------------------------------------------- -void LLDynamicTexture::restoreGL() +void LLViewerDynamicTexture::restoreGL() { if (gGLManager.mIsDisabled) { @@ -273,10 +258,10 @@ void LLDynamicTexture::restoreGL() for( S32 order = 0; order < ORDER_COUNT; order++ ) { - for (instance_list_t::iterator iter = LLDynamicTexture::sInstances[order].begin(); - iter != LLDynamicTexture::sInstances[order].end(); ++iter) + for (instance_list_t::iterator iter = LLViewerDynamicTexture::sInstances[order].begin(); + iter != LLViewerDynamicTexture::sInstances[order].end(); ++iter) { - LLDynamicTexture *dynamicTexture = *iter; + LLViewerDynamicTexture *dynamicTexture = *iter; dynamicTexture->restoreGLTexture() ; } } diff --git a/indra/newview/lldynamictexture.h b/indra/newview/lldynamictexture.h index 5a20eaef9b..2a944eaada 100644 --- a/indra/newview/lldynamictexture.h +++ b/indra/newview/lldynamictexture.h @@ -1,6 +1,6 @@ /** * @file lldynamictexture.h - * @brief Implementation of LLDynamicTexture class + * @brief Implementation of LLViewerDynamicTexture class * * $LicenseInfo:firstyear=2002&license=viewergpl$ * @@ -33,61 +33,55 @@ #ifndef LL_LLDYNAMICTEXTURE_H #define LL_LLDYNAMICTEXTURE_H +#include "llcamera.h" #include "llgl.h" #include "llcoord.h" -#include "llimagegl.h" +#include "llviewertexture.h" +#include "llcamera.h" -class LLDynamicTexture +class LLViewerDynamicTexture : public LLViewerTexture { +protected: + /*virtual*/ ~LLViewerDynamicTexture(); + public: enum EOrder { ORDER_FIRST = 0, ORDER_MIDDLE = 1, ORDER_LAST = 2, ORDER_RESET = 3, ORDER_COUNT = 4 }; - LLDynamicTexture(S32 width, + LLViewerDynamicTexture(S32 width, S32 height, S32 components, // = 4, EOrder order, // = ORDER_MIDDLE, BOOL clamp); - virtual ~LLDynamicTexture(); + + /*virtual*/ S8 getType() const ; S32 getOriginX() { return mOrigin.mX; } S32 getOriginY() { return mOrigin.mY; } - S32 getWidth() { return mWidth; } - S32 getHeight() { return mHeight; } - S32 getComponents() { return mComponents; } - S32 getSize() { return mWidth * mHeight * mComponents; } + + S32 getSize() { return mFullWidth * mFullHeight * mComponents; } virtual BOOL needsRender() { return TRUE; } virtual void preRender(BOOL clear_depth = TRUE); virtual BOOL render(); virtual void postRender(BOOL success); - virtual void restoreGLTexture() ; - virtual void destroyGLTexture() ; - - LLImageGL* getTexture(void) const { return mTexture; } + virtual void restoreGLTexture() {} + virtual void destroyGLTexture() {} static BOOL updateAllInstances(); - - static void destroyGL(); - static void restoreGL(); - + static void destroyGL() ; + static void restoreGL() ; protected: - void releaseGLTexture(); void generateGLTexture(); void generateGLTexture(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes = FALSE); protected: - S32 mWidth; - S32 mHeight; - S32 mComponents; - LLPointer mTexture; - F32 mLastBindTime; BOOL mClamp; LLCoordGL mOrigin; - LLCamera mCamera; - typedef std::set instance_list_t; - static instance_list_t sInstances[ LLDynamicTexture::ORDER_COUNT ]; + + typedef std::set instance_list_t; + static instance_list_t sInstances[ LLViewerDynamicTexture::ORDER_COUNT ]; static S32 sNumRenders; }; diff --git a/indra/newview/llemote.cpp b/indra/newview/llemote.cpp index bacf3daf5a..c83846215e 100644 --- a/indra/newview/llemote.cpp +++ b/indra/newview/llemote.cpp @@ -39,7 +39,6 @@ #include "llcharacter.h" #include "m3math.h" #include "llvoavatar.h" -#include "llagent.h" //----------------------------------------------------------------------------- // Constants diff --git a/indra/newview/lleventnotifier.cpp b/indra/newview/lleventnotifier.cpp index e7403c2903..2c52cf9565 100644 --- a/indra/newview/lleventnotifier.cpp +++ b/indra/newview/lleventnotifier.cpp @@ -38,6 +38,7 @@ #include "llnotify.h" #include "lleventinfo.h" +#include "llfloaterreg.h" #include "llfloaterdirectory.h" #include "llfloaterworldmap.h" #include "llagent.h" @@ -191,12 +192,15 @@ bool LLEventNotification::handleResponse(const LLSD& notification, const LLSD& r switch (option) { case 0: - gAgent.teleportViaLocation(getEventPosGlobal()); - gFloaterWorldMap->trackLocation(getEventPosGlobal()); - break; + { + gAgent.teleportViaLocation(getEventPosGlobal()); + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) floater_world_map->trackLocation(getEventPosGlobal()); + break; + } case 1: gDisplayEventHack = TRUE; - LLFloaterDirectory::showEvents(getEventID()); + LLFloaterReg::showInstance("search", LLSD().insert("panel", "event").insert("id", S32(getEventID()))); break; case 2: break; diff --git a/indra/newview/lleventpoll.h b/indra/newview/lleventpoll.h index 12e4b49d57..f2465a361e 100644 --- a/indra/newview/lleventpoll.h +++ b/indra/newview/lleventpoll.h @@ -35,6 +35,9 @@ #include "llhttpclient.h" +class LLHost; + + class LLEventPoll ///< implements the viewer side of server-to-viewer pushed events. { diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp index 69edccacf0..bef9e40c49 100644 --- a/indra/newview/llface.cpp +++ b/indra/newview/llface.cpp @@ -47,7 +47,7 @@ #include "lllightconstants.h" #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llvosky.h" #include "llvovolume.h" #include "pipeline.h" @@ -179,6 +179,10 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp) void LLFace::destroy() { + if(mTexture.notNull()) + { + mTexture->removeFace(this) ; + } if (mDrawPoolp) { mDrawPoolp->removeFace(this); @@ -217,7 +221,7 @@ void LLFace::setWorldMatrix(const LLMatrix4 &mat) llerrs << "Faces on this drawable are not independently modifiable\n" << llendl; } -void LLFace::setPool(LLFacePool* new_pool, LLViewerImage *texturep) +void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep) { LLMemType mt1(LLMemType::MTYPE_DRAWABLE); @@ -247,9 +251,28 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerImage *texturep) } mDrawPoolp = new_pool; } - mTexture = texturep; + setTexture(texturep) ; } +void LLFace::setTexture(LLViewerTexture* tex) +{ + if(mTexture == tex) + { + return ; + } + + if(mTexture.notNull()) + { + mTexture->removeFace(this) ; + } + + mTexture = tex ; + + if(mTexture.notNull()) + { + mTexture->addFace(this) ; + } +} void LLFace::setTEOffset(const S32 te_offset) { @@ -422,7 +445,7 @@ void LLFace::renderForSelect(U32 data_mask) } } -void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color) +void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color) { if(mDrawablep.isNull() || mVertexBuffer.isNull() || mDrawablep->getSpatialGroup() == NULL || mDrawablep->getSpatialGroup()->isState(LLSpatialGroup::GEOM_DIRTY)) @@ -463,8 +486,8 @@ void LLFace::renderSelected(LLImageGL *imagep, const LLColor4& color) /* removed in lieu of raycast uv detection void LLFace::renderSelectedUV() { - LLViewerImage* red_blue_imagep = gImageList.getImageFromFile("uv_test1.j2c", TRUE, TRUE); - LLViewerImage* green_imagep = gImageList.getImageFromFile("uv_test2.tga", TRUE, TRUE); + LLViewerTexture* red_blue_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test1.j2c", TRUE, TRUE); + LLViewerTexture* green_imagep = LLViewerTextureManager::getFetchedTextureFromFile("uv_test2.tga", TRUE, TRUE); LLGLSUVSelect object_select; @@ -998,7 +1021,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume, break; case BE_BRIGHTNESS: case BE_DARKNESS: - if( mTexture.notNull() && mTexture->getHasGLTexture()) + if( mTexture.notNull() && mTexture->hasValidGLTexture()) { // Offset by approximately one texel S32 cur_discard = mTexture->getDiscardLevel(); diff --git a/indra/newview/llface.h b/indra/newview/llface.h index 4a551ff261..e0728fe15e 100644 --- a/indra/newview/llface.h +++ b/indra/newview/llface.h @@ -45,16 +45,15 @@ #include "xform.h" #include "lldarrayptr.h" #include "llvertexbuffer.h" -#include "llviewerimage.h" -#include "llstat.h" +#include "llviewertexture.h" #include "lldrawable.h" class LLFacePool; class LLVolume; -class LLViewerImage; +class LLViewerTexture; class LLTextureEntry; class LLVertexProgram; -class LLViewerImage; +class LLViewerTexture; class LLGeometryManager; const F32 MIN_ALPHA_SIZE = 1024.f; @@ -87,8 +86,8 @@ public: U16 getGeomCount() const { return mGeomCount; } // vertex count for this face U16 getGeomIndex() const { return mGeomIndex; } // index into draw pool U16 getGeomStart() const { return mGeomIndex; } // index into draw pool - LLViewerImage* getTexture() const { return mTexture; } - void setTexture(LLViewerImage* tex) { mTexture = tex; } + LLViewerTexture* getTexture() const { return mTexture; } + void setTexture(LLViewerTexture* tex) ; LLXformMatrix* getXform() const { return mXform; } BOOL hasGeometry() const { return mGeomCount > 0; } LLVector3 getPositionAgent() const; @@ -120,10 +119,10 @@ public: LLVertexBuffer* getVertexBuffer() const { return mVertexBuffer; } void setPoolType(U32 type) { mPoolType = type; } S32 getTEOffset() { return mTEOffset; } - LLViewerImage* getTexture() { return mTexture; } + LLViewerTexture* getTexture() { return mTexture; } void setViewerObject(LLViewerObject* object); - void setPool(LLFacePool *pool, LLViewerImage *texturep); + void setPool(LLFacePool *pool, LLViewerTexture *texturep); void setDrawable(LLDrawable *drawable); void setTEOffset(const S32 te_offset); @@ -172,7 +171,7 @@ public: void renderSelectedUV(); void renderForSelect(U32 data_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0); - void renderSelected(LLImageGL *image, const LLColor4 &color); + void renderSelected(LLViewerTexture *image, const LLColor4 &color); F32 getKey() const { return mDistance; } @@ -223,7 +222,7 @@ protected: U32 mLastIndicesIndex; LLXformMatrix* mXform; - LLPointer mTexture; + LLPointer mTexture; LLPointer mDrawablep; LLPointer mVObjp; S32 mTEOffset; diff --git a/indra/newview/llfasttimerview.cpp b/indra/newview/llfasttimerview.cpp index c9037d0fbb..8ceb41c27a 100644 --- a/indra/newview/llfasttimerview.cpp +++ b/indra/newview/llfasttimerview.cpp @@ -41,295 +41,117 @@ #include "llrender.h" #include "llmath.h" #include "llfontgl.h" +#include "llsdserialize.h" #include "llappviewer.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llui.h" #include "llviewercontrol.h" #include "llstat.h" #include "llfasttimer.h" - +#include "lltreeiterators.h" +#include "llmetricperformancetester.h" ////////////////////////////////////////////////////////////////////////////// static const S32 MAX_VISIBLE_HISTORY = 10; static const S32 LINE_GRAPH_HEIGHT = 240; -struct ft_display_info { - int timer; - const char *desc; - const LLColor4 *color; - S32 disabled; // initialized to 0 - int level; // calculated based on desc - int parent; // calculated -}; +//static const int FTV_DISPLAY_NUM = (sizeof(ft_display_table)/sizeof(ft_display_table[0])); +static S32 FTV_NUM_TIMERS; +const S32 FTV_MAX_DEPTH = 8; -static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f); -static const LLColor4 green0(0.0f, 0.5f, 0.0f, 1.0f); -static const LLColor4 blue0(0.0f, 0.0f, 0.5f, 1.0f); -static const LLColor4 blue7(0.0f, 0.0f, 0.5f, 1.0f); +std::vector ft_display_idx; // line of table entry for display purposes (for collapse) -static const LLColor4 green7(0.6f, 1.0f, 0.4f, 1.0f); -static const LLColor4 green8(0.4f, 1.0f, 0.6f, 1.0f); -static const LLColor4 green9(0.6f, 1.0f, 0.6f, 1.0f); +typedef LLTreeDFSIter timer_tree_iterator_t; -// green(6), blue, yellow, orange, pink(2), cyan -// red (5) magenta (4) -static struct ft_display_info ft_display_table[] = -{ - { LLFastTimer::FTM_FRAME, "Frame", &LLColor4::white, 0 }, - { LLFastTimer::FTM_MESSAGES, " System Messages", &LLColor4::grey1, 1 }, - { LLFastTimer::FTM_MOUSEHANDLER, " Mouse", &LLColor4::grey1, 0 }, - { LLFastTimer::FTM_KEYHANDLER, " Keyboard", &LLColor4::grey1, 0 }, - { LLFastTimer::FTM_SLEEP, " Sleep", &LLColor4::grey2, 0 }, - { LLFastTimer::FTM_IDLE, " Idle", &blue0, 0 }, - { LLFastTimer::FTM_PUMP, " Pump", &LLColor4::magenta2, 1 }, - { LLFastTimer::FTM_CURL, " Curl", &LLColor4::magenta3, 0 }, - { LLFastTimer::FTM_INVENTORY, " Inventory Update", &LLColor4::purple6, 1 }, - { LLFastTimer::FTM_AUTO_SELECT, " Open and Select", &LLColor4::red, 0 }, - { LLFastTimer::FTM_FILTER, " Filter", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_ARRANGE, " Arrange", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_REFRESH, " Refresh", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_SORT, " Sort", &LLColor4::red5, 0 }, - { LLFastTimer::FTM_RESET_DRAWORDER, " ResetDrawOrder", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_WORLD_UPDATE, " World Update", &LLColor4::blue1, 1 }, - { LLFastTimer::FTM_UPDATE_MOVE, " Move Objects", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_OCTREE_BALANCE, " Octree Balance", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_SIMULATE_PARTICLES, " Particle Sim", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_OBJECTLIST_UPDATE, " Object Update", &LLColor4::purple1, 1 }, - { LLFastTimer::FTM_AVATAR_UPDATE, " Avatars", &LLColor4::purple2, 0 }, - { LLFastTimer::FTM_JOINT_UPDATE, " Joints", &LLColor4::purple3, 0 }, - { LLFastTimer::FTM_ATTACHMENT_UPDATE, " Attachments", &LLColor4::purple4, 0 }, - { LLFastTimer::FTM_UPDATE_ANIMATION, " Animation", &LLColor4::purple5, 0 }, - { LLFastTimer::FTM_FLEXIBLE_UPDATE, " Flex Update", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_LOD_UPDATE, " LOD Update", &LLColor4::magenta1, 0 }, - { LLFastTimer::FTM_REGION_UPDATE, " Region Update", &LLColor4::cyan2, 0 }, - { LLFastTimer::FTM_NETWORK, " Network", &LLColor4::orange1, 1 }, - { LLFastTimer::FTM_IDLE_NETWORK, " Decode Msgs", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_PROCESS_MESSAGES, " Process Msgs", &LLColor4::orange3, 0 }, - { LLFastTimer::FTM_PROCESS_OBJECTS, " Object Updates",&LLColor4::orange4, 0 }, - { LLFastTimer::FTM_CREATE_OBJECT, " Create Obj", &LLColor4::orange5, 0 }, -// { LLFastTimer::FTM_LOAD_AVATAR, " Load Avatar", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_PROCESS_IMAGES, " Image Updates",&LLColor4::orange6, 0 }, - { LLFastTimer::FTM_PIPELINE, " Pipeline", &LLColor4::magenta4, 0 }, - { LLFastTimer::FTM_CLEANUP, " Cleanup", &LLColor4::cyan3, 0 }, - { LLFastTimer::FTM_AUDIO_UPDATE, " Audio Update", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_VFILE_WAIT, " VFile Wait", &LLColor4::cyan6, 0 }, -// { LLFastTimer::FTM_IDLE_CB, " Callbacks", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_RENDER, " Render", &green0, 1 }, - { LLFastTimer::FTM_PICK, " Pick", &LLColor4::purple, 1 }, - { LLFastTimer::FTM_HUD_EFFECTS, " HUD Effects", &LLColor4::orange1, 0 }, - { LLFastTimer::FTM_HUD_UPDATE, " HUD Update", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_UPDATE_SKY, " Sky Update", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_UPDATE_TEXTURES, " Textures", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_GEO_UPDATE, " Geo Update", &LLColor4::blue3, 1 }, - { LLFastTimer::FTM_UPDATE_PRIMITIVES, " Volumes", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_GEN_VOLUME, " Gen Volume", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_GEN_FLEX, " Flexible", &LLColor4::yellow4, 0 }, - { LLFastTimer::FTM_GEN_TRIANGLES, " Triangles", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_UPDATE_AVATAR, " Avatar", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_UPDATE_TREE, " Tree", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_UPDATE_TERRAIN, " Terrain", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_UPDATE_CLOUDS, " Clouds", &LLColor4::yellow7, 0 }, - { LLFastTimer::FTM_UPDATE_GRASS, " Grass", &LLColor4::yellow8, 0 }, - { LLFastTimer::FTM_UPDATE_WATER, " Water", &LLColor4::yellow9, 0 }, - { LLFastTimer::FTM_GEO_LIGHT, " Lighting", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_GEO_SHADOW, " Shadow", &LLColor4::black, 0 }, - { LLFastTimer::FTM_UPDATE_PARTICLES, " Particles", &LLColor4::blue5, 0 }, - { LLFastTimer::FTM_GEO_RESERVE, " Reserve", &LLColor4::blue6, 0 }, - { LLFastTimer::FTM_UPDATE_LIGHTS, " Lights", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_GEO_SKY, " Sky", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_UPDATE_WLPARAM, " Windlight Param",&LLColor4::magenta2, 0 }, - { LLFastTimer::FTM_CULL, " Object Cull", &LLColor4::blue2, 1 }, - { LLFastTimer::FTM_CULL_REBOUND, " Rebound", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_FRUSTUM_CULL, " Frustum Cull", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_OCCLUSION_READBACK, " Occlusion Read", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_IMAGE_UPDATE, " Image Update", &LLColor4::yellow4, 1 }, - { LLFastTimer::FTM_IMAGE_CREATE, " Image CreateGL",&LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_IMAGE_DECODE, " Image Decode", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_IMAGE_MARK_DIRTY, " Dirty Textures",&LLColor4::red1, 0 }, - { LLFastTimer::FTM_STATESORT, " State Sort", &LLColor4::orange1, 1 }, - { LLFastTimer::FTM_STATESORT_DRAWABLE, " Drawable", &LLColor4::orange2, 0 }, - { LLFastTimer::FTM_STATESORT_POSTSORT, " Post Sort", &LLColor4::orange3, 0 }, - { LLFastTimer::FTM_REBUILD_OCCLUSION_VB," Occlusion", &LLColor4::cyan5, 0 }, - { LLFastTimer::FTM_REBUILD_VBO, " VBO Rebuild", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_REBUILD_VOLUME_VB, " Volume", &LLColor4::blue1, 0 }, -// { LLFastTimer::FTM_REBUILD_NONE_VB, " Unknown", &LLColor4::cyan5, 0 }, -// { LLFastTimer::FTM_REBUILD_BRIDGE_VB, " Bridge", &LLColor4::blue2, 0 }, -// { LLFastTimer::FTM_REBUILD_HUD_VB, " HUD", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_REBUILD_TERRAIN_VB, " Terrain", &LLColor4::blue4, 0 }, -// { LLFastTimer::FTM_REBUILD_WATER_VB, " Water", &LLColor4::blue5, 0 }, -// { LLFastTimer::FTM_REBUILD_TREE_VB, " Tree", &LLColor4::cyan1, 0 }, - { LLFastTimer::FTM_REBUILD_PARTICLE_VB, " Particle", &LLColor4::cyan2, 0 }, -// { LLFastTimer::FTM_REBUILD_CLOUD_VB, " Cloud", &LLColor4::cyan3, 0 }, - { LLFastTimer::FTM_REBUILD_GRASS_VB, " Grass", &LLColor4::cyan4, 0 }, - { LLFastTimer::FTM_SHADOW_RENDER, " Shadow", &LLColor4::green5, 1 }, - { LLFastTimer::FTM_SHADOW_SIMPLE, " Simple", &LLColor4::yellow2, 1 }, - { LLFastTimer::FTM_SHADOW_ALPHA, " Alpha", &LLColor4::yellow6, 1 }, - { LLFastTimer::FTM_SHADOW_TERRAIN, " Terrain", &LLColor4::green6, 1 }, - { LLFastTimer::FTM_SHADOW_AVATAR, " Avatar", &LLColor4::yellow1, 1 }, - { LLFastTimer::FTM_SHADOW_TREE, " Tree", &LLColor4::yellow8, 1 }, - { LLFastTimer::FTM_RENDER_GEOMETRY, " Geometry", &LLColor4::green2, 1 }, - { LLFastTimer::FTM_POOLS, " Pools", &LLColor4::green3, 1 }, - { LLFastTimer::FTM_POOLRENDER, " RenderPool", &LLColor4::green4, 1 }, - { LLFastTimer::FTM_RENDER_TERRAIN, " Terrain", &LLColor4::green6, 0 }, - { LLFastTimer::FTM_RENDER_CHARACTERS, " Avatars", &LLColor4::yellow1, 0 }, - { LLFastTimer::FTM_RENDER_SIMPLE, " Simple", &LLColor4::yellow2, 0 }, - { LLFastTimer::FTM_RENDER_FULLBRIGHT, " Fullbright", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_RENDER_GLOW, " Glow", &LLColor4::orange1, 0 }, - { LLFastTimer::FTM_RENDER_GRASS, " Grass", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_RENDER_INVISIBLE, " Invisible", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_RENDER_SHINY, " Shiny", &LLColor4::yellow3, 0 }, - { LLFastTimer::FTM_RENDER_BUMP, " Bump", &LLColor4::yellow4, 0 }, - { LLFastTimer::FTM_RENDER_TREES, " Trees", &LLColor4::yellow8, 0 }, - { LLFastTimer::FTM_RENDER_OCCLUSION, " Occlusion", &LLColor4::red1, 0 }, - { LLFastTimer::FTM_RENDER_CLOUDS, " Clouds", &LLColor4::yellow5, 0 }, - { LLFastTimer::FTM_RENDER_ALPHA, " Alpha", &LLColor4::yellow6, 0 }, - { LLFastTimer::FTM_RENDER_HUD, " HUD", &LLColor4::yellow7, 0 }, - { LLFastTimer::FTM_RENDER_WATER, " Water", &LLColor4::yellow9, 0 }, - { LLFastTimer::FTM_RENDER_WL_SKY, " WL Sky", &LLColor4::blue3, 0 }, - { LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE," Fake VBO update", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_RENDER_BLOOM, " Bloom", &LLColor4::blue4, 0 }, - { LLFastTimer::FTM_RENDER_BLOOM_FBO, " First FBO", &LLColor4::blue, 0 }, - { LLFastTimer::FTM_RENDER_UI, " UI", &LLColor4::cyan4, 1 }, - { LLFastTimer::FTM_RENDER_TIMER, " Timers", &LLColor4::cyan5, 1, 0 }, - { LLFastTimer::FTM_RENDER_FONTS, " Fonts", &LLColor4::pink1, 0 }, - { LLFastTimer::FTM_SWAP, " Swap", &LLColor4::pink2, 0 }, - { LLFastTimer::FTM_CLIENT_COPY, " Client Copy", &LLColor4::red1, 1}, - -#if 0 || !LL_RELEASE_FOR_DOWNLOAD - { LLFastTimer::FTM_TEMP1, " Temp1", &LLColor4::red1, 0 }, - { LLFastTimer::FTM_TEMP2, " Temp2", &LLColor4::magenta1, 0 }, - { LLFastTimer::FTM_TEMP3, " Temp3", &LLColor4::red2, 0 }, - { LLFastTimer::FTM_TEMP4, " Temp4", &LLColor4::magenta2, 0 }, - { LLFastTimer::FTM_TEMP5, " Temp5", &LLColor4::red3, 0 }, - { LLFastTimer::FTM_TEMP6, " Temp6", &LLColor4::magenta3, 0 }, - { LLFastTimer::FTM_TEMP7, " Temp7", &LLColor4::red4, 0 }, - { LLFastTimer::FTM_TEMP8, " Temp8", &LLColor4::magenta4, 0 }, -#endif - - { LLFastTimer::FTM_OTHER, " Other", &red0 } -}; -static int ft_display_didcalc = 0; -static const int FTV_DISPLAY_NUM = LL_ARRAY_SIZE(ft_display_table); - -S32 ft_display_idx[FTV_DISPLAY_NUM]; // line of table entry for display purposes (for collapse) - -LLFastTimerView::LLFastTimerView(const std::string& name, const LLRect& rect) - : LLFloater(name, rect, std::string("Fast Timers")) +BOOL LLFastTimerView::sAnalyzePerformance = FALSE; + +static timer_tree_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +{ + return timer_tree_iterator_t(&id, + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), + boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); +} + +static timer_tree_iterator_t end_timer_tree() +{ + return timer_tree_iterator_t(); +} + +LLFastTimerView::LLFastTimerView(const LLRect& rect) +: LLFloater(LLSD()), + mHoverTimer(NULL) { + setRect(rect); setVisible(FALSE); mDisplayMode = 0; mAvgCountTotal = 0; mMaxCountTotal = 0; - mDisplayCenter = 1; + mDisplayCenter = ALIGN_CENTER; mDisplayCalls = 0; mDisplayHz = 0; mScrollIndex = 0; - mHoverIndex = -1; + mHoverID = NULL; mHoverBarIndex = -1; - mBarStart = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; - memset(mBarStart, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); - mBarEnd = new S32[(MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM]; - memset(mBarEnd, 0, (MAX_VISIBLE_HISTORY + 1) * FTV_DISPLAY_NUM * sizeof(S32)); - mSubtractHidden = 0; + FTV_NUM_TIMERS = LLFastTimer::NamedTimer::instanceCount(); mPrintStats = -1; - - // One-time setup - if (!ft_display_didcalc) - { - int pidx[FTV_DISPLAY_NUM]; - int pdisabled[FTV_DISPLAY_NUM]; - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - int level = 0; - const char *text = ft_display_table[i].desc; - while(text[0] == ' ') - { - text++; - level++; - } - llassert(level < FTV_DISPLAY_NUM); - ft_display_table[i].desc = text; - ft_display_table[i].level = level; - if (level > 0) - { - ft_display_table[i].parent = pidx[level-1]; - if (pdisabled[level-1]) - { - ft_display_table[i].disabled = 3; - } - } - else - { - ft_display_table[i].parent = -1; - } - ft_display_idx[i] = i; - pidx[level] = i; - pdisabled[level] = ft_display_table[i].disabled; - } - ft_display_didcalc = 1; - } } -LLFastTimerView::~LLFastTimerView() -{ - delete[] mBarStart; - delete[] mBarEnd; -} BOOL LLFastTimerView::handleRightMouseDown(S32 x, S32 y, MASK mask) { - if (mBarRect.pointInRect(x, y)) + if (mHoverTimer ) + { + // right click collapses timers + if (!mHoverTimer->getCollapsed()) + { + mHoverTimer->setCollapsed(true); + } + else if (mHoverTimer->getParent()) + { + mHoverTimer->getParent()->setCollapsed(true); + } + } + else if (mBarRect.pointInRect(x, y)) { S32 bar_idx = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); bar_idx = llclamp(bar_idx, 0, MAX_VISIBLE_HISTORY); mPrintStats = bar_idx; -// return TRUE; // for now, pass all mouse events through } return FALSE; } -S32 LLFastTimerView::getLegendIndex(S32 y) +LLFastTimer::NamedTimer* LLFastTimerView::getLegendID(S32 y) { S32 idx = (getRect().getHeight() - y) / ((S32) LLFontGL::getFontMonospace()->getLineHeight()+2) - 5; - if (idx >= 0 && idx < FTV_DISPLAY_NUM) + + if (idx >= 0 && idx < (S32)ft_display_idx.size()) { return ft_display_idx[idx]; } - return -1; + return NULL; } BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) { if (x < mBarRect.mLeft) { - S32 legend_index = getLegendIndex(y); - if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + LLFastTimer::NamedTimer* idp = getLegendID(y); + if (idp) { - S32 disabled = ft_display_table[legend_index].disabled; - if (++disabled > 2) - disabled = 0; - ft_display_table[legend_index].disabled = disabled; - S32 level = ft_display_table[legend_index].level; - - // propagate enable/disable to all children - legend_index++; - while (legend_index < FTV_DISPLAY_NUM && ft_display_table[legend_index].level > level) - { - ft_display_table[legend_index].disabled = disabled ? 3 : 0; - legend_index++; - } + idp->setCollapsed(!idp->getCollapsed()); } } + else if (mHoverTimer) + { + //left click drills down by expanding timers + mHoverTimer->setCollapsed(false); + } else if (mask & MASK_ALT) { - if (mask & MASK_SHIFT) - { - mSubtractHidden = !mSubtractHidden; - } - else if (mask & MASK_CONTROL) + if (mask & MASK_CONTROL) { mDisplayHz = !mDisplayHz; } @@ -345,8 +167,7 @@ BOOL LLFastTimerView::handleMouseDown(S32 x, S32 y, MASK mask) } else if (mask & MASK_CONTROL) { - if (++mDisplayCenter > 2) - mDisplayCenter = 0; + mDisplayCenter = (ChildAlignment)((mDisplayCenter + 1) % ALIGN_COUNT); } else { @@ -367,13 +188,15 @@ BOOL LLFastTimerView::handleMouseUp(S32 x, S32 y, MASK mask) return FALSE; } - BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) { + mHoverTimer = NULL; + mHoverID = NULL; + if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y)) { - mHoverIndex = -1; - mHoverBarIndex = MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight()); + mHoverBarIndex = llmin(LLFastTimer::getCurFrameIndex() - 1, + MAX_VISIBLE_HISTORY - ((y - mBarRect.mBottom) * (MAX_VISIBLE_HISTORY + 2) / mBarRect.getHeight())); if (mHoverBarIndex == 0) { return TRUE; @@ -382,39 +205,89 @@ BOOL LLFastTimerView::handleHover(S32 x, S32 y, MASK mask) { mHoverBarIndex = 0; } - for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + + S32 i = 0; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it, ++i) { - if (x > mBarStart[mHoverBarIndex * FTV_DISPLAY_NUM + i] && - x < mBarEnd[mHoverBarIndex * FTV_DISPLAY_NUM + i] && - ft_display_table[i].disabled <= 1) + // is mouse over bar for this timer? + if (x > mBarStart[mHoverBarIndex][i] && + x < mBarEnd[mHoverBarIndex][i]) { - mHoverIndex = i; + mHoverID = (*it); + mHoverTimer = (*it); + mToolTipRect.set(mBarStart[mHoverBarIndex][i], + mBarRect.mBottom + llround(((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex + 1)) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f))), + mBarEnd[mHoverBarIndex][i], + mBarRect.mBottom + llround((F32)(MAX_VISIBLE_HISTORY - mHoverBarIndex) * ((F32)mBarRect.getHeight() / ((F32)MAX_VISIBLE_HISTORY + 2.f)))); + } + + if ((*it)->getCollapsed()) + { + it.skipDescendants(); } } } else if (x < mBarRect.mLeft) { - S32 legend_index = getLegendIndex(y); - if (legend_index >= 0 && legend_index < FTV_DISPLAY_NUM) + LLFastTimer::NamedTimer* timer_id = getLegendID(y); + if (timer_id) { - mHoverIndex = legend_index; + mHoverID = timer_id; } } return FALSE; } + +BOOL LLFastTimerView::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + if(LLFastTimer::sPauseHistory && mBarRect.pointInRect(x, y)) + { + // tooltips for timer bars + if (mHoverTimer) + { + localRectToScreen(mToolTipRect, sticky_rect_screen); + msg = mHoverTimer->getToolTip(LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex); + return TRUE; + } + } + else + { + // tooltips for timer legend + if (x < mBarRect.mLeft) + { + LLFastTimer::NamedTimer* idp = getLegendID(y); + if (idp) + { + msg = idp->getToolTip(); + return TRUE; + } + } + + } + + return FALSE; +} + BOOL LLFastTimerView::handleScrollWheel(S32 x, S32 y, S32 clicks) { LLFastTimer::sPauseHistory = TRUE; mScrollIndex = llclamp(mScrollIndex - clicks, - 0, llmin(LLFastTimer::sLastFrameIndex, (S32)LLFastTimer::FTM_HISTORY_NUM-MAX_VISIBLE_HISTORY)); + 0, + llmin(LLFastTimer::getLastFrameIndex(), (S32)LLFastTimer::NamedTimer::HISTORY_NUM - MAX_VISIBLE_HISTORY)); return TRUE; } +static LLFastTimer::DeclareTimer FTM_RENDER_TIMER("Timers", true); + +static std::map sTimerColors; + void LLFastTimerView::draw() { - LLFastTimer t(LLFastTimer::FTM_RENDER_TIMER); + LLFastTimer t(FTM_RENDER_TIMER); std::string tdesc; @@ -433,47 +306,9 @@ void LLFastTimerView::draw() S32 texth, textw; LLPointer box_imagep = LLUI::getUIImage("rounded_square.tga"); - // Make sure all timers are accounted for - // Set 'FTM_OTHER' to unaccounted ticks last frame - { - S32 display_timer[LLFastTimer::FTM_NUM_TYPES]; - S32 hidx = LLFastTimer::sLastFrameIndex % LLFastTimer::FTM_HISTORY_NUM; - for (S32 i=0; i < LLFastTimer::FTM_NUM_TYPES; i++) - { - display_timer[i] = 0; - } - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - S32 tidx = ft_display_table[i].timer; - display_timer[tidx] = 1; - } - LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] = 0; - LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] = 0; - for (S32 tidx = 0; tidx < LLFastTimer::FTM_NUM_TYPES; tidx++) - { - U64 counts = LLFastTimer::sCountHistory[hidx][tidx]; - if (counts > 0 && display_timer[tidx] == 0) - { - LLFastTimer::sCountHistory[hidx][LLFastTimer::FTM_OTHER] += counts; - LLFastTimer::sCallHistory[hidx][LLFastTimer::FTM_OTHER] += 1; - } - } - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] = 0; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] = 0; - for (S32 h = 0; h < LLFastTimer::FTM_HISTORY_NUM; h++) - { - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCountHistory[h][LLFastTimer::FTM_OTHER]; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] += LLFastTimer::sCallHistory[h][LLFastTimer::FTM_OTHER]; - } - LLFastTimer::sCountAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; - LLFastTimer::sCallAverage[LLFastTimer::FTM_OTHER] /= LLFastTimer::FTM_HISTORY_NUM; - } - // Draw the window background - { - 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)); - } + 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)); S32 xleft = margin; S32 ytop = margin; @@ -512,148 +347,135 @@ void LLFastTimerView::draw() y -= (texth + 2); } - // Calc the total ticks - S32 histmax = llmin(LLFastTimer::sLastFrameIndex+1, MAX_VISIBLE_HISTORY); - U64 ticks_sum[LLFastTimer::FTM_HISTORY_NUM+1][FTV_DISPLAY_NUM]; - for (S32 j=-1; j= 0) - hidx = (LLFastTimer::sLastFrameIndex+j) % LLFastTimer::FTM_HISTORY_NUM; - else - hidx = -1; - - // calculate tick info by adding child ticks to parents - for (S32 i=0; i < FTV_DISPLAY_NUM; i++) - { - if (mSubtractHidden && ft_display_table[i].disabled > 1) - { - continue; - } - // Get ticks - S32 tidx = ft_display_table[i].timer; - if (hidx >= 0) - ticks_sum[j+1][i] = LLFastTimer::sCountHistory[hidx][tidx]; - else - ticks_sum[j+1][i] = LLFastTimer::sCountAverage[tidx]; - S32 pidx = ft_display_table[i].parent; - // Add ticks to parents - while (pidx >= 0) - { - ticks_sum[j+1][pidx] += ticks_sum[j+1][i]; - pidx = ft_display_table[pidx].parent; - } - } - } + S32 histmax = llmin(LLFastTimer::getLastFrameIndex()+1, MAX_VISIBLE_HISTORY); // Draw the legend - - S32 legendwidth = 0; xleft = margin; ytop = y; y -= (texth + 2); - S32 cur_line = 0; - S32 display_line[FTV_DISPLAY_NUM]; - for (S32 i=0; igetDepth(), 0.f, 3.f, 0.f, 1.f); + // lightness alternates with depth + F32 lightness = idp->getDepth() % 2 ? 0.5f : 0.6f; - int tidx = ft_display_table[i].timer; - F32 ms = 0; - S32 calls = 0; - if (mHoverBarIndex > 0 && mHoverIndex >= 0) - { - S32 hidx = (LLFastTimer::sLastFrameIndex + (mHoverBarIndex - 1) - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - S32 bidx = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex - mHoverBarIndex; - U64 ticks = ticks_sum[bidx+1][i]; // : LLFastTimer::sCountHistory[hidx][tidx]; - ms = (F32)((F64)ticks * iclock_freq); - calls = (S32)LLFastTimer::sCallHistory[hidx][tidx]; - } - else - { - U64 ticks = ticks_sum[0][i]; - ms = (F32)((F64)ticks * iclock_freq); - calls = (S32)LLFastTimer::sCallAverage[tidx]; - } - if (mDisplayCalls) - { - tdesc = llformat("%s (%d)",ft_display_table[i].desc,calls); - } - else - { - tdesc = llformat("%s [%.1f]",ft_display_table[i].desc,ms); - } - dx = (texth+4) + level*8; + LLColor4 child_color; + child_color.setHSL(hue, saturation, lightness); - LLColor4 color = disabled > 1 ? LLColor4::grey : LLColor4::white; - if (level > 0) + sTimerColors[idp] = child_color; + } + + const S32 LEGEND_WIDTH = 220; + { + LLLocalClipRect clip(LLRect(margin, y, LEGEND_WIDTH, margin)); + S32 cur_line = 0; + ft_display_idx.clear(); + std::map display_line; + for (timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != timer_tree_iterator_t(); + ++it) { - S32 line_start_y = (top + bottom) / 2; - S32 line_end_y = line_start_y + ((texth + 2) * (display_line[i] - display_line[parent])) - (texth / 2); - gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); - S32 line_x = x + (texth + 4) + ((level - 1) * 8); - gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); - if (disabled == 1) + LLFastTimer::NamedTimer* idp = (*it); + display_line[idp] = cur_line; + ft_display_idx.push_back(idp); + cur_line++; + + x = xleft; + + left = x; right = x + texth; + top = y; bottom = y - texth; + S32 scale_offset = 0; + if (idp == mHoverID) { - gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); + scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 2.f); + } + gl_rect_2d(left - scale_offset, top + scale_offset, right + scale_offset, bottom - scale_offset, sTimerColors[idp]); + + F32 ms = 0; + S32 calls = 0; + if (mHoverBarIndex > 0 && mHoverID) + { + S32 hidx = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex - mHoverBarIndex; + U64 ticks = idp->getHistoricalCount(hidx); + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)idp->getHistoricalCalls(hidx); + } + else + { + U64 ticks = idp->getCountAverage(); + ms = (F32)((F64)ticks * iclock_freq); + calls = (S32)idp->getCallAverage(); + } + + if (mDisplayCalls) + { + tdesc = llformat("%s (%d)",idp->getName().c_str(),calls); + } + else + { + tdesc = llformat("%s [%.1f]",idp->getName().c_str(),ms); + } + dx = (texth+4) + idp->getDepth()*8; + + LLColor4 color = LLColor4::white; + if (idp->getDepth() > 0) + { + S32 line_start_y = (top + bottom) / 2; + S32 line_end_y = line_start_y + ((texth + 2) * (cur_line - display_line[idp->getParent()])) - texth; + gl_line_2d(x + dx - 8, line_start_y, x + dx, line_start_y, color); + S32 line_x = x + (texth + 4) + ((idp->getDepth() - 1) * 8); + gl_line_2d(line_x, line_start_y, line_x, line_end_y, color); + if (idp->getCollapsed() && !idp->getChildren().empty()) + { + gl_line_2d(line_x+4, line_start_y-3, line_x+4, line_start_y+4, color); + } + } + + x += dx; + BOOL is_child_of_hover_item = (idp == mHoverID); + LLFastTimer::NamedTimer* next_parent = idp->getParent(); + while(!is_child_of_hover_item && next_parent) + { + is_child_of_hover_item = (mHoverID == next_parent); + next_parent = next_parent->getParent(); + } + + LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, + x, y, + color, + LLFontGL::LEFT, LLFontGL::TOP, + is_child_of_hover_item ? LLFontGL::BOLD : LLFontGL::NORMAL); + + y -= (texth + 2); + + textw = dx + LLFontGL::getFontMonospace()->getWidth(idp->getName()) + 40; + + if (idp->getCollapsed()) + { + it.skipDescendants(); } } - - x += dx; - BOOL is_child_of_hover_item = (i == mHoverIndex); - S32 next_parent = ft_display_table[i].parent; - while(!is_child_of_hover_item && next_parent >= 0) - { - is_child_of_hover_item = (mHoverIndex == next_parent); - next_parent = ft_display_table[next_parent].parent; - } - - if (is_child_of_hover_item) - { - LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::BOLD); - } - else - { - LLFontGL::getFontMonospace()->renderUTF8(tdesc, 0, x, y, color, LLFontGL::LEFT, LLFontGL::TOP); - } - y -= (texth + 2); - - textw = dx + LLFontGL::getFontMonospace()->getWidth(std::string(ft_display_table[i].desc)) + 40; - if (textw > legendwidth) - legendwidth = textw; } - for (S32 i=cur_line; igetLineHeight() + 4); mBarRect.mBottom = margin + LINE_GRAPH_HEIGHT; @@ -665,25 +487,18 @@ void LLFastTimerView::draw() barw = width - xleft - margin; // Draw the history bars - if (LLFastTimer::sLastFrameIndex >= 0) + if (LLFastTimer::getLastFrameIndex() >= 0) { + LLLocalClipRect clip(LLRect(xleft, ytop - margin, getRect().getWidth() - margin, margin)); + U64 totalticks; if (!LLFastTimer::sPauseHistory) { - U64 ticks = 0; - int hidx = (LLFastTimer::sLastFrameIndex - mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - for (S32 i=0; i= 10) { - if (mSubtractHidden && ft_display_table[i].disabled > 1) - { - continue; - } - int tidx = ft_display_table[i].timer; - ticks += LLFastTimer::sCountHistory[hidx][tidx]; - } - if (LLFastTimer::sCurFrameIndex >= 10) - { - U64 framec = LLFastTimer::sCurFrameIndex; + U64 framec = LLFastTimer::getCurFrameIndex(); U64 avg = (U64)mAvgCountTotal; mAvgCountTotal = (avg*framec + ticks) / (framec + 1); if (ticks > mMaxCountTotal) @@ -691,11 +506,13 @@ void LLFastTimerView::draw() mMaxCountTotal = ticks; } } -#if 1 + if (ticks < mAvgCountTotal/100 || ticks > mAvgCountTotal*100) - LLFastTimer::sResetHistory = 1; -#endif - if (LLFastTimer::sCurFrameIndex < 10 || LLFastTimer::sResetHistory) + { + LLFastTimer::sResetHistory = true; + } + + if (LLFastTimer::getCurFrameIndex() < 10 || LLFastTimer::sResetHistory) { mAvgCountTotal = ticks; mMaxCountTotal = ticks; @@ -716,16 +533,8 @@ void LLFastTimerView::draw() totalticks = 0; for (S32 j=0; j 1) - { - continue; - } - int tidx = ft_display_table[i].timer; - ticks += LLFastTimer::sCountHistory[j][tidx]; - } + U64 ticks = LLFastTimer::NamedTimer::getRootNamedTimer().getHistoricalCount(j); + if (ticks > totalticks) totalticks = ticks; } @@ -798,18 +607,23 @@ void LLFastTimerView::draw() gl_rect_2d(graph_rect, FALSE); } + mBarStart.clear(); + mBarEnd.clear(); + // Draw bars for each history entry // Special: -1 = show running average gGL.getTexUnit(0)->bind(box_imagep->getImage()); for (S32 j=-1; j LINE_GRAPH_HEIGHT; j++) { - int sublevel_dx[FTV_DISPLAY_NUM+1]; - int sublevel_left[FTV_DISPLAY_NUM+1]; - int sublevel_right[FTV_DISPLAY_NUM+1]; + mBarStart.push_back(std::vector()); + mBarEnd.push_back(std::vector()); + int sublevel_dx[FTV_MAX_DEPTH]; + int sublevel_left[FTV_MAX_DEPTH]; + int sublevel_right[FTV_MAX_DEPTH]; S32 tidx; if (j >= 0) { - tidx = LLFastTimer::FTM_HISTORY_NUM - j - 1 - mScrollIndex; + tidx = LLFastTimer::NamedTimer::HISTORY_NUM - j - 1 - mScrollIndex; } else { @@ -819,88 +633,75 @@ void LLFastTimerView::draw() x = xleft; // draw the bars for each stat - int xpos[FTV_DISPLAY_NUM+1]; - int deltax[FTV_DISPLAY_NUM+1]; - xpos[0] = xleft; + std::vector xpos; + std::vector deltax; + xpos.push_back(xleft); + + LLFastTimer::NamedTimer* prev_id = NULL; - for (S32 i = 0; i < FTV_DISPLAY_NUM; i++) + S32 i = 0; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it, ++i) { - if (ft_display_table[i].disabled > 1) - { - continue; - } - - F32 frac = (F32)ticks_sum[tidx+1][i] / (F32)totalticks; + LLFastTimer::NamedTimer* idp = (*it); + F32 frac = tidx == -1 + ? (F32)idp->getCountAverage() / (F32)totalticks + : (F32)idp->getHistoricalCount(tidx) / (F32)totalticks; dx = llround(frac * (F32)barw); - deltax[i] = dx; + S32 prev_delta_x = deltax.empty() ? 0 : deltax.back(); + deltax.push_back(dx); - int level = ft_display_table[i].level; - int parent = ft_display_table[i].parent; - llassert(level < FTV_DISPLAY_NUM); - llassert(parent < FTV_DISPLAY_NUM); + int level = idp->getDepth() - 1; - left = xpos[level]; - - S32 prev_idx = i - 1; - while (prev_idx > 0) + while ((S32)xpos.size() > level + 1) { - if (ft_display_table[prev_idx].disabled <= 1) - { - break; - } - prev_idx--; + xpos.pop_back(); } - S32 next_idx = i + 1; - while (next_idx < FTV_DISPLAY_NUM) - { - if (ft_display_table[next_idx].disabled <= 1) - { - break; - } - next_idx++; - } - + left = xpos.back(); + if (level == 0) - { + { sublevel_left[level] = xleft; sublevel_dx[level] = dx; sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; - } - else if (i==0 || ft_display_table[prev_idx].level < level) + } + else if (prev_id && prev_id->getDepth() < idp->getDepth()) { - // If we are the first entry at a new sublevel block, calc the - // total width of this sublevel and modify left to align block. - U64 sublevelticks = ticks_sum[tidx+1][i]; - for (S32 k=i+1; kbeginChildren(); + it != prev_id->endChildren(); + ++it) + { + sublevelticks += (tidx == -1) + ? (*it)->getCountAverage() + : (*it)->getHistoricalCount(tidx); + } + + F32 subfrac = (F32)sublevelticks / (F32)totalticks; sublevel_dx[level] = (int)(subfrac * (F32)barw + .5f); - if (mDisplayCenter == 1) // center aligned + if (mDisplayCenter == ALIGN_CENTER) { - left += (deltax[parent] - sublevel_dx[level])/2; + left += (prev_delta_x - sublevel_dx[level])/2; } - else if (mDisplayCenter == 2) // right aligned + else if (mDisplayCenter == ALIGN_RIGHT) { - left += (deltax[parent] - sublevel_dx[level]); - } + left += (prev_delta_x - sublevel_dx[level]); + } sublevel_left[level] = left; sublevel_right[level] = sublevel_left[level] + sublevel_dx[level]; } right = left + dx; - xpos[level] = right; - xpos[level+1] = left; + xpos.back() = right; + xpos.push_back(left); - mBarStart[(j + 1) * FTV_DISPLAY_NUM + i] = left; - mBarEnd[(j + 1) * FTV_DISPLAY_NUM + i] = right; + mBarStart.back().push_back(left); + mBarEnd.back().push_back(right); top = y; bottom = y - barh; @@ -908,23 +709,23 @@ void LLFastTimerView::draw() if (right > left) { //U32 rounded_edges = 0; - LLColor4 color = *ft_display_table[i].color; + LLColor4 color = sTimerColors[idp];//*ft_display_table[i].color; S32 scale_offset = 0; - BOOL is_child_of_hover_item = (i == mHoverIndex); - S32 next_parent = ft_display_table[i].parent; - while(!is_child_of_hover_item && next_parent >= 0) + BOOL is_child_of_hover_item = (idp == mHoverID); + LLFastTimer::NamedTimer* next_parent = idp->getParent(); + while(!is_child_of_hover_item && next_parent) { - is_child_of_hover_item = (mHoverIndex == next_parent); - next_parent = ft_display_table[next_parent].parent; + is_child_of_hover_item = (mHoverID == next_parent); + next_parent = next_parent->getParent(); } - if (i == mHoverIndex) + if (idp == mHoverID) { scale_offset = llfloor(sinf(mHighlightTimer.getElapsedTimeF32() * 6.f) * 3.f); //color = lerp(color, LLColor4::black, -0.4f); } - else if (mHoverIndex >= 0 && !is_child_of_hover_item) + else if (mHoverID != NULL && !is_child_of_hover_item) { color = lerp(color, LLColor4::grey, 0.8f); } @@ -935,7 +736,13 @@ void LLFastTimerView::draw() gl_segmented_rect_2d_fragment_tex(sublevel_left[level], top - level + scale_offset, sublevel_right[level], bottom + level - scale_offset, box_imagep->getTextureWidth(), box_imagep->getTextureHeight(), 16, start_fragment, end_fragment); } - + + if ((*it)->getCollapsed()) + { + it.skipDescendants(); + } + + prev_id = idp; } y -= (barh + dy); if (j < 0) @@ -970,10 +777,10 @@ void LLFastTimerView::draw() //highlight visible range { - S32 first_frame = LLFastTimer::FTM_HISTORY_NUM - mScrollIndex; + S32 first_frame = LLFastTimer::NamedTimer::HISTORY_NUM - mScrollIndex; S32 last_frame = first_frame - MAX_VISIBLE_HISTORY; - F32 frame_delta = ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1); + F32 frame_delta = ((F32) (graph_rect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1); F32 right = (F32) graph_rect.mLeft + frame_delta*first_frame; F32 left = (F32) graph_rect.mLeft + frame_delta*last_frame; @@ -996,28 +803,27 @@ void LLFastTimerView::draw() } U64 cur_max = 0; - for (S32 idx = 0; idx < FTV_DISPLAY_NUM; ++idx) + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - if (ft_display_table[idx].disabled > 1) - { //skip disabled timers - continue; - } + LLFastTimer::NamedTimer* idp = (*it); //fatten highlighted timer - if (mHoverIndex == idx) + if (mHoverID == idp) { gGL.flush(); glLineWidth(3); } - const F32 * col = ft_display_table[idx].color->mV; + const F32 * col = sTimerColors[idp].mV;// ft_display_table[idx].color->mV; F32 alpha = 1.f; - if (mHoverIndex >= 0 && - idx != mHoverIndex) + if (mHoverID != NULL && + idp != mHoverID) { //fade out non-hihglighted timers - if (ft_display_table[idx].parent != mHoverIndex) + if (idp->getParent() != mHoverID) { alpha = alpha_interp; } @@ -1025,9 +831,9 @@ void LLFastTimerView::draw() gGL.color4f(col[0], col[1], col[2], alpha); gGL.begin(LLRender::LINE_STRIP); - for (U32 j = 0; j < LLFastTimer::FTM_HISTORY_NUM; j++) + for (U32 j = 0; j < LLFastTimer::NamedTimer::HISTORY_NUM; j++) { - U64 ticks = ticks_sum[j+1][idx]; + U64 ticks = idp->getHistoricalCount(j); if (mDisplayHz) { @@ -1037,26 +843,31 @@ void LLFastTimerView::draw() } else if (mDisplayCalls) { - S32 tidx = ft_display_table[idx].timer; - S32 hidx = (LLFastTimer::sLastFrameIndex + j) % LLFastTimer::FTM_HISTORY_NUM; - ticks = (S32)LLFastTimer::sCallHistory[hidx][tidx]; + ticks = (S32)idp->getHistoricalCalls(j); } if (alpha == 1.f) - { //normalize to highlighted timer + { + //normalize to highlighted timer cur_max = llmax(cur_max, ticks); } - F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::FTM_HISTORY_NUM-1)*j; + F32 x = graph_rect.mLeft + ((F32) (graph_rect.getWidth()))/(LLFastTimer::NamedTimer::HISTORY_NUM-1)*j; F32 y = graph_rect.mBottom + (F32) graph_rect.getHeight()/max_ticks*ticks; gGL.vertex2f(x,y); } gGL.end(); - if (mHoverIndex == idx) + if (mHoverID == idp) { gGL.flush(); glLineWidth(1); } + + if (idp->getCollapsed()) + { + //skip hidden timers + it.skipDescendants(); + } } //interpolate towards new maximum @@ -1068,12 +879,16 @@ void LLFastTimerView::draw() alpha_interp = alpha_interp + (alpha_target-alpha_interp) * dt; - if (mHoverIndex >= 0) + if (mHoverID != NULL) { x = (graph_rect.mRight + graph_rect.mLeft)/2; y = graph_rect.mBottom + 8; - LLFontGL::getFontMonospace()->renderUTF8(std::string(ft_display_table[mHoverIndex].desc), 0, x, y, LLColor4::white, + LLFontGL::getFontMonospace()->renderUTF8( + mHoverID->getName(), + 0, + x, y, + LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM); } } @@ -1083,87 +898,274 @@ void LLFastTimerView::draw() if (mPrintStats >= 0) { std::string legend_stat; - S32 stat_num; - S32 first = 1; - for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + bool first = true; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - if (ft_display_table[stat_num].disabled > 1) - continue; + LLFastTimer::NamedTimer* idp = (*it); + if (!first) + { legend_stat += ", "; - first=0; - legend_stat += ft_display_table[stat_num].desc; + } + first = true; + legend_stat += idp->getName(); + + if (idp->getCollapsed()) + { + it.skipDescendants(); + } } llinfos << legend_stat << llendl; std::string timer_stat; - first = 1; - for (stat_num = 0; stat_num < FTV_DISPLAY_NUM; stat_num++) + first = true; + for(timer_tree_iterator_t it = begin_timer_tree(LLFastTimer::NamedTimer::getRootNamedTimer()); + it != end_timer_tree(); + ++it) { - S32 disabled = ft_display_table[stat_num].disabled; - if (disabled > 1) - continue; + LLFastTimer::NamedTimer* idp = (*it); + if (!first) + { timer_stat += ", "; - first=0; + } + first = false; + U64 ticks; - S32 tidx = ft_display_table[stat_num].timer; if (mPrintStats > 0) { - S32 hidx = (LLFastTimer::sLastFrameIndex+(mPrintStats-1)-mScrollIndex) % LLFastTimer::FTM_HISTORY_NUM; - ticks = disabled >= 1 ? ticks_sum[mPrintStats][stat_num] : LLFastTimer::sCountHistory[hidx][tidx]; + S32 hidx = (mPrintStats - 1) - mScrollIndex; + ticks = idp->getHistoricalCount(hidx); } else { - ticks = disabled >= 1 ? ticks_sum[0][stat_num] : LLFastTimer::sCountAverage[tidx]; + ticks = idp->getCountAverage(); } F32 ms = (F32)((F64)ticks * iclock_freq); timer_stat += llformat("%.1f",ms); + + if (idp->getCollapsed()) + { + it.skipDescendants(); + } } llinfos << timer_stat << llendl; mPrintStats = -1; } - mHoverIndex = -1; + mHoverID = NULL; mHoverBarIndex = -1; LLView::draw(); } -F64 LLFastTimerView::getTime(LLFastTimer::EFastTimerType tidx) +F64 LLFastTimerView::getTime(const std::string& name) { - // Find table index - S32 i; - for (i=0; igetCountAverage() / (F64)LLFastTimer::countsPerSecond(); } - - if (i == FTV_DISPLAY_NUM) - { - // walked off the end of ft_display_table without finding - // the desired timer type - llwarns << "Timer type " << tidx << " not known." << llendl; - return F64(0.0); - } - - S32 table_idx = i; - - // Add child ticks to parent - U64 ticks = LLFastTimer::sCountAverage[tidx]; - S32 level = ft_display_table[table_idx].level; - for (i=table_idx+1; ifirst; + + F64 time = iter->second["Time"].asReal(); + + total_time += time; + + if (time > 0.0) + { + ret[label]["TotalTime"] = ret[label]["TotalTime"].asReal() + time; + ret[label]["MaxTime"] = llmax(time, ret[label]["MaxTime"].asReal()); + + if (ret[label]["MinTime"].asReal() == 0) + { + ret[label]["MinTime"] = time; + } + else + { + ret[label]["MinTime"] = llmin(ret[label]["MinTime"].asReal(), time); + } + + LLSD::Integer samples = iter->second["Calls"].asInteger(); + + ret[label]["Samples"] = ret[label]["Samples"].asInteger() + samples; + ret[label]["MaxSamples"] = llmax(ret[label]["MaxSamples"].asInteger(), samples); + + if (ret[label]["MinSamples"].asInteger() == 0) + { + ret[label]["MinSamples"] = samples; + } + else + { + ret[label]["MinSamples"] = llmin(ret[label]["MinSamples"].asInteger(), samples); + } + } + } + total_frames++; + } + + ret["SessionTime"] = total_time; + ret["FrameCount"] = total_frames; + + return ret; + +} + +//static +void LLFastTimerView::doAnalysisDefault(std::string baseline, std::string target, std::string output) +{ + + //analyze baseline + std::ifstream base_is(baseline.c_str()); + LLSD base = analyzePerformanceLogDefault(base_is); + base_is.close(); + + //analyze current + std::ifstream target_is(target.c_str()); + LLSD current = analyzePerformanceLogDefault(target_is); + target_is.close(); + + //output comparision + std::ofstream os(output.c_str()); + + LLSD::Real session_time = current["SessionTime"].asReal(); + + os << "Label, % Change, % of Session, Cur Min, Cur Max, Cur Mean, Cur Total, Cur Samples, Base Min, Base Max, Base Mean, Base Total, Base Samples\n"; + for (LLSD::map_iterator iter = base.beginMap(); iter != base.endMap(); ++iter) + { + LLSD::String label = iter->first; + + if (current[label]["Samples"].asInteger() == 0 || + base[label]["Samples"].asInteger() == 0) + { + //cannot compare + continue; + } + LLSD::Real a = base[label]["TotalTime"].asReal() / base[label]["Samples"].asReal(); + LLSD::Real b = current[label]["TotalTime"].asReal() / base[label]["Samples"].asReal(); + + LLSD::Real diff = b-a; + + LLSD::Real perc = diff/a * 100; + + os << llformat("%s, %.2f, %.4f, %.4f, %.4f, %.4f, %.4f, %d, %.4f, %.4f, %.4f, %.4f, %d\n", + label.c_str(), + (F32) perc, + (F32) (current[label]["TotalTime"].asReal()/session_time * 100.0), + (F32) current[label]["MinTime"].asReal(), + (F32) current[label]["MaxTime"].asReal(), + (F32) b, + (F32) current[label]["TotalTime"].asReal(), + current[label]["Samples"].asInteger(), + (F32) base[label]["MinTime"].asReal(), + (F32) base[label]["MaxTime"].asReal(), + (F32) a, + (F32) base[label]["TotalTime"].asReal(), + base[label]["Samples"].asInteger()); + } + + + os.flush(); + os.close(); +} + +//------------------------- +//static +LLSD LLFastTimerView::analyzeMetricPerformanceLog(std::istream& is) +{ + LLSD ret; + LLSD cur; + + while (!is.eof() && LLSDSerialize::fromXML(cur, is)) + { + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + + LLMetricPerformanceTester* tester = LLMetricPerformanceTester::getTester(iter->second["Name"].asString()) ; + if(tester) + { + ret[label]["Name"] = iter->second["Name"] ; + + S32 num_of_strings = tester->getNumOfMetricStrings() ; + for(S32 index = 0 ; index < num_of_strings ; index++) + { + ret[label][ tester->getMetricString(index) ] = iter->second[ tester->getMetricString(index) ] ; + } + } + } + } + + return ret; +} + +//static +void LLFastTimerView::doAnalysisMetrics(std::string baseline, std::string target, std::string output) +{ + if(!LLMetricPerformanceTester::hasMetricPerformanceTesters()) + { + return ; + } + + //analyze baseline + std::ifstream base_is(baseline.c_str()); + LLSD base = analyzeMetricPerformanceLog(base_is); + base_is.close(); + + //analyze current + std::ifstream target_is(target.c_str()); + LLSD current = analyzeMetricPerformanceLog(target_is); + target_is.close(); + + //output comparision + std::ofstream os(output.c_str()); + + os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; + for(LLMetricPerformanceTester::name_tester_map_t::iterator iter = LLMetricPerformanceTester::sTesterMap.begin() ; + iter != LLMetricPerformanceTester::sTesterMap.end() ; ++iter) + { + LLMetricPerformanceTester* tester = ((LLMetricPerformanceTester*)iter->second) ; + tester->analyzePerformance(&os, &base, ¤t) ; + } + + os.flush(); + os.close(); +} + +//static +void LLFastTimerView::doAnalysis(std::string baseline, std::string target, std::string output) +{ + if(LLFastTimer::sLog) + { + doAnalysisDefault(baseline, target, output) ; + return ; + } + + if(LLFastTimer::sMetricLog) + { + doAnalysisMetrics(baseline, target, output) ; + return ; + } +} + + diff --git a/indra/newview/llfasttimerview.h b/indra/newview/llfasttimerview.h index 86fc194610..f301888984 100644 --- a/indra/newview/llfasttimerview.h +++ b/indra/newview/llfasttimerview.h @@ -34,39 +34,62 @@ #define LL_LLFASTTIMERVIEW_H #include "llfloater.h" -#include "llframetimer.h" +#include "llfasttimer.h" class LLFastTimerView : public LLFloater { public: - LLFastTimerView(const std::string& name, const LLRect& rect); - virtual ~LLFastTimerView(); + LLFastTimerView(const LLRect& rect); + + static BOOL sAnalyzePerformance; + + static void doAnalysis(std::string baseline, std::string target, std::string output); + +private: + static void doAnalysisDefault(std::string baseline, std::string target, std::string output) ; + static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; + static LLSD analyzeMetricPerformanceLog(std::istream& is) ; + static LLSD analyzePerformanceLogDefault(std::istream& is) ; + +public: 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); virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void draw(); - S32 getLegendIndex(S32 y); - F64 getTime(LLFastTimer::EFastTimerType tidx); + LLFastTimer::NamedTimer* getLegendID(S32 y); + F64 getTime(const std::string& name); private: - S32* mBarStart; - S32* mBarEnd; + typedef std::vector > bar_positions_t; + bar_positions_t mBarStart; + bar_positions_t mBarEnd; S32 mDisplayMode; - S32 mDisplayCenter; + + typedef enum child_alignment + { + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT, + ALIGN_COUNT + } ChildAlignment; + + ChildAlignment mDisplayCenter; S32 mDisplayCalls; S32 mDisplayHz; U64 mAvgCountTotal; U64 mMaxCountTotal; LLRect mBarRect; S32 mScrollIndex; - S32 mHoverIndex; + LLFastTimer::NamedTimer* mHoverID; + LLFastTimer::NamedTimer* mHoverTimer; + LLRect mToolTipRect; S32 mHoverBarIndex; LLFrameTimer mHighlightTimer; - S32 mSubtractHidden; S32 mPrintStats; }; diff --git a/indra/newview/llfavoritesbar.cpp b/indra/newview/llfavoritesbar.cpp new file mode 100644 index 0000000000..7ad60232c7 --- /dev/null +++ b/indra/newview/llfavoritesbar.cpp @@ -0,0 +1,801 @@ +/** + * @file llfavoritesbar.cpp + * @brief LLFavoritesBarCtrl class implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfavoritesbar.h" + +#include "llbutton.h" +#include "llfloaterreg.h" +#include "llfocusmgr.h" +#include "llinventory.h" +#include "lllandmarkactions.h" +#include "lltrans.h" +#include "lluictrlfactory.h" +#include "llmenugl.h" + +#include "llagent.h" +#include "llclipboard.h" +#include "llinventoryclipboard.h" +#include "llinventorybridge.h" +#include "llinventorymodel.h" +#include "llfloaterworldmap.h" +#include "lllandmarkactions.h" +#include "llsidetray.h" +#include "lltoggleablemenu.h" +#include "llviewerinventory.h" +#include "llviewermenu.h" +#include "llviewermenu.h" + +static LLDefaultChildRegistry::Register r("favorites_bar"); + +const S32 DROP_DOWN_MENU_WIDTH = 250; + +/** + * Helper for LLFavoriteLandmarkButton and LLFavoriteLandmarkMenuItem. + * Performing requests for SLURL for given Landmark ID + */ +class LLSLURLGetter +{ +public: + LLSLURLGetter() + : mLandmarkID(LLUUID::null) + , mSLURL("(Loading...)") + , mLoaded(false) {} + + void setLandmarkID(const LLUUID& id) { mLandmarkID = id; } + + const std::string& getSLURL() + { + if(!mLoaded) + requestSLURL(); + + return mSLURL; + } +private: + /** + * Requests landmark data from server. + */ + void requestSLURL() + { + if (mLandmarkID.isNull()) + return; + + LLVector3d g_pos; + if(LLLandmarkActions::getLandmarkGlobalPos(mLandmarkID, g_pos)) + { + LLLandmarkActions::getSLURLfromPosGlobal(g_pos, + boost::bind(&LLSLURLGetter::landmarkNameCallback, this, _1), false); + } + } + + void landmarkNameCallback(const std::string& name) + { + mSLURL = name; + mLoaded = true; + } + + LLUUID mLandmarkID; + std::string mSLURL; + bool mLoaded; +}; + +/** + * This class is needed to override LLButton default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in createButtons function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkButton : public LLButton +{ +public: + + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) + { + if(LLUI::sShowXUINames) + { + return LLButton::handleToolTip(x, y, msg, sticky_rect); + } + + msg = mUrlGetter.getSLURL(); + return TRUE; + } + + void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + +protected: + LLFavoriteLandmarkButton(const LLButton::Params& p) : LLButton(p) {} + friend class LLUICtrlFactory; + +private: + LLSLURLGetter mUrlGetter; +}; + +/** + * This class is needed to override LLMenuItemCallGL default handleToolTip function and + * show SLURL as button tooltip. + * *NOTE: dzaporozhan: This is a workaround. We could set tooltips for buttons + * in showDropDownMenu function but landmark data is not available when Favorites Bar is + * created. Thats why we are requesting landmark data after + */ +class LLFavoriteLandmarkMenuItem : public LLMenuItemCallGL +{ +public: + BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect) + { + if(LLUI::sShowXUINames) + { + return LLMenuItemCallGL::handleToolTip(x, y, msg, sticky_rect); + } + + msg = mUrlGetter.getSLURL(); + return TRUE; + } + + void setLandmarkID(const LLUUID& id){ mUrlGetter.setLandmarkID(id); } + +protected: + + LLFavoriteLandmarkMenuItem(const LLMenuItemCallGL::Params& p) : LLMenuItemCallGL(p) {} + friend class LLUICtrlFactory; + +private: + LLSLURLGetter mUrlGetter; +}; + + +// updateButtons's helper +struct LLFavoritesSort +{ + // Sorting by creation date and name + // TODO - made it customizible using gSavedSettings + bool operator()(const LLViewerInventoryItem* const& a, const LLViewerInventoryItem* const& b) + { + time_t first_create = a->getCreationDate(); + time_t second_create = b->getCreationDate(); + if (first_create == second_create) + { + return (LLStringUtil::compareDict(a->getName(), b->getName()) < 0); + } + else + { + return (first_create > second_create); + } + } +}; + +LLFavoritesBarCtrl::Params::Params() +: chevron_button_tool_tip("chevron_button_tool_tip") +{ +} + +LLFavoritesBarCtrl::LLFavoritesBarCtrl(const LLFavoritesBarCtrl::Params& p) +: LLUICtrl(p), + mFont(p.font.isProvided() ? p.font() : LLFontGL::getFontSansSerifSmall()), + mPopupMenuHandle(), + mInventoryItemsPopupMenuHandle(), + mChevronButtonToolTip(p.chevron_button_tool_tip) +{ + // Register callback for menus with current registrar (will be parent panel's registrar) + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Favorites.DoToSelected", + boost::bind(&LLFavoritesBarCtrl::doToSelected, this, _2)); + + // Add this if we need to selectively enable items + //LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Favorites.EnableSelected", + // boost::bind(&LLFavoritesBarCtrl::enableSelected, this, _2)); + + gInventory.addObserver(this); +} + +LLFavoritesBarCtrl::~LLFavoritesBarCtrl() +{ + gInventory.removeObserver(this); + + LLView::deleteViewByHandle(mPopupMenuHandle); + LLView::deleteViewByHandle(mInventoryItemsPopupMenuHandle); +} + +BOOL LLFavoritesBarCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + *accept = ACCEPT_NO; + + switch (cargo_type) + { + + case DAD_LANDMARK: + { + // Copy the item into the favorites folder (if it's not already there). + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + if (item->getParentUUID() == favorites_id) + { + llwarns << "Attemt to copy a favorite item into the same folder." << llendl; + break; + } + + *accept = ACCEPT_YES_COPY_SINGLE; + + if (drop) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + LLPointer(NULL)); + + llinfos << "Copied inventory item #" << item->getUUID() << " to favorites." << llendl; + } + + } + break; + default: + break; + } + + return TRUE; +} + +//virtual +void LLFavoritesBarCtrl::changed(U32 mask) +{ + if (mFavoriteFolderId.isNull()) + { + mFavoriteFolderId = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + + if (mFavoriteFolderId.notNull()) + { + gInventory.fetchDescendentsOf(mFavoriteFolderId); + } + } + else + { + updateButtons(getRect().getWidth()); + } +} + +//virtual +void LLFavoritesBarCtrl::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + updateButtons(width); + + LLUICtrl::reshape(width, height, called_from_parent); +} + +LLXMLNodePtr LLFavoritesBarCtrl::getButtonXMLNode() +{ + LLXMLNodePtr buttonXMLNode = NULL; + bool success = LLUICtrlFactory::getLayeredXMLNode("favorites_bar_button.xml", buttonXMLNode); + if (!success) + { + llwarns << "Unable to read xml file with button for Favorites Bar: favorites_bar_button.xml" << llendl; + buttonXMLNode = NULL; + } + return buttonXMLNode; +} + +void LLFavoritesBarCtrl::updateButtons(U32 bar_width) +{ + LLInventoryModel::item_array_t items; + + if (!collectFavoriteItems(items)) + { + return; + } + + static LLXMLNodePtr buttonXMLNode = getButtonXMLNode(); + if (buttonXMLNode.isNull()) + { + return; + } + + S32 buttonWidth = 120; //default value + buttonXMLNode->getAttributeS32("width", buttonWidth); + S32 buttonHGap = 2; // default value + buttonXMLNode->getAttributeS32("left", buttonHGap); + + const S32 buttonVGap = 2; + + S32 count = items.count(); + + const S32 buttonHPad = LLUI::sSettingGroups["config"]->getS32("ButtonHPad"); + const S32 chevron_button_width = mFont->getWidth(">>") + buttonHPad * 2; + + S32 buttons_space = bar_width - buttonHGap; + + S32 first_drop_down_item = count; + + // Calculating, how much buttons can fit in the bar + S32 buttons_width = 0; + for (S32 i = 0; i < count; ++i) + { + buttons_width += buttonWidth + buttonHGap; + if (buttons_width > buttons_space) + { + // There is no space for all buttons. + // Calculating the number of buttons, that are fit with chevron button + buttons_space -= chevron_button_width + buttonHGap; + while (i >= 0 && buttons_width > buttons_space) + { + buttons_width -= buttonWidth + buttonHGap; + i--; + } + first_drop_down_item = i + 1; // First item behind visible items + + break; + } + } + + bool recreate_buttons = true; + + // If inventory items are not changed up to mFirstDropDownItem, no need to recreate them + if (mFirstDropDownItem == first_drop_down_item && (mItemNamesCache.size() == count || mItemNamesCache.size() == mFirstDropDownItem)) + { + S32 i; + for (i = 0; i < mFirstDropDownItem; ++i) + { + if (mItemNamesCache.get(i) != items.get(i)->getName()) + { + break; + } + } + if (i == mFirstDropDownItem) + { + recreate_buttons = false; + } + } + + if (recreate_buttons) + { + mFirstDropDownItem = first_drop_down_item; + + mItemNamesCache.clear(); + for (S32 i = 0; i < mFirstDropDownItem; i++) + { + mItemNamesCache.put(items.get(i)->getName()); + } + + // Rebuild the buttons only + // child_list_t is a linked list, so safe to erase from the middle if we pre-incrament the iterator + for ( child_list_const_iter_t child_it = getChildList()->begin(); child_it != getChildList()->end(); ) + { + child_list_const_iter_t cur_it = child_it++; + LLView* viewp = *cur_it; + LLButton* button = dynamic_cast(viewp); + if (button) + { + removeChild(button); + delete button; + } + } + + createButtons(items, buttonXMLNode, buttonWidth, buttonHGap); + } + + // Chevron button + if (mFirstDropDownItem != count) + { + // Chevron button should stay right aligned + LLView *chevron_button = findChildView(std::string(">>"), FALSE); + if (chevron_button) + { + LLRect rect; + rect.setOriginAndSize(bar_width - chevron_button_width - buttonHGap, buttonVGap, chevron_button_width, getRect().getHeight()-buttonVGap); + chevron_button->setRect(rect); + chevron_button->setVisible(TRUE); + mChevronRect = rect; + } + else + { + static LLButton::Params default_button_params(LLUICtrlFactory::getDefaultParams()); + std::string flat_icon = "transparent.j2c"; + std::string hover_icon = default_button_params.image_unselected.name; + std::string hover_icon_selected = default_button_params.image_selected.name; + + LLButton::Params bparams; + + LLRect rect; + rect.setOriginAndSize(bar_width - chevron_button_width - buttonHGap, buttonVGap, chevron_button_width, getRect().getHeight()-buttonVGap); + + bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_BOTTOM); + bparams.image_unselected.name(flat_icon); + bparams.image_disabled.name(flat_icon); + bparams.image_selected.name(hover_icon_selected); + bparams.image_hover_selected.name(hover_icon_selected); + bparams.image_disabled_selected.name(hover_icon_selected); + bparams.image_hover_unselected.name(hover_icon); + bparams.rect (rect); + bparams.tab_stop(false); + bparams.font(mFont); + bparams.name(">>"); + bparams.tool_tip(mChevronButtonToolTip); + bparams.click_callback.function(boost::bind(&LLFavoritesBarCtrl::showDropDownMenu, this)); + + addChildInBack(LLUICtrlFactory::create (bparams)); + + mChevronRect = rect; + } + } + else + { + // Hide chevron button if all items are visible on bar + LLView *chevron_button = findChildView(std::string(">>"), FALSE); + if (chevron_button) + { + chevron_button->setVisible(FALSE); + } + } +} + + +void LLFavoritesBarCtrl::createButtons(const LLInventoryModel::item_array_t &items, const LLXMLNodePtr &buttonXMLNode, S32 buttonWidth, S32 buttonHGap) +{ + S32 curr_x = buttonHGap; + // Adding buttons + for(S32 i = mFirstDropDownItem -1; i >= 0; i--) + { + LLInventoryItem* item = items.get(i); + + LLFavoriteLandmarkButton* fav_btn = LLUICtrlFactory::defaultBuilder(buttonXMLNode, this, NULL); + if (NULL == fav_btn) + { + llwarns << "Unable to create button for landmark: " << item->getName() << llendl; + continue; + } + + fav_btn->setLandmarkID(item->getUUID()); + + // change only left and save bottom + fav_btn->setOrigin(curr_x, fav_btn->getRect().mBottom); + fav_btn->setFont(mFont); + fav_btn->setName(item->getName()); + fav_btn->setLabel(item->getName()); + fav_btn->setToolTip(item->getName()); + fav_btn->setCommitCallback(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + fav_btn->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this, item->getUUID(), _1, _2, _3,_4 )); + sendChildToBack(fav_btn); + + curr_x += buttonWidth + buttonHGap; + } +} + + +BOOL LLFavoritesBarCtrl::postBuild() +{ + // make the popup menu available + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_favorites.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!menu) + { + menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); + } + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); + mInventoryItemsPopupMenuHandle = menu->getHandle(); + + return TRUE; +} + +BOOL LLFavoritesBarCtrl::collectFavoriteItems(LLInventoryModel::item_array_t &items) +{ + if (mFavoriteFolderId.isNull()) + return FALSE; + + LLInventoryModel::cat_array_t cats; + + LLIsType is_type(LLAssetType::AT_LANDMARK); + gInventory.collectDescendentsIf(mFavoriteFolderId, cats, items, LLInventoryModel::EXCLUDE_TRASH, is_type); + + std::sort(items.begin(), items.end(), LLFavoritesSort()); + + return TRUE; +} + +void LLFavoritesBarCtrl::showDropDownMenu() +{ + if (mPopupMenuHandle.isDead()) + { + LLToggleableMenu::Params menu_p; + menu_p.name("favorites menu"); + menu_p.can_tear_off(false); + menu_p.visible(false); + menu_p.scrollable(true); + menu_p.max_scrollable_items = 10; + menu_p.preferred_width = DROP_DOWN_MENU_WIDTH; + + LLToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + + mPopupMenuHandle = menu->getHandle(); + } + + LLToggleableMenu* menu = (LLToggleableMenu*)mPopupMenuHandle.get(); + + if(menu) + { + if (!menu->toggleVisibility()) + return; + + LLInventoryModel::item_array_t items; + + if (!collectFavoriteItems(items)) + { + return; + } + + S32 count = items.count(); + + // Check it there are changed items, since last call + if (mItemNamesCache.size() == count) + { + S32 i; + for (i = mFirstDropDownItem; i < count; i++) + { + if (mItemNamesCache.get(i) != items.get(i)->getName()) + { + break; + } + } + + // Check passed, just show the menu + if (i == count) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + + menu->setButtonRect(mChevronRect, this); + + LLMenuGL::showPopup(this, menu, getRect().getWidth() - menu->getRect().getWidth(), 0); + return; + } + } + + // Add menu items to cache, if there is only names of buttons + if (mItemNamesCache.size() == mFirstDropDownItem) + { + for (S32 i = mFirstDropDownItem; i < count; i++) + { + mItemNamesCache.put(items.get(i)->getName()); + } + } + + menu->empty(); + + U32 max_width = llmin(DROP_DOWN_MENU_WIDTH, getRect().getWidth()); + U32 widest_item = 0; + + for(S32 i = mFirstDropDownItem; i < count; i++) + { + LLInventoryItem* item = items.get(i); + const std::string& item_name = item->getName(); + + LLMenuItemCallGL::Params item_params; + item_params.name(item_name); + item_params.label(item_name); + + item_params.on_click.function(boost::bind(&LLFavoritesBarCtrl::onButtonClick, this, item->getUUID())); + LLFavoriteLandmarkMenuItem *menu_item = LLUICtrlFactory::create(item_params); + menu_item->setRightMouseDownCallback(boost::bind(&LLFavoritesBarCtrl::onButtonRightClick, this,item->getUUID(),_1,_2,_3,_4)); + menu_item->setLandmarkID(item->getUUID()); + + // Check whether item name wider than menu + if (menu_item->getNominalWidth() > max_width) + { + S32 chars_total = item_name.length(); + S32 chars_fitted = 1; + menu_item->setLabel(LLStringExplicit("")); + S32 label_space = max_width - menu_item->getFont()->getWidth("...") - + menu_item->getNominalWidth(); // This returns width of menu item with empty label (pad pixels) + + while (chars_fitted < chars_total && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) + { + chars_fitted++; + } + chars_fitted--; // Rolling back one char, that doesn't fit + + menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); + } + widest_item = llmax(widest_item, menu_item->getNominalWidth()); + + menu->addChild(menu_item); + } + + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + + menu->setButtonRect(mChevronRect, this); + + LLMenuGL::showPopup(this, menu, getRect().getWidth() - max_width, 0); + + } +} + +void LLFavoritesBarCtrl::onButtonClick(LLUUID item_id) +{ + LLInventoryModel::item_array_t items; + + if (!collectFavoriteItems(items)) + { + return; + } + + // We only have one Inventory, gInventory. Some day this should be better abstracted. + LLInvFVBridgeAction::doAction(item_id,&gInventory); +} + +void LLFavoritesBarCtrl::onButtonRightClick( LLUUID item_id,LLView* fav_button,S32 x,S32 y,MASK mask) +{ + mSelectedItemID = item_id; + + LLMenuGL* menu = (LLMenuGL*)mInventoryItemsPopupMenuHandle.get(); + if (!menu) + { + return; + } + + // Release mouse capture so hover events go to the popup menu + // because this is happening during a mouse down. + gFocusMgr.setMouseCapture(NULL); + + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(fav_button, menu, x, y); +} + +void copy_slurl_to_clipboard_cb(std::string& slurl) +{ + gClipboard.copyFromString(utf8str_to_wstring(slurl)); +} + + +void LLFavoritesBarCtrl::doToSelected(const LLSD& userdata) +{ + std::string action = userdata.asString(); + llinfos << "Action = " << action << " Item = " << mSelectedItemID.asString() << llendl; + + LLViewerInventoryItem* item = gInventory.getItem(mSelectedItemID); + if (!item) + return; + + if (action == "open") + { + teleport_via_landmark(item->getAssetUUID()); + } + else if (action == "about") + { + LLSD key; + key["type"] = "landmark"; + key["id"] = mSelectedItemID; + + LLSideTray::getInstance()->showPanel("panel_places", key); + } + else if (action == "copy_slurl") + { + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero()) + { + LLLandmarkActions::getSLURLfromPosGlobal(posGlobal, copy_slurl_to_clipboard_cb); + } + } + else if (action == "show_on_map") + { + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + + LLVector3d posGlobal; + LLLandmarkActions::getLandmarkGlobalPos(mSelectedItemID, posGlobal); + + if (!posGlobal.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(posGlobal); + LLFloaterReg::showInstance("world_map", "center"); + } + } + else if (action == "cut") + { + } + else if (action == "copy") + { + LLInventoryClipboard::instance().store(mSelectedItemID); + } + else if (action == "paste") + { + pastFromClipboard(); + } + else if (action == "delete") + { + gInventory.removeItem(mSelectedItemID); + } +} + +BOOL LLFavoritesBarCtrl::isClipboardPasteable() const +{ + if (!LLInventoryClipboard::instance().hasContents()) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.get(i); + + // Can't paste folders + const LLInventoryCategory *cat = gInventory.getCategory(item_id); + if (cat) + { + return FALSE; + } + + const LLInventoryItem *item = gInventory.getItem(item_id); + if (item && LLAssetType::AT_LANDMARK != item->getType()) + { + return FALSE; + } + } + return TRUE; +} + +void LLFavoritesBarCtrl::pastFromClipboard() const +{ + LLInventoryModel* model = &gInventory; + if(model && isClipboardPasteable()) + { + LLInventoryItem* item = NULL; + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + LLUUID parent_id(mFavoriteFolderId); + for(S32 i = 0; i < count; i++) + { + item = model->getItem(objects.get(i)); + if (item) + { + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + parent_id, + std::string(), + LLPointer(NULL)); + } + } + } +} + + +// EOF diff --git a/indra/newview/llfavoritesbar.h b/indra/newview/llfavoritesbar.h new file mode 100644 index 0000000000..824b396add --- /dev/null +++ b/indra/newview/llfavoritesbar.h @@ -0,0 +1,101 @@ +/** + * @file llfavoritesbar.h + * @brief LLFavoritesBarCtrl base class + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFAVORITESBARCTRL_H +#define LL_LLFAVORITESBARCTRL_H + +#include "lluictrl.h" + +#include "llinventorymodel.h" + +class LLFavoritesBarCtrl : public LLUICtrl, public LLInventoryObserver +{ +public: + struct Params : public LLInitParam::Block + { + Optional chevron_button_tool_tip; + Params(); + }; + +protected: + LLFavoritesBarCtrl(const Params&); + friend class LLUICtrlFactory; +public: + virtual ~LLFavoritesBarCtrl(); + + /*virtual*/ BOOL postBuild(); + + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + // LLInventoryObserver observer trigger + virtual void changed(U32 mask); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +protected: + void updateButtons(U32 bar_width); + void createButtons(const LLInventoryModel::item_array_t &items, const LLXMLNodePtr &root, S32 buttonWidth, S32 buttonHGap); + LLXMLNodePtr getButtonXMLNode(); + BOOL collectFavoriteItems(LLInventoryModel::item_array_t &items); + + void onButtonClick(LLUUID id); + void onButtonRightClick(LLUUID id,LLView* button,S32 x,S32 y,MASK mask); + + void doToSelected(const LLSD& userdata); + BOOL isClipboardPasteable() const; + void pastFromClipboard() const; + + + void showDropDownMenu(); + + LLHandle mPopupMenuHandle; + LLHandle mInventoryItemsPopupMenuHandle; + + LLUUID mFavoriteFolderId; + const LLFontGL *mFont; + S32 mFirstDropDownItem; + + typedef LLDynamicArray item_names_array_t; + item_names_array_t mItemNamesCache; + + LLUUID mSelectedItemID; + LLRect mChevronRect; + + std::string mChevronButtonToolTip; +}; + + +#endif // LL_LLFAVORITESBARCTRL_H + diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 35613b7c34..2a8365b3f0 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -47,7 +47,7 @@ #include "llviewercontrol.h" #include "llworld.h" #include "lldrawpoolterrain.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llwindow.h" #include "llui.h" #include "llcontrol.h" @@ -434,7 +434,6 @@ void LLFeatureManager::applyRecommendedSettings() setGraphicsLevel(level, false); gSavedSettings.setU32("RenderQualityPerformance", level); - gSavedSettings.setBOOL("RenderCustomSettings", FALSE); // now apply the tweaks to draw distance // these are double negatives, because feature masks only work by diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 537bf0c6a4..383963a41d 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -35,6 +35,7 @@ #include "stdtypes.h" +#include "llsingleton.h" #include "llstring.h" #include diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp index 8f5882615f..028e1cc098 100644 --- a/indra/newview/llfilepicker.cpp +++ b/indra/newview/llfilepicker.cpp @@ -39,6 +39,7 @@ #include "lldir.h" #include "llframetimer.h" #include "lltrans.h" +#include "llwindow.h" // beforeDialog() #if LL_SDL #include "llwindowsdl.h" // for some X/GTK utils to help with filepickers @@ -818,6 +819,13 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter) reset(); mNavOptions.optionFlags &= ~kNavAllowMultipleFiles; + + if(filter == FFLOAD_ALL) // allow application bundles etc. to be traversed; important for DEV-16869, but generally useful + { + // mNavOptions.optionFlags |= kNavAllowOpenPackages; + mNavOptions.optionFlags |= kNavSupportPackages; + } + // Modal, so pause agent send_agent_pause(); { diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp index 9ee24d6d83..de079b7123 100644 --- a/indra/newview/llfirstuse.cpp +++ b/indra/newview/llfirstuse.cpp @@ -51,8 +51,6 @@ std::set LLFirstUse::sConfigVariables; // static void LLFirstUse::addConfigVariable(const std::string& var) { - //Don't add the warning, now that we're storing the default in the settings_default.xml file - //gSavedSettings.addWarning(var); sConfigVariables.insert(var); } @@ -63,7 +61,7 @@ void LLFirstUse::disableFirstUse() for (std::set::iterator iter = sConfigVariables.begin(); iter != sConfigVariables.end(); ++iter) { - gSavedSettings.setWarning(*iter, FALSE); + gWarningSettings.setBOOL(*iter, FALSE); } } @@ -74,7 +72,7 @@ void LLFirstUse::resetFirstUse() for (std::set::iterator iter = sConfigVariables.begin(); iter != sConfigVariables.end(); ++iter) { - gSavedSettings.setWarning(*iter, TRUE); + gWarningSettings.setBOOL(*iter, TRUE); } } @@ -82,9 +80,9 @@ void LLFirstUse::resetFirstUse() // Called whenever the viewer detects that your balance went up void LLFirstUse::useBalanceIncrease(S32 delta) { - if (gSavedSettings.getWarning("FirstBalanceIncrease")) + if (gWarningSettings.getBOOL("FirstBalanceIncrease")) { - gSavedSettings.setWarning("FirstBalanceIncrease", FALSE); + gWarningSettings.setBOOL("FirstBalanceIncrease", FALSE); LLSD args; args["AMOUNT"] = llformat("%d",delta); @@ -96,9 +94,9 @@ void LLFirstUse::useBalanceIncrease(S32 delta) // Called whenever the viewer detects your balance went down void LLFirstUse::useBalanceDecrease(S32 delta) { - if (gSavedSettings.getWarning("FirstBalanceDecrease")) + if (gWarningSettings.getBOOL("FirstBalanceDecrease")) { - gSavedSettings.setWarning("FirstBalanceDecrease", FALSE); + gWarningSettings.setBOOL("FirstBalanceDecrease", FALSE); LLSD args; args["AMOUNT"] = llformat("%d",-delta); @@ -112,9 +110,9 @@ void LLFirstUse::useSit() { // Our orientation island uses sitting to teach vehicle driving // so just never show this message. JC - //if (gSavedSettings.getWarning("FirstSit")) + //if (gWarningSettings.getBOOL("FirstSit")) //{ - // gSavedSettings.setWarning("FirstSit", FALSE); + // gWarningSettings.setBOOL("FirstSit", FALSE); // // LLNotifications::instance().add("FirstSit"); //} @@ -123,9 +121,9 @@ void LLFirstUse::useSit() // static void LLFirstUse::useMap() { - if (gSavedSettings.getWarning("FirstMap")) + if (gWarningSettings.getBOOL("FirstMap")) { - gSavedSettings.setWarning("FirstMap", FALSE); + gWarningSettings.setBOOL("FirstMap", FALSE); LLNotifications::instance().add("FirstMap"); } @@ -140,34 +138,34 @@ void LLFirstUse::useGoTo() // static void LLFirstUse::useBuild() { - if (gSavedSettings.getWarning("FirstBuild")) + if (gWarningSettings.getBOOL("FirstBuild")) { - gSavedSettings.setWarning("FirstBuild", FALSE); + gWarningSettings.setBOOL("FirstBuild", FALSE); LLNotifications::instance().add("FirstBuild"); } } - +/* // static void LLFirstUse::useLeftClickNoHit() { - if (gSavedSettings.getWarning("FirstLeftClickNoHit")) + if (gWarningSettings.getBOOL("FirstLeftClickNoHit")) { - gSavedSettings.setWarning("FirstLeftClickNoHit", FALSE); + gWarningSettings.setBOOL("FirstLeftClickNoHit", FALSE); LLNotifications::instance().add("FirstLeftClickNoHit"); } } - +*/ // static void LLFirstUse::useTeleport() { - if (gSavedSettings.getWarning("FirstTeleport")) + if (gWarningSettings.getBOOL("FirstTeleport")) { LLVector3d teleportDestination = LLTracker::getTrackedPositionGlobal(); if(teleportDestination != LLVector3d::zero) { - gSavedSettings.setWarning("FirstTeleport", FALSE); + gWarningSettings.setBOOL("FirstTeleport", FALSE); LLNotifications::instance().add("FirstTeleport"); } @@ -181,9 +179,9 @@ void LLFirstUse::useOverrideKeys() // so don't show this message until you get off OI. JC if (!gAgent.inPrelude()) { - if (gSavedSettings.getWarning("FirstOverrideKeys")) + if (gWarningSettings.getBOOL("FirstOverrideKeys")) { - gSavedSettings.setWarning("FirstOverrideKeys", FALSE); + gWarningSettings.setBOOL("FirstOverrideKeys", FALSE); LLNotifications::instance().add("FirstOverrideKeys"); } @@ -199,9 +197,9 @@ void LLFirstUse::useAttach() // static void LLFirstUse::useAppearance() { - if (gSavedSettings.getWarning("FirstAppearance")) + if (gWarningSettings.getBOOL("FirstAppearance")) { - gSavedSettings.setWarning("FirstAppearance", FALSE); + gWarningSettings.setBOOL("FirstAppearance", FALSE); LLNotifications::instance().add("FirstAppearance"); } @@ -210,9 +208,9 @@ void LLFirstUse::useAppearance() // static void LLFirstUse::useInventory() { - if (gSavedSettings.getWarning("FirstInventory")) + if (gWarningSettings.getBOOL("FirstInventory")) { - gSavedSettings.setWarning("FirstInventory", FALSE); + gWarningSettings.setBOOL("FirstInventory", FALSE); LLNotifications::instance().add("FirstInventory"); } @@ -222,9 +220,9 @@ void LLFirstUse::useInventory() // static void LLFirstUse::useSandbox() { - if (gSavedSettings.getWarning("FirstSandbox")) + if (gWarningSettings.getBOOL("FirstSandbox")) { - gSavedSettings.setWarning("FirstSandbox", FALSE); + gWarningSettings.setBOOL("FirstSandbox", FALSE); LLSD args; args["HOURS"] = llformat("%d",SANDBOX_CLEAN_FREQ); @@ -236,9 +234,9 @@ void LLFirstUse::useSandbox() // static void LLFirstUse::useFlexible() { - if (gSavedSettings.getWarning("FirstFlexible")) + if (gWarningSettings.getBOOL("FirstFlexible")) { - gSavedSettings.setWarning("FirstFlexible", FALSE); + gWarningSettings.setBOOL("FirstFlexible", FALSE); LLNotifications::instance().add("FirstFlexible"); } @@ -247,9 +245,9 @@ void LLFirstUse::useFlexible() // static void LLFirstUse::useDebugMenus() { - if (gSavedSettings.getWarning("FirstDebugMenus")) + if (gWarningSettings.getBOOL("FirstDebugMenus")) { - gSavedSettings.setWarning("FirstDebugMenus", FALSE); + gWarningSettings.setBOOL("FirstDebugMenus", FALSE); LLNotifications::instance().add("FirstDebugMenus"); } @@ -258,9 +256,9 @@ void LLFirstUse::useDebugMenus() // static void LLFirstUse::useSculptedPrim() { - if (gSavedSettings.getWarning("FirstSculptedPrim")) + if (gWarningSettings.getBOOL("FirstSculptedPrim")) { - gSavedSettings.setWarning("FirstSculptedPrim", FALSE); + gWarningSettings.setBOOL("FirstSculptedPrim", FALSE); LLNotifications::instance().add("FirstSculptedPrim"); @@ -270,9 +268,9 @@ void LLFirstUse::useSculptedPrim() // static void LLFirstUse::useMedia() { - if (gSavedSettings.getWarning("FirstMedia")) + if (gWarningSettings.getBOOL("FirstMedia")) { - gSavedSettings.setWarning("FirstMedia", FALSE); + gWarningSettings.setBOOL("FirstMedia", FALSE); LLNotifications::instance().add("FirstMedia"); } diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h index bb64cdd2c6..7b4f9f516f 100644 --- a/indra/newview/llfirstuse.h +++ b/indra/newview/llfirstuse.h @@ -95,7 +95,7 @@ public: static void useMap(); static void useGoTo(); static void useBuild(); - static void useLeftClickNoHit(); +// static void useLeftClickNoHit(); static void useTeleport(); static void useOverrideKeys(); static void useAttach(); diff --git a/indra/newview/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp index 8f2c6d538b..216bca8262 100644 --- a/indra/newview/llflexibleobject.cpp +++ b/indra/newview/llflexibleobject.cpp @@ -39,11 +39,10 @@ #include "llglheaders.h" #include "llrendersphere.h" #include "llviewerobject.h" -#include "llimagegl.h" #include "llagent.h" #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" @@ -262,6 +261,7 @@ void LLVolumeImplFlexible::onSetVolume(const LLVolumeParams &volume_params, cons // updated every time step. In the future, perhaps there could be an // optimization similar to what Havok does for objects that are stationary. //--------------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_FLEXIBLE_UPDATE("Update Flexies"); BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { if (mVO->mDrawable.isNull()) @@ -280,7 +280,7 @@ BOOL LLVolumeImplFlexible::doIdleUpdate(LLAgent &agent, LLWorld &world, const F6 parent->mDrawable->mQuietCount = 0; } - LLFastTimer ftm(LLFastTimer::FTM_FLEXIBLE_UPDATE); + LLFastTimer ftm(FTM_FLEXIBLE_UPDATE); S32 new_res = mAttributes->getSimulateLOD(); diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h index 895701da3a..811ae24df2 100644 --- a/indra/newview/llflexibleobject.h +++ b/indra/newview/llflexibleobject.h @@ -43,7 +43,6 @@ #ifndef LL_LLFLEXIBLEOBJECT_H #define LL_LLFLEXIBLEOBJECT_H -#include "llmemory.h" #include "llprimitive.h" #include "llvovolume.h" #include "llwind.h" diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 810799d27c..56c5eaa70e 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -42,7 +42,7 @@ #include "llcurl.h" #include "llimagej2c.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewertexteditor.h" #include "llviewercontrol.h" @@ -58,9 +58,10 @@ #include "lltrans.h" #include "llappviewer.h" #include "llglheaders.h" -#include "llmediamanager.h" #include "llwindow.h" +#include "llbutton.h" + #if LL_WINDOWS #include "lldxhardware.h" #endif @@ -69,59 +70,51 @@ extern LLCPUInfo gSysCPU; extern LLMemoryInfo gSysMemory; extern U32 gPacketsIn; -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - -LLFloaterAbout* LLFloaterAbout::sInstance = NULL; - static std::string get_viewer_release_notes_url(); + ///---------------------------------------------------------------------------- /// Class LLFloaterAbout ///---------------------------------------------------------------------------- // Default constructor -LLFloaterAbout::LLFloaterAbout() -: LLFloater(std::string("floater_about"), std::string("FloaterAboutRect"), LLStringUtil::null) +LLFloaterAbout::LLFloaterAbout(const LLSD& key) +: LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml"); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about.xml"); + +} - // Support for changing product name. - std::string title("About "); - title += LLAppViewer::instance()->getSecondLifeTitle(); - setTitle(title); +// Destroys the object +LLFloaterAbout::~LLFloaterAbout() +{ +} +BOOL LLFloaterAbout::postBuild() +{ + center(); LLViewerTextEditor *support_widget = getChild("support_editor", true); LLViewerTextEditor *credits_widget = getChild("credits_editor", true); - - if (!support_widget || !credits_widget) - { - return; - } - // For some reason, adding style doesn't work unless this is true. support_widget->setParseHTML(TRUE); // Text styles for release notes hyperlinks - LLStyleSP viewer_link_style(new LLStyle); - viewer_link_style->setVisible(true); - viewer_link_style->setFontName(LLStringUtil::null); - viewer_link_style->setLinkHREF(get_viewer_release_notes_url()); - viewer_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + LLStyle::Params link_style_params; + link_style_params.color.control = "HTMLLinkColor"; + link_style_params.link_href = get_viewer_release_notes_url(); // Version string - std::string version = LLAppViewer::instance()->getSecondLifeTitle() + std::string version = LLTrans::getString("APP_NAME") + llformat(" %d.%d.%d (%d) %s %s (%s)\n", LL_VERSION_MAJOR, LL_VERSION_MINOR, LL_VERSION_PATCH, LL_VIEWER_BUILD, __DATE__, __TIME__, gSavedSettings.getString("VersionChannelName").c_str()); - support_widget->appendColoredText(version, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, viewer_link_style); + support_widget->appendColoredText(version, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor")); + support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, link_style_params); std::string support; support.append("\n\n"); @@ -138,11 +131,9 @@ LLFloaterAbout::LLFloaterAbout() LLViewerRegion* region = gAgent.getRegion(); if (region) { - LLStyleSP server_link_style(new LLStyle); - server_link_style->setVisible(true); - server_link_style->setFontName(LLStringUtil::null); - server_link_style->setLinkHREF(region->getCapability("ServerReleaseNotes")); - server_link_style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); + LLStyle::Params server_link_style_params; + server_link_style_params.color.control = "HTMLLinkColor"; + server_link_style_params.link_href = region->getCapability("ServerReleaseNotes"); const LLVector3d &pos = gAgent.getPositionGlobal(); LLUIString pos_text = getString("you_are_at"); @@ -150,8 +141,8 @@ LLFloaterAbout::LLFloaterAbout() llformat("%.1f, %.1f, %.1f ", pos.mdV[VX], pos.mdV[VY], pos.mdV[VZ])); support.append(pos_text); - std::string region_text = llformat("in %s located at ", - gAgent.getRegion()->getName().c_str()); + LLUIString region_text = getString ("in_region") + " "; + region_text.setArg("[REGION]", llformat ("%s", gAgent.getRegion()->getName().c_str())); support.append(region_text); std::string buffer; @@ -164,8 +155,8 @@ LLFloaterAbout::LLFloaterAbout() support.append(gLastVersionChannel); support.append("\n"); - support_widget->appendColoredText(support, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); - support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style); + support_widget->appendColoredText(support, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor")); + support_widget->appendStyledText(LLTrans::getString("ReleaseNotes"), false, false, server_link_style_params); support = "\n\n"; } @@ -175,25 +166,26 @@ LLFloaterAbout::LLFloaterAbout() // and this info sometimes gets sent to support // CPU - support.append("CPU: "); + support.append(getString("CPU") + " "); support.append( gSysCPU.getCPUString() ); support.append("\n"); U32 memory = gSysMemory.getPhysicalMemoryKB() / 1024; // Moved hack adjustment to Windows memory size into llsys.cpp - std::string mem_text = llformat("Memory: %u MB\n", memory ); - support.append(mem_text); + LLStringUtil::format_map_t args; + args["[MEM]"] = llformat ("%u", memory); + support.append(getString("Memory", args) + "\n"); - support.append("OS Version: "); + support.append(getString("OSVersion") + " "); support.append( LLAppViewer::instance()->getOSInfo().getOSString() ); support.append("\n"); - support.append("Graphics Card Vendor: "); + support.append(getString("GraphicsCardVendor") + " "); support.append( (const char*) glGetString(GL_VENDOR) ); support.append("\n"); - support.append("Graphics Card: "); + support.append(getString("GraphicsCard") + " "); support.append( (const char*) glGetString(GL_RENDERER) ); support.append("\n"); @@ -211,98 +203,65 @@ LLFloaterAbout::LLFloaterAbout() getWindow()->setCursor(UI_CURSOR_ARROW); #endif - support.append("OpenGL Version: "); + support.append(getString("OpenGLVersion") + " "); support.append( (const char*) glGetString(GL_VERSION) ); support.append("\n"); support.append("\n"); - support.append("libcurl Version: "); + support.append(getString("LibCurlVersion") + " "); support.append( LLCurl::getVersionString() ); support.append("\n"); - support.append("J2C Decoder Version: "); + support.append(getString("J2CDecoderVersion") + " "); support.append( LLImageJ2C::getEngineInfo() ); support.append("\n"); - support.append("Audio Driver Version: "); + support.append(getString("AudioDriverVersion") + " "); bool want_fullname = true; - support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : "(none)" ); + support.append( gAudiop ? gAudiop->getDriverName(want_fullname) : getString("none") ); support.append("\n"); - LLMediaManager *mgr = LLMediaManager::getInstance(); - if (mgr) - { - LLMediaBase *media_source = mgr->createSourceFromMimeType("http", "text/html"); - if (media_source) - { - support.append("LLMozLib Version: "); - support.append(media_source->getVersion()); - support.append("\n"); - mgr->destroySource(media_source); - } - } + // TODO: Implement media plugin version query + + support.append(getString("LLQtWebkitVersion") + " "); + support.append("\n"); if (gPacketsIn > 0) { - std::string packet_loss = llformat("Packets Lost: %.0f/%.0f (%.1f%%)", - LLViewerStats::getInstance()->mPacketsLostStat.getCurrent(), - F32(gPacketsIn), - 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) ); - support.append(packet_loss); - support.append("\n"); + args["[LOST]"] = llformat ("%.0f", LLViewerStats::getInstance()->mPacketsLostStat.getCurrent()); + args["[IN]"] = llformat ("%.0f", F32(gPacketsIn)); + args["[PCT]"] = llformat ("%.1f", 100.f*LLViewerStats::getInstance()->mPacketsLostStat.getCurrent() / F32(gPacketsIn) ); + support.append(getString ("PacketsLost", args) + "\n"); } - support_widget->appendColoredText(support, FALSE, FALSE, gColors.getColor("TextFgReadOnlyColor")); + support_widget->appendColoredText(support, FALSE, FALSE, LLUIColorTable::instance().getColor("TextFgReadOnlyColor")); // Fix views support_widget->setCursorPos(0); support_widget->setEnabled(FALSE); - support_widget->setTakesFocus(TRUE); - support_widget->setHandleEditKeysDirectly(TRUE); credits_widget->setCursorPos(0); credits_widget->setEnabled(FALSE); - credits_widget->setTakesFocus(TRUE); - credits_widget->setHandleEditKeysDirectly(TRUE); - center(); - - sInstance = this; -} - -// Destroys the object -LLFloaterAbout::~LLFloaterAbout() -{ - sInstance = NULL; -} - -// static -void LLFloaterAbout::show(void*) -{ - if (!sInstance) - { - sInstance = new LLFloaterAbout(); - } - - sInstance->open(); /*Flawfinder: ignore*/ + return TRUE; } -static std::string get_viewer_release_notes_url() -{ - std::ostringstream version; - version << LL_VERSION_MAJOR << "." - << LL_VERSION_MINOR << "." - << LL_VERSION_PATCH << "." - << LL_VERSION_BUILD; + static std::string get_viewer_release_notes_url() + { + std::ostringstream version; + version << LL_VERSION_MAJOR << "." + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VERSION_BUILD; - LLSD query; - query["channel"] = gSavedSettings.getString("VersionChannelName"); - query["version"] = version.str(); + LLSD query; + query["channel"] = gSavedSettings.getString("VersionChannelName"); + query["version"] = version.str(); - std::ostringstream url; - url << RELEASE_NOTES_BASE_URL << LLURI::mapToQueryString(query); + std::ostringstream url; + url << LLTrans::getString("RELEASE_NOTES_BASE_URL") << LLURI::mapToQueryString(query); - return url.str(); -} + return url.str(); + } diff --git a/indra/newview/llfloaterabout.h b/indra/newview/llfloaterabout.h index 7564b8e41c..c15a20d549 100644 --- a/indra/newview/llfloaterabout.h +++ b/indra/newview/llfloaterabout.h @@ -36,16 +36,15 @@ #include "llfloater.h" class LLFloaterAbout -: public LLFloater + : public LLFloater { -public: - LLFloaterAbout(); + friend class LLFloaterReg; +private: + LLFloaterAbout(const LLSD& key); virtual ~LLFloaterAbout(); - static void show(void*); - -private: - static LLFloaterAbout* sInstance; +public: + /*virtual*/ BOOL postBuild(); }; diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp index 162456b8ce..dec27db74b 100644 --- a/indra/newview/llfloateranimpreview.cpp +++ b/indra/newview/llfloateranimpreview.cpp @@ -37,11 +37,13 @@ #include "llbvhloader.h" #include "lldatapacker.h" #include "lldir.h" +#include "lleconomy.h" #include "llvfile.h" #include "llapr.h" #include "llstring.h" #include "llagent.h" +#include "llanimationstates.h" #include "llbbox.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -66,8 +68,7 @@ #include "llvoavatar.h" #include "pipeline.h" #include "lluictrlfactory.h" - -S32 LLFloaterAnimPreview::sUploadAmount = 10; +#include "lltrans.h" const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; @@ -82,6 +83,40 @@ const F32 MAX_CAMERA_ZOOM = 10.f; const F32 BASE_ANIM_TIME_OFFSET = 5.f; +std::string STATUS[] = +{ + "E_ST_OK", + "E_ST_EOF", + "E_ST_NO_CONSTRAINT", + "E_ST_NO_FILE", +"E_ST_NO_HIER", +"E_ST_NO_JOINT", +"E_ST_NO_NAME", +"E_ST_NO_OFFSET", +"E_ST_NO_CHANNELS", +"E_ST_NO_ROTATION", +"E_ST_NO_AXIS", +"E_ST_NO_MOTION", +"E_ST_NO_FRAMES", +"E_ST_NO_FRAME_TIME", +"E_ST_NO_POS", +"E_ST_NO_ROT", +"E_ST_NO_XLT_FILE", +"E_ST_NO_XLT_HEADER", +"E_ST_NO_XLT_NAME", +"E_ST_NO_XLT_IGNORE", +"E_ST_NO_XLT_RELATIVE", +"E_ST_NO_XLT_OUTNAME", +"E_ST_NO_XLT_MATRIX", +"E_ST_NO_XLT_MERGECHILD", +"E_ST_NO_XLT_MERGEPARENT", +"E_ST_NO_XLT_PRIORITY", +"E_ST_NO_XLT_LOOP", +"E_ST_NO_XLT_EASEIN", +"E_ST_NO_XLT_EASEOUT", +"E_ST_NO_XLT_HAND", +"E_ST_NO_XLT_EMOTE", +}; //----------------------------------------------------------------------------- // LLFloaterAnimPreview() //----------------------------------------------------------------------------- @@ -131,9 +166,9 @@ void LLFloaterAnimPreview::setAnimCallbacks() childSetCommitCallback("priority", onCommitPriority, this); childSetCommitCallback("loop_check", onCommitLoop, this); childSetCommitCallback("loop_in_point", onCommitLoopIn, this); - childSetValidate("loop_in_point", validateLoopIn); + childSetValidate("loop_in_point", boost::bind(&LLFloaterAnimPreview::validateLoopIn, this, _1)); childSetCommitCallback("loop_out_point", onCommitLoopOut, this); - childSetValidate("loop_out_point", validateLoopOut); + childSetValidate("loop_out_point", boost::bind(&LLFloaterAnimPreview::validateLoopOut, this, _1)); childSetCommitCallback("hand_pose_combo", onCommitHandPose, this); @@ -141,9 +176,9 @@ void LLFloaterAnimPreview::setAnimCallbacks() childSetValue("emote_combo", "[None]"); childSetCommitCallback("ease_in_time", onCommitEaseIn, this); - childSetValidate("ease_in_time", validateEaseIn); + childSetValidate("ease_in_time", boost::bind(&LLFloaterAnimPreview::validateEaseIn, this, _1)); childSetCommitCallback("ease_out_time", onCommitEaseOut, this); - childSetValidate("ease_out_time", validateEaseOut); + childSetValidate("ease_out_time", boost::bind(&LLFloaterAnimPreview::validateEaseOut, this, _1)); } //----------------------------------------------------------------------------- @@ -151,7 +186,6 @@ void LLFloaterAnimPreview::setAnimCallbacks() //----------------------------------------------------------------------------- BOOL LLFloaterAnimPreview::postBuild() { - LLRect r; LLKeyframeMotion* motionp = NULL; LLBVHLoader* loaderp = NULL; @@ -162,7 +196,6 @@ BOOL LLFloaterAnimPreview::postBuild() childSetCommitCallback("name_form", onCommitName, this); - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); childSetAction("ok_btn", onBtnOK, this); setDefaultBtn(); @@ -172,63 +205,14 @@ BOOL LLFloaterAnimPreview::postBuild() PREVIEW_HPAD + PREF_BUTTON_HEIGHT + PREVIEW_HPAD); mPreviewImageRect.set(0.f, 1.f, 1.f, 0.f); - S32 y = mPreviewRect.mTop + BTN_HEIGHT; - S32 btn_left = PREVIEW_HPAD; - - r.set( btn_left, y, btn_left + 32, y - BTN_HEIGHT ); mPlayButton = getChild( "play_btn"); - if (!mPlayButton) - { - mPlayButton = new LLButton(std::string("play_btn"), LLRect(0,0,0,0)); - } - mPlayButton->setClickedCallback(onBtnPlay); - mPlayButton->setCallbackUserData(this); - - mPlayButton->setImages(std::string("button_anim_play.tga"), - std::string("button_anim_play_selected.tga")); - mPlayButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); - - mPlayButton->setScaleImage(TRUE); + mPlayButton->setClickedCallback(onBtnPlay, this); mStopButton = getChild( "stop_btn"); - if (!mStopButton) - { - mStopButton = new LLButton(std::string("stop_btn"), LLRect(0,0,0,0)); - } - mStopButton->setClickedCallback(onBtnStop); - mStopButton->setCallbackUserData(this); - - mStopButton->setImages(std::string("button_anim_stop.tga"), - std::string("button_anim_stop_selected.tga")); - mStopButton->setDisabledImages(LLStringUtil::null,LLStringUtil::null); - - mStopButton->setScaleImage(TRUE); - - r.set(r.mRight + PREVIEW_HPAD, y, getRect().getWidth() - PREVIEW_HPAD, y - BTN_HEIGHT); - //childSetCommitCallback("playback_slider", onSliderMove, this); + mStopButton->setClickedCallback(onBtnStop, this); childHide("bad_animation_text"); - //childSetCommitCallback("preview_base_anim", onCommitBaseAnim, this); - //childSetValue("preview_base_anim", "Standing"); - - //childSetCommitCallback("priority", onCommitPriority, this); - //childSetCommitCallback("loop_check", onCommitLoop, this); - //childSetCommitCallback("loop_in_point", onCommitLoopIn, this); - //childSetValidate("loop_in_point", validateLoopIn); - //childSetCommitCallback("loop_out_point", onCommitLoopOut, this); - //childSetValidate("loop_out_point", validateLoopOut); - - //childSetCommitCallback("hand_pose_combo", onCommitHandPose, this); - - //childSetCommitCallback("emote_combo", onCommitEmote, this); - //childSetValue("emote_combo", "[None]"); - - //childSetCommitCallback("ease_in_time", onCommitEaseIn, this); - //childSetValidate("ease_in_time", validateEaseIn); - //childSetCommitCallback("ease_out_time", onCommitEaseOut, this); - //childSetValidate("ease_out_time", validateEaseOut); - std::string exten = gDirUtilp->getExtension(mFilename); if (exten == "bvh") { @@ -254,7 +238,19 @@ BOOL LLFloaterAnimPreview::postBuild() { file_buffer[file_size] = '\0'; llinfos << "Loading BVH file " << mFilename << llendl; - loaderp = new LLBVHLoader(file_buffer); + ELoadStatus load_status = E_ST_OK; + S32 line_number = 0; + loaderp = new LLBVHLoader(file_buffer, load_status, line_number); + std::string status = getString(STATUS[load_status]); + + if(load_status == E_ST_NO_XLT_FILE) + { + llwarns << "NOTE: No translation table found." << llendl; + } + else + { + llwarns << "ERROR: [line: " << line_number << "] " << status << llendl; + } } infile.close() ; @@ -309,8 +305,9 @@ BOOL LLFloaterAnimPreview::postBuild() motionp->setName(childGetValue("name_form").asString()); mAnimPreview->getDummyAvatar()->startMotion(mMotionID); - childSetMinValue("playback_slider", 0.0); - childSetMaxValue("playback_slider", 1.0); + + getChild("playback_slider")->setMinValue(0.0); + getChild("playback_slider")->setMaxValue(1.0); childSetValue("loop_check", LLSD(motionp->getLoop())); childSetValue("loop_in_point", LLSD(motionp->getLoopIn() / motionp->getDuration() * 100.f)); @@ -327,7 +324,6 @@ BOOL LLFloaterAnimPreview::postBuild() } else { - delete mAnimPreview; mAnimPreview = NULL; mMotionID.setNull(); childSetValue("bad_animation_text", getString("failed_to_initialize")); @@ -347,7 +343,7 @@ BOOL LLFloaterAnimPreview::postBuild() else { LLUIString out_str = getString("failed_file_read"); - out_str.setArg("[STATUS]", loaderp->getStatus()); // *TODO:Translate + out_str.setArg("[STATUS]", getString(STATUS[loaderp->getStatus()])); childSetValue("bad_animation_text", out_str.getString()); } } @@ -369,7 +365,6 @@ BOOL LLFloaterAnimPreview::postBuild() //----------------------------------------------------------------------------- LLFloaterAnimPreview::~LLFloaterAnimPreview() { - delete mAnimPreview; mAnimPreview = NULL; setEnabled(FALSE); @@ -389,7 +384,7 @@ void LLFloaterAnimPreview::draw() { gGL.color3f(1.f, 1.f, 1.f); - gGL.getTexUnit(0)->bind(mAnimPreview->getTexture()); + gGL.getTexUnit(0)->bind(mAnimPreview); gGL.begin( LLRender::QUADS ); { @@ -736,7 +731,7 @@ void LLFloaterAnimPreview::onCommitName(LLUICtrl* ctrl, void* data) motionp->setName(previewp->childGetValue("name_form").asString()); } - LLFloaterNameDesc::doCommit(ctrl, data); + previewp->doCommit(); } //----------------------------------------------------------------------------- @@ -813,57 +808,53 @@ void LLFloaterAnimPreview::onCommitEaseOut(LLUICtrl* ctrl, void* data) //----------------------------------------------------------------------------- // validateEaseIn() //----------------------------------------------------------------------------- -BOOL LLFloaterAnimPreview::validateEaseIn(LLUICtrl* spin, void* data) +bool LLFloaterAnimPreview::validateEaseIn(const LLSD& data) { - LLFloaterAnimPreview* previewp = (LLFloaterAnimPreview*)data; - if (!previewp->getEnabled()) - return FALSE; + if (!getEnabled()) + return false; - LLVOAvatar* avatarp = previewp->mAnimPreview->getDummyAvatar(); - LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(previewp->mMotionID); + LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); + LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (!motionp->getLoop()) { - F32 new_ease_in = llclamp((F32)previewp->childGetValue("ease_in_time").asReal(), 0.f, motionp->getDuration() - motionp->getEaseOutDuration()); - previewp->childSetValue("ease_in_time", LLSD(new_ease_in)); + F32 new_ease_in = llclamp((F32)childGetValue("ease_in_time").asReal(), 0.f, motionp->getDuration() - motionp->getEaseOutDuration()); + childSetValue("ease_in_time", LLSD(new_ease_in)); } - return TRUE; + return true; } //----------------------------------------------------------------------------- // validateEaseOut() //----------------------------------------------------------------------------- -BOOL LLFloaterAnimPreview::validateEaseOut(LLUICtrl* spin, void* data) +bool LLFloaterAnimPreview::validateEaseOut(const LLSD& data) { - LLFloaterAnimPreview* previewp = (LLFloaterAnimPreview*)data; + if (!getEnabled()) + return false; - if (!previewp->getEnabled()) - return FALSE; - - LLVOAvatar* avatarp = previewp->mAnimPreview->getDummyAvatar(); - LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(previewp->mMotionID); + LLVOAvatar* avatarp = mAnimPreview->getDummyAvatar(); + LLKeyframeMotion* motionp = (LLKeyframeMotion*)avatarp->findMotion(mMotionID); if (!motionp->getLoop()) { - F32 new_ease_out = llclamp((F32)previewp->childGetValue("ease_out_time").asReal(), 0.f, motionp->getDuration() - motionp->getEaseInDuration()); - previewp->childSetValue("ease_out_time", LLSD(new_ease_out)); + F32 new_ease_out = llclamp((F32)childGetValue("ease_out_time").asReal(), 0.f, motionp->getDuration() - motionp->getEaseInDuration()); + childSetValue("ease_out_time", LLSD(new_ease_out)); } - return TRUE; + return true; } //----------------------------------------------------------------------------- // validateLoopIn() //----------------------------------------------------------------------------- -BOOL LLFloaterAnimPreview::validateLoopIn(LLUICtrl* ctrl, void* data) +bool LLFloaterAnimPreview::validateLoopIn(const LLSD& data) { - LLFloaterAnimPreview* previewp = (LLFloaterAnimPreview*)data; - if (!previewp->getEnabled()) - return FALSE; + if (!getEnabled()) + return false; - F32 loop_in_value = (F32)previewp->childGetValue("loop_in_point").asReal(); - F32 loop_out_value = (F32)previewp->childGetValue("loop_out_point").asReal(); + F32 loop_in_value = (F32)childGetValue("loop_in_point").asReal(); + F32 loop_out_value = (F32)childGetValue("loop_out_point").asReal(); if (loop_in_value < 0.f) { @@ -878,21 +869,20 @@ BOOL LLFloaterAnimPreview::validateLoopIn(LLUICtrl* ctrl, void* data) loop_in_value = loop_out_value; } - previewp->childSetValue("loop_in_point", LLSD(loop_in_value)); - return TRUE; + childSetValue("loop_in_point", LLSD(loop_in_value)); + return true; } //----------------------------------------------------------------------------- // validateLoopOut() //----------------------------------------------------------------------------- -BOOL LLFloaterAnimPreview::validateLoopOut(LLUICtrl* spin, void* data) +bool LLFloaterAnimPreview::validateLoopOut(const LLSD& data) { - LLFloaterAnimPreview* previewp = (LLFloaterAnimPreview*)data; - if (!previewp->getEnabled()) - return FALSE; + if (!getEnabled()) + return false; - F32 loop_out_value = (F32)previewp->childGetValue("loop_out_point").asReal(); - F32 loop_in_value = (F32)previewp->childGetValue("loop_in_point").asReal(); + F32 loop_out_value = (F32)childGetValue("loop_out_point").asReal(); + F32 loop_in_value = (F32)childGetValue("loop_in_point").asReal(); if (loop_out_value < 0.f) { @@ -907,8 +897,8 @@ BOOL LLFloaterAnimPreview::validateLoopOut(LLUICtrl* spin, void* data) loop_out_value = loop_in_value; } - previewp->childSetValue("loop_out_point", LLSD(loop_out_value)); - return TRUE; + childSetValue("loop_out_point", LLSD(loop_out_value)); + return true; } @@ -992,7 +982,7 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata) std::string name = floaterp->childGetValue("name_form").asString(); std::string desc = floaterp->childGetValue("description_form").asString(); LLAssetStorage::LLStoreAssetCallback callback = NULL; - S32 expected_upload_cost = sUploadAmount; + S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); void *userdata = NULL; upload_new_resource(floaterp->mTransactionID, // tid LLAssetType::AT_ANIMATION, @@ -1018,13 +1008,13 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata) LLKeyframeDataCache::removeKeyframeData(floaterp->mMotionID); } - floaterp->close(false); + floaterp->closeFloater(false); } //----------------------------------------------------------------------------- // LLPreviewAnimation //----------------------------------------------------------------------------- -LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) +LLPreviewAnimation::LLPreviewAnimation(S32 width, S32 height) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) { mNeedsUpdate = TRUE; mCameraDistance = PREVIEW_CAMERA_DISTANCE; @@ -1070,7 +1060,7 @@ BOOL LLPreviewAnimation::render() glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); - glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f); + glOrtho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); @@ -1080,7 +1070,7 @@ BOOL LLPreviewAnimation::render() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - gl_rect_2d_simple( mWidth, mHeight ); + gl_rect_2d_simple( mFullWidth, mFullHeight ); glMatrixMode(GL_PROJECTION); gGL.popMatrix(); @@ -1102,7 +1092,7 @@ BOOL LLPreviewAnimation::render() target_pos + (mCameraOffset * av_rot) ); // point of interest LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE); + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); mCameraRelPos = LLViewerCamera::getInstance()->getOrigin() - avatarp->mHeadp->getWorldPosition(); diff --git a/indra/newview/llfloateranimpreview.h b/indra/newview/llfloateranimpreview.h index 639c9277cd..f1c4a6b0d0 100644 --- a/indra/newview/llfloateranimpreview.h +++ b/indra/newview/llfloateranimpreview.h @@ -41,12 +41,14 @@ class LLVOAvatar; class LLViewerJointMesh; -class LLPreviewAnimation : public LLDynamicTexture +class LLPreviewAnimation : public LLViewerDynamicTexture { -public: - LLPreviewAnimation(S32 width, S32 height); +protected: virtual ~LLPreviewAnimation(); +public: + LLPreviewAnimation(S32 width, S32 height); + BOOL render(); void requestUpdate(); void rotate(F32 yaw_radians, F32 pitch_radians); @@ -86,22 +88,21 @@ public: static void onBtnPlay(void*); static void onBtnStop(void*); - static void setUploadAmount(S32 amount) { sUploadAmount = amount; } static void onSliderMove(LLUICtrl*, void*); static void onCommitBaseAnim(LLUICtrl*, void*); static void onCommitLoop(LLUICtrl*, void*); static void onCommitLoopIn(LLUICtrl*, void*); static void onCommitLoopOut(LLUICtrl*, void*); - static BOOL validateLoopIn(LLUICtrl*, void*); - static BOOL validateLoopOut(LLUICtrl*, void*); + bool validateLoopIn(const LLSD& data); + bool validateLoopOut(const LLSD& data); static void onCommitName(LLUICtrl*, void*); static void onCommitHandPose(LLUICtrl*, void*); static void onCommitEmote(LLUICtrl*, void*); static void onCommitPriority(LLUICtrl*, void*); static void onCommitEaseIn(LLUICtrl*, void*); static void onCommitEaseOut(LLUICtrl*, void*); - static BOOL validateEaseIn(LLUICtrl*, void*); - static BOOL validateEaseOut(LLUICtrl*, void*); + bool validateEaseIn(const LLSD& data); + bool validateEaseOut(const LLSD& data); static void onBtnOK(void*); static void onSaveComplete(const LLUUID& asset_uuid, LLAssetType::EType type, @@ -114,7 +115,7 @@ protected: void draw(); void resetMotion(); - LLPreviewAnimation* mAnimPreview; + LLPointer< LLPreviewAnimation > mAnimPreview; S32 mLastMouseX; S32 mLastMouseY; LLButton* mPlayButton; @@ -127,8 +128,6 @@ protected: LLAnimPauseRequest mPauseRequest; std::map mIDList; - - static S32 sUploadAmount; }; #endif // LL_LLFLOATERANIMPREVIEW_H diff --git a/indra/newview/llfloaterauction.cpp b/indra/newview/llfloaterauction.cpp index 747431fb19..da2a4d9d93 100644 --- a/indra/newview/llfloaterauction.cpp +++ b/indra/newview/llfloaterauction.cpp @@ -41,12 +41,13 @@ #include "llparcel.h" #include "llvfile.h" #include "llvfs.h" +#include "llwindow.h" #include "llagent.h" #include "llcombobox.h" #include "llnotify.h" #include "llsavedsettingsglue.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "lluictrlfactory.h" @@ -69,41 +70,29 @@ void auction_tga_upload_done(const LLUUID& asset_id, /// Class llfloaterauction ///---------------------------------------------------------------------------- -LLFloaterAuction* LLFloaterAuction::sInstance = NULL; - // Default constructor -LLFloaterAuction::LLFloaterAuction() : - LLFloater(std::string("floater_auction")), +LLFloaterAuction::LLFloaterAuction(const LLSD& key) + : LLFloater(key), mParcelID(-1) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_auction.xml"); - - childSetValue("fence_check", - LLSD( gSavedSettings.getBOOL("AuctionShowFence") ) ); - childSetCommitCallback("fence_check", - LLSavedSettingsGlue::setBOOL, (void*)"AuctionShowFence"); - - childSetAction("snapshot_btn", onClickSnapshot, this); - childSetAction("ok_btn", onClickOK, this); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_auction.xml"); + mCommitCallbackRegistrar.add("ClickSnapshot", boost::bind(&LLFloaterAuction::onClickSnapshot, this)); + mCommitCallbackRegistrar.add("ClickOK", boost::bind(&LLFloaterAuction::onClickOK, this)); } // Destroys the object LLFloaterAuction::~LLFloaterAuction() { - sInstance = NULL; } -// static -void LLFloaterAuction::show() +BOOL LLFloaterAuction::postBuild() { - if(!sInstance) - { - sInstance = new LLFloaterAuction(); - sInstance->center(); - sInstance->setFocus(TRUE); - } - sInstance->initialize(); - sInstance->open(); /*Flawfinder: ignore*/ + return TRUE; +} + +void LLFloaterAuction::onOpen(const LLSD& key) +{ + initialize(); } void LLFloaterAuction::initialize() @@ -197,7 +186,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) tga->encode(raw); LLVFile::writeFile(tga->getData(), tga->getDataSize(), gVFS, self->mImageID, LLAssetType::AT_IMAGE_TGA); - raw->biasedScaleToPowerOfTwo(LLViewerImage::MAX_IMAGE_SIZE_DEFAULT); + raw->biasedScaleToPowerOfTwo(LLViewerTexture::MAX_IMAGE_SIZE_DEFAULT); llinfos << "Writing J2C..." << llendl; @@ -205,7 +194,7 @@ void LLFloaterAuction::onClickSnapshot(void* data) j2c->encode(raw, 0.0f); LLVFile::writeFile(j2c->getData(), j2c->getDataSize(), gVFS, self->mImageID, LLAssetType::AT_TEXTURE); - self->mImage = new LLImageGL((LLImageRaw*)raw, FALSE); + self->mImage = LLViewerTextureManager::getLocalTexture((LLImageRaw*)raw, FALSE); gGL.getTexUnit(0)->bind(self->mImage); self->mImage->setAddressMode(LLTexUnit::TAM_CLAMP); } @@ -259,7 +248,7 @@ void LLFloaterAuction::onClickOK(void* data) self->mImage = NULL; self->mParcelID = -1; self->mParcelHost.invalidate(); - self->close(); + self->closeFloater(); } diff --git a/indra/newview/llfloaterauction.h b/indra/newview/llfloaterauction.h index e13bce01e1..1acc08057c 100644 --- a/indra/newview/llfloaterauction.h +++ b/indra/newview/llfloaterauction.h @@ -36,8 +36,8 @@ #include "llfloater.h" #include "lluuid.h" -#include "llmemory.h" -#include "llviewerimage.h" +#include "llpointer.h" +#include "llviewertexture.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFloaterAuction @@ -48,28 +48,27 @@ class LLParcelSelection; class LLFloaterAuction : public LLFloater { + friend class LLFloaterReg; public: // LLFloater interface - /*virtual*/ void onClose(bool app_quitting) { setVisible(FALSE); } + /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void draw(); - // LLFloaterAuction interface - static void show(); - private: - LLFloaterAuction(); + + LLFloaterAuction(const LLSD& key); ~LLFloaterAuction(); + void initialize(); static void onClickSnapshot(void* data); static void onClickOK(void* data); - static LLFloaterAuction* sInstance; - + /*virtual*/ BOOL postBuild(); private: LLTransactionID mTransactionID; LLAssetID mImageID; - LLPointer mImage; + LLPointer mImage; LLSafeHandle mParcelp; S32 mParcelID; LLHost mParcelHost; diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp index e382fefece..91b9bcfe72 100644 --- a/indra/newview/llfloateravatarpicker.cpp +++ b/indra/newview/llfloateravatarpicker.cpp @@ -33,85 +33,74 @@ #include "llfloateravatarpicker.h" -#include "message.h" - +// Viewer includes #include "llagent.h" -#include "llbutton.h" #include "llfocusmgr.h" -#include "llinventoryview.h" +#include "llfloaterreg.h" +#include "llfloaterinventory.h" +#include "llfoldervieweventlistener.h" #include "llinventorymodel.h" -#include "lllineeditor.h" -#include "llscrolllistctrl.h" -#include "lltextbox.h" -#include "lluictrlfactory.h" #include "llviewercontrol.h" #include "llworld.h" -const S32 MIN_WIDTH = 200; -const S32 MIN_HEIGHT = 340; -const LLRect FLOATER_RECT(0, 380, 240, 0); -const std::string FLOATER_TITLE = "Choose Resident"; - -// static -LLFloaterAvatarPicker* LLFloaterAvatarPicker::sInstance = NULL; - +// Linden libraries +#include "llbutton.h" +#include "lllineeditor.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" +#include "lltabcontainer.h" +#include "lltextbox.h" +#include "lluictrlfactory.h" +#include "message.h" LLFloaterAvatarPicker* LLFloaterAvatarPicker::show(callback_t callback, void* userdata, BOOL allow_multiple, BOOL closeOnSelect) { - // TODO: This class should not be a singleton as it's used in multiple places - // and therefore can't be used simultaneously. -MG - if (!sInstance) - { - sInstance = new LLFloaterAvatarPicker(); - sInstance->mCallback = callback; - sInstance->mCallbackUserdata = userdata; - sInstance->mCloseOnSelect = FALSE; - - sInstance->open(); /* Flawfinder: ignore */ - sInstance->center(); - sInstance->setAllowMultiple(allow_multiple); - } - else - { - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->mCallback = callback; - sInstance->mCallbackUserdata = userdata; - sInstance->setAllowMultiple(allow_multiple); - } + // *TODO: Use a key to allow this not to be an effective singleton + LLFloaterAvatarPicker* floater = LLFloaterReg::showTypedInstance("avatar_picker"); - sInstance->mNearMeListComplete = FALSE; - sInstance->mCloseOnSelect = closeOnSelect; - return sInstance; + floater->mCallback = callback; + floater->mCallbackUserdata = userdata; + floater->setAllowMultiple(allow_multiple); + floater->mNearMeListComplete = FALSE; + floater->mCloseOnSelect = closeOnSelect; + + return floater; } // Default constructor -LLFloaterAvatarPicker::LLFloaterAvatarPicker() : - LLFloater(std::string("avatarpicker"), FLOATER_RECT, FLOATER_TITLE, TRUE, MIN_WIDTH, MIN_HEIGHT), +LLFloaterAvatarPicker::LLFloaterAvatarPicker(const LLSD& key) + : LLFloater(key), mResultsReturned(FALSE), mCallback(NULL), - mCallbackUserdata(NULL) + mCallbackUserdata(NULL), + mNearMeListComplete(FALSE), + mCloseOnSelect(FALSE) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_picker.xml", NULL); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_picker.xml"); } BOOL LLFloaterAvatarPicker::postBuild() { - childSetKeystrokeCallback("Edit", editKeystroke, this); + getChild("Edit")->setKeystrokeCallback(editKeystroke, this); childSetAction("Find", onBtnFind, this); childDisable("Find"); childSetAction("Refresh", onBtnRefresh, this); childSetCommitCallback("near_me_range", onRangeAdjust, this); - - childSetDoubleClickCallback("SearchResults", onBtnSelect); - childSetDoubleClickCallback("NearMe", onBtnSelect); + + LLScrollListCtrl* searchresults = getChild("SearchResults"); + searchresults->setDoubleClickCallback(onBtnSelect, this); childSetCommitCallback("SearchResults", onList, this); - childSetCommitCallback("NearMe", onList, this); childDisable("SearchResults"); - + + LLScrollListCtrl* nearme = getChild("NearMe"); + nearme->setDoubleClickCallback(onBtnSelect, this); + childSetCommitCallback("NearMe", onList, this); + childSetAction("Select", onBtnSelect, this); childDisable("Select"); @@ -126,41 +115,34 @@ BOOL LLFloaterAvatarPicker::postBuild() search_panel->setDefaultBtn("Find"); } - getChild("SearchResults")->addCommentText(getString("no_results")); + getChild("SearchResults")->setCommentText(getString("no_results")); LLInventoryPanel* inventory_panel = getChild("InventoryPanel"); inventory_panel->setFilterTypes(0x1 << LLInventoryType::IT_CALLINGCARD); inventory_panel->setFollowsAll(); inventory_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); inventory_panel->openDefaultFolderForType(LLAssetType::AT_CALLINGCARD); - inventory_panel->setSelectCallback(LLFloaterAvatarPicker::onCallingCardSelectionChange, this); - - childSetTabChangeCallback("ResidentChooserTabs", "SearchPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "CallingCardsPanel", onTabChanged, this); - childSetTabChangeCallback("ResidentChooserTabs", "NearMePanel", onTabChanged, this); + inventory_panel->setSelectCallback(boost::bind(&LLFloaterAvatarPicker::doCallingCardSelectionChange, this, _1, _2)); + + getChild("ResidentChooserTabs")->setCommitCallback( + boost::bind(&LLFloaterAvatarPicker::onTabChanged, this)); setAllowMultiple(FALSE); - + + center(); + return TRUE; } -void LLFloaterAvatarPicker::onTabChanged(void* userdata, bool from_click) +void LLFloaterAvatarPicker::onTabChanged() { - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if (!self) - { - return; - } - - self->childSetEnabled("Select", self->visibleItemsSelected()); + childSetEnabled("Select", visibleItemsSelected()); } // Destroys the object LLFloaterAvatarPicker::~LLFloaterAvatarPicker() { gFocusMgr.releaseFocusIfNeeded( this ); - - sInstance = NULL; } void LLFloaterAvatarPicker::onBtnFind(void* userdata) @@ -216,7 +198,7 @@ void LLFloaterAvatarPicker::onBtnSelect(void* userdata) if(self->mCloseOnSelect) { self->mCloseOnSelect = FALSE; - self->close(); + self->closeFloater(); } } @@ -229,14 +211,14 @@ void LLFloaterAvatarPicker::onBtnRefresh(void* userdata) } self->getChild("NearMe")->deleteAllItems(); - self->getChild("NearMe")->addCommentText(self->getString("searching")); + self->getChild("NearMe")->setCommentText(self->getString("searching")); self->mNearMeListComplete = FALSE; } void LLFloaterAvatarPicker::onBtnClose(void* userdata) { LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)userdata; - if(self) self->close(); + if(self) self->closeFloater(); } void LLFloaterAvatarPicker::onRangeAdjust(LLUICtrl* source, void* data) @@ -253,18 +235,8 @@ void LLFloaterAvatarPicker::onList(LLUICtrl* ctrl, void* userdata) } } -// static callback for inventory picker (select from calling cards) -void LLFloaterAvatarPicker::onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data) -{ - LLFloaterAvatarPicker* self = (LLFloaterAvatarPicker*)data; - if (self) - { - self->doCallingCardSelectionChange( items, user_action, data ); - } -} - // Callback for inventory picker (select from calling cards) -void LLFloaterAvatarPicker::doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data) +void LLFloaterAvatarPicker::doCallingCardSelectionChange(const std::deque &items, BOOL user_action) { bool panel_active = (childGetVisibleTab("ResidentChooserTabs") == getChild("CallingCardsPanel")); @@ -330,7 +302,7 @@ void LLFloaterAvatarPicker::populateNearMe() { childDisable("NearMe"); childDisable("Select"); - near_me_scroller->addCommentText(getString("no_one_near")); + near_me_scroller->setCommentText(getString("no_one_near")); } else { @@ -394,7 +366,7 @@ void LLFloaterAvatarPicker::find() gAgent.sendReliableMessage(); getChild("SearchResults")->deleteAllItems(); - getChild("SearchResults")->addCommentText(getString("searching")); + getChild("SearchResults")->setCommentText(getString("searching")); childSetEnabled("Select", FALSE); mResultsReturned = FALSE; @@ -421,23 +393,21 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* // Not for us if (agent_id != gAgent.getID()) return; - - // Dialog already closed - LLFloaterAvatarPicker *self = sInstance; - if (!self) return; + + LLFloaterAvatarPicker* floater = LLFloaterReg::findTypedInstance("avatar_picker"); // these are not results from our last request - if (query_id != self->mQueryID) + if (query_id != floater->mQueryID) { return; } - LLScrollListCtrl* search_results = self->getChild("SearchResults"); + LLScrollListCtrl* search_results = floater->getChild("SearchResults"); // clear "Searching" label on first results search_results->deleteAllItems(); - self->mResultsReturned = TRUE; + floater->mResultsReturned = TRUE; BOOL found_one = FALSE; S32 num_new_rows = msg->getNumberOfBlocks("Data"); @@ -451,10 +421,10 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* if (avatar_id.isNull()) { LLStringUtil::format_map_t map; - map["[TEXT]"] = self->childGetText("Edit"); - avatar_name = self->getString("not_found", map); + map["[TEXT]"] = floater->childGetText("Edit"); + avatar_name = floater->getString("not_found", map); search_results->setEnabled(FALSE); - self->childDisable("Select"); + floater->childDisable("Select"); } else { @@ -470,9 +440,9 @@ void LLFloaterAvatarPicker::processAvatarPickerReply(LLMessageSystem* msg, void* if (found_one) { - self->childEnable("Select"); + floater->childEnable("Select"); search_results->selectFirstItem(); - self->onList(search_results, self); + floater->onList(search_results, floater); search_results->setFocus(TRUE); } } @@ -501,7 +471,7 @@ BOOL LLFloaterAvatarPicker::handleKeyHere(KEY key, MASK mask) } else if (key == KEY_ESCAPE && mask == MASK_NONE) { - close(); + closeFloater(); return TRUE; } diff --git a/indra/newview/llfloateravatarpicker.h b/indra/newview/llfloateravatarpicker.h index 56bc387bce..63896bef9f 100644 --- a/indra/newview/llfloateravatarpicker.h +++ b/indra/newview/llfloateravatarpicker.h @@ -48,6 +48,10 @@ public: void* userdata, BOOL allow_multiple = FALSE, BOOL closeOnSelect = FALSE); + + LLFloaterAvatarPicker(const LLSD& key); + virtual ~LLFloaterAvatarPicker(); + virtual BOOL postBuild(); static void processAvatarPickerReply(class LLMessageSystem* msg, void**); @@ -62,10 +66,9 @@ private: static void onRangeAdjust(LLUICtrl* source, void* data); static void onBtnClose(void* userdata); static void onList(class LLUICtrl* ctrl, void* userdata); - static void onTabChanged(void* userdata, bool from_click); + void onTabChanged(); - void doCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); - static void onCallingCardSelectionChange(const std::deque &items, BOOL user_action, void* data); + void doCallingCardSelectionChange(const std::deque &items, BOOL user_action); void populateNearMe(); BOOL visibleItemsSelected() const; // Returns true if any items in the current tab are selected. @@ -85,12 +88,6 @@ private: void (*mCallback)(const std::vector& name, const std::vector& id, void* userdata); void* mCallbackUserdata; - - static LLFloaterAvatarPicker* sInstance; - - // do not call these directly - LLFloaterAvatarPicker(); - virtual ~LLFloaterAvatarPicker(); }; #endif diff --git a/indra/newview/llfloateravatartextures.cpp b/indra/newview/llfloateravatartextures.cpp index e81b5d7fce..3976e25ba4 100644 --- a/indra/newview/llfloateravatartextures.cpp +++ b/indra/newview/llfloateravatartextures.cpp @@ -42,32 +42,17 @@ using namespace LLVOAvatarDefines; -LLFloaterAvatarTextures::LLFloaterAvatarTextures(const LLUUID& id) : - LLFloater(std::string("avatar_texture_debug")), - mID(id) +LLFloaterAvatarTextures::LLFloaterAvatarTextures(const LLSD& id) + : LLFloater(id), + mID(id.asUUID()) { +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_avatar_textures.xml"); } LLFloaterAvatarTextures::~LLFloaterAvatarTextures() { } -LLFloaterAvatarTextures* LLFloaterAvatarTextures::show(const LLUUID &id) -{ - - LLFloaterAvatarTextures* floaterp = new LLFloaterAvatarTextures(id); - - // Builds and adds to gFloaterView - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_avatar_textures.xml"); - - gFloaterView->addChild(floaterp); - floaterp->open(); /*Flawfinder: ignore*/ - - gFloaterView->adjustToFitScreen(floaterp, FALSE); - - return floaterp; -} - BOOL LLFloaterAvatarTextures::postBuild() { for (U32 i=0; i < TEX_NUM_INDICES; i++) @@ -142,7 +127,7 @@ void LLFloaterAvatarTextures::refresh() } else { - setTitle(mTitle + ": INVALID AVATAR (" + mID.asString() + ")"); + setTitle(mTitle + ": " + getString("InvalidAvatar") + " (" + mID.asString() + ")"); } } diff --git a/indra/newview/llfloateravatartextures.h b/indra/newview/llfloateravatartextures.h index 4138edeb4d..e27484d26f 100644 --- a/indra/newview/llfloateravatartextures.h +++ b/indra/newview/llfloateravatartextures.h @@ -43,7 +43,7 @@ class LLTextureCtrl; class LLFloaterAvatarTextures : public LLFloater { public: - LLFloaterAvatarTextures(const LLUUID& id); + LLFloaterAvatarTextures(const LLSD& id); virtual ~LLFloaterAvatarTextures(); /*virtual*/ BOOL postBuild(); @@ -51,8 +51,6 @@ public: void refresh(); - static LLFloaterAvatarTextures* show(const LLUUID& id); - private: static void onClickDump(void*); diff --git a/indra/newview/llfloaterbeacons.cpp b/indra/newview/llfloaterbeacons.cpp index 5476b35dc8..13a7888f60 100644 --- a/indra/newview/llfloaterbeacons.cpp +++ b/indra/newview/llfloaterbeacons.cpp @@ -40,8 +40,9 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed) +: LLFloater(seed) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_beacons.xml"); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_beacons.xml"); // Initialize pipeline states from saved settings. // OK to do at floater constructor time because beacons do not display unless the floater is open @@ -55,44 +56,21 @@ LLFloaterBeacons::LLFloaterBeacons(const LLSD& seed) LLPipeline::setRenderParticleBeacons( gSavedSettings.getBOOL("particlesbeacon")); LLPipeline::setRenderHighlights( gSavedSettings.getBOOL("renderhighlights")); LLPipeline::setRenderBeacons( gSavedSettings.getBOOL("renderbeacons")); + mCommitCallbackRegistrar.add("Beacons.UICheck", boost::bind(&LLFloaterBeacons::onClickUICheck, this,_1)); } BOOL LLFloaterBeacons::postBuild() { - childSetCommitCallback("touch_only", onClickUICheck, this); - childSetCommitCallback("scripted", onClickUICheck, this); - childSetCommitCallback("physical", onClickUICheck, this); - childSetCommitCallback("sounds", onClickUICheck, this); - childSetCommitCallback("particles", onClickUICheck, this); - childSetCommitCallback("highlights", onClickUICheck, this); - childSetCommitCallback("beacons", onClickUICheck, this); return TRUE; } -// Needed to make the floater visibility toggle the beacons. -// Too bad we can't just add control_name="BeaconAlwaysOn" to the XML. -void LLFloaterBeacons::open() -{ - LLFloater::open(); - gSavedSettings.setBOOL( "BeaconAlwaysOn", TRUE); -} -void LLFloaterBeacons::close(bool app_quitting) -{ - LLFloater::close(app_quitting); - if(!app_quitting) - { - gSavedSettings.setBOOL( "BeaconAlwaysOn", FALSE); - } -} - // Callback attached to each check box control to both affect their main purpose // and to implement the couple screwy interdependency rules that some have. -//static -void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) + +void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl) { LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl; std::string name = check->getName(); - LLFloaterBeacons* view = (LLFloaterBeacons*)data; if( name == "touch_only") { LLPipeline::toggleRenderScriptedTouchBeacons(NULL); @@ -102,8 +80,8 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) LLPipeline::getRenderScriptedBeacons(NULL) ) { LLPipeline::setRenderScriptedBeacons(FALSE); - view->getChild("scripted")->setControlValue(LLSD(FALSE)); - view->getChild("touch_only")->setControlValue(LLSD(TRUE)); // just to be sure it's in sync with llpipeline + getChild("scripted")->setControlValue(LLSD(FALSE)); + getChild("touch_only")->setControlValue(LLSD(TRUE)); // just to be sure it's in sync with llpipeline } } else if(name == "scripted") @@ -115,8 +93,8 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) LLPipeline::getRenderScriptedBeacons(NULL) ) { LLPipeline::setRenderScriptedTouchBeacons(FALSE); - view->getChild("touch_only")->setControlValue(LLSD(FALSE)); - view->getChild("scripted")->setControlValue(LLSD(TRUE)); // just to be sure it's in sync with llpipeline + getChild("touch_only")->setControlValue(LLSD(FALSE)); + getChild("scripted")->setControlValue(LLSD(TRUE)); // just to be sure it's in sync with llpipeline } } else if(name == "physical") LLPipeline::setRenderPhysicalBeacons(check->get()); @@ -131,8 +109,8 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) !LLPipeline::getRenderHighlights(NULL) ) { LLPipeline::setRenderBeacons(TRUE); - view->getChild("beacons")->setControlValue(LLSD(TRUE)); - view->getChild("highlights")->setControlValue(LLSD(FALSE)); // just to be sure it's in sync with llpipeline + getChild("beacons")->setControlValue(LLSD(TRUE)); + getChild("highlights")->setControlValue(LLSD(FALSE)); // just to be sure it's in sync with llpipeline } } else if(name == "beacons") @@ -144,8 +122,8 @@ void LLFloaterBeacons::onClickUICheck(LLUICtrl *ctrl, void* data) !LLPipeline::getRenderHighlights(NULL) ) { LLPipeline::setRenderHighlights(TRUE); - view->getChild("highlights")->setControlValue(LLSD(TRUE)); - view->getChild("beacons")->setControlValue(LLSD(FALSE)); // just to be sure it's in sync with llpipeline + getChild("highlights")->setControlValue(LLSD(TRUE)); + getChild("beacons")->setControlValue(LLSD(FALSE)); // just to be sure it's in sync with llpipeline } } } diff --git a/indra/newview/llfloaterbeacons.h b/indra/newview/llfloaterbeacons.h index c12bdd7261..c175cb3ef4 100644 --- a/indra/newview/llfloaterbeacons.h +++ b/indra/newview/llfloaterbeacons.h @@ -36,22 +36,20 @@ #include "llfloater.h" -class LLFloaterBeacons : public LLFloater, public LLFloaterSingleton +class LLFloaterBeacons : public LLFloater { - friend class LLUISingleton >; + friend class LLFloaterReg; public: + /*virtual*/ BOOL postBuild(); // Needed to make the floater visibility toggle the beacons. // Too bad we can't just add control_name="BeaconAlwaysOn" to the XML. - /*virtual*/ void open(); - /*virtual*/ void close(bool app_quitting); + void onClickUICheck(LLUICtrl *ctrl); private: LLFloaterBeacons(const LLSD& seed); - - static void onClickUICheck(LLUICtrl *ctrl, void* data); }; #endif diff --git a/indra/newview/llfloaterbuildoptions.cpp b/indra/newview/llfloaterbuildoptions.cpp index 3cd35db19c..30e9428df9 100644 --- a/indra/newview/llfloaterbuildoptions.cpp +++ b/indra/newview/llfloaterbuildoptions.cpp @@ -40,58 +40,16 @@ #include "llfloaterbuildoptions.h" #include "lluictrlfactory.h" -// library includes -#include "llfontgl.h" -#include "llcheckboxctrl.h" -#include "llspinctrl.h" -#include "llsliderctrl.h" - -// newview includes -#include "llresmgr.h" -#include "llviewercontrol.h" - -// -// Globals -// -LLFloaterBuildOptions *LLFloaterBuildOptions::sInstance = NULL; - // // Methods // -LLFloaterBuildOptions::LLFloaterBuildOptions( ) -: LLFloater(std::string("build options floater")) +LLFloaterBuildOptions::LLFloaterBuildOptions(const LLSD& key) + : LLFloater(key) { - sInstance = this; + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_build_options.xml"); } LLFloaterBuildOptions::~LLFloaterBuildOptions() { - sInstance = NULL; } -// static -void LLFloaterBuildOptions::show(void*) -{ - if (sInstance) - { - sInstance->open(); /*Flawfinder: ignore*/ - } - else - { - LLFloaterBuildOptions* floater = new LLFloaterBuildOptions(); - - LLUICtrlFactory::getInstance()->buildFloater(floater, "floater_build_options.xml"); - floater->open(); /*Flawfinder: ignore*/ - } -} - -LLFloaterBuildOptions* LLFloaterBuildOptions::getInstance() -{ - return sInstance; -} - -// static -BOOL LLFloaterBuildOptions::visible(void*) -{ - return (sInstance != NULL); -} diff --git a/indra/newview/llfloaterbuildoptions.h b/indra/newview/llfloaterbuildoptions.h index e030b063d9..43cbb201c2 100644 --- a/indra/newview/llfloaterbuildoptions.h +++ b/indra/newview/llfloaterbuildoptions.h @@ -42,19 +42,12 @@ class LLFloaterBuildOptions -: public LLFloater + : public LLFloater { -protected: - LLFloaterBuildOptions(); + friend class LLFloaterReg; +private: + LLFloaterBuildOptions(const LLSD& key); ~LLFloaterBuildOptions(); - -public: - static void show(void*); - static LLFloaterBuildOptions* getInstance(); - static BOOL visible(void*); - -protected: - static LLFloaterBuildOptions* sInstance; }; #endif diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index d4e1e98125..a73ebf4e06 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -52,21 +52,29 @@ #include "llviewerstats.h" #include "lluictrlfactory.h" #include "llselectmgr.h" +#include "llcheckboxctrl.h" #include "roles_constants.h" // for GP_OBJECT_MANIPULATE -LLFloaterBulkPermission::LLFloaterBulkPermission(const LLSD& seed) : mDone(FALSE) +LLFloaterBulkPermission::LLFloaterBulkPermission(const LLSD& seed) +: LLFloater(seed), + mDone(FALSE) { mID.generate(); - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_bulk_perms.xml"); - childSetEnabled("next_owner_transfer", gSavedSettings.getBOOL("BulkChangeNextOwnerCopy")); - childSetAction("help", onHelpBtn, this); - childSetAction("apply", onApplyBtn, this); - childSetAction("close", onCloseBtn, this); - childSetAction("check_all", onCheckAll, this); - childSetAction("check_none", onUncheckAll, this); - childSetCommitCallback("next_owner_copy", &onCommitCopy, this); +// LLUICtrlFactory::getInstance()->buildFloater(this,"floater_bulk_perms.xml"); + mCommitCallbackRegistrar.add("BulkPermission.Apply", boost::bind(&LLFloaterBulkPermission::onApplyBtn, this)); + mCommitCallbackRegistrar.add("BulkPermission.Close", boost::bind(&LLFloaterBulkPermission::onCloseBtn, this)); + mCommitCallbackRegistrar.add("BulkPermission.CheckAll", boost::bind(&LLFloaterBulkPermission::onCheckAll, this)); + mCommitCallbackRegistrar.add("BulkPermission.UncheckAll", boost::bind(&LLFloaterBulkPermission::onUncheckAll, this)); + mCommitCallbackRegistrar.add("BulkPermission.CommitCopy", boost::bind(&LLFloaterBulkPermission::onCommitCopy, this)); +} + +BOOL LLFloaterBulkPermission::postBuild() +{ +// childSetAction("help", onHelpBtn, this); // this is not in use + + return TRUE; } void LLFloaterBulkPermission::doApply() @@ -93,7 +101,7 @@ void LLFloaterBulkPermission::doApply() LLSelectMgr::getInstance()->getSelection()->applyToNodes(&gatherer); if(mObjectIDs.empty()) { - list->addCommentText(getString("nothing_to_modify_text")); + list->setCommentText(getString("nothing_to_modify_text")); } else { @@ -144,41 +152,39 @@ void LLFloaterBulkPermission::inventoryChanged(LLViewerObject* viewer_object, } } -void LLFloaterBulkPermission::onApplyBtn(void* user_data) +void LLFloaterBulkPermission::onApplyBtn() { - LLFloaterBulkPermission* self = static_cast(user_data); - self->doApply(); + doApply(); } -void LLFloaterBulkPermission::onHelpBtn(void* user_data) -{ - LLNotifications::instance().add("HelpBulkPermission"); -} +// angela -- this is not in use +//void LLFloaterBulkPermission::onHelpBtn(void* user_data) +//{ +// LLNotifications::instance().add("HelpBulkPermission"); +//} -void LLFloaterBulkPermission::onCloseBtn(void* user_data) +void LLFloaterBulkPermission::onCloseBtn() { - LLFloaterBulkPermission* self = static_cast(user_data); - self->onClose(false); + closeFloater(); } //static -void LLFloaterBulkPermission::onCommitCopy(LLUICtrl* ctrl, void* data) +void LLFloaterBulkPermission::onCommitCopy() { - LLFloaterBulkPermission* self = static_cast(data); // Implements fair use BOOL copyable = gSavedSettings.getBOOL("BulkChangeNextOwnerCopy"); if(!copyable) { gSavedSettings.setBOOL("BulkChangeNextOwnerTransfer", TRUE); } - LLCheckBoxCtrl* xfer = self->getChild("next_owner_transfer"); + LLCheckBoxCtrl* xfer =getChild("next_owner_transfer"); xfer->setEnabled(copyable); } BOOL LLFloaterBulkPermission::start() { // note: number of top-level objects to modify is mObjectIDs.count(). - getChild("queue output")->addCommentText(getString("start_text")); + getChild("queue output")->setCommentText(getString("start_text")); return nextObject(); } @@ -201,7 +207,7 @@ BOOL LLFloaterBulkPermission::nextObject() if(isDone() && !mDone) { - getChild("queue output")->addCommentText(getString("done_text")); + getChild("queue output")->setCommentText(getString("done_text")); mDone = TRUE; } return successful_start; @@ -244,7 +250,6 @@ void LLFloaterBulkPermission::doCheckUncheckAll(BOOL check) gSavedSettings.setBOOL("BulkChangeIncludeBodyParts" , check); gSavedSettings.setBOOL("BulkChangeIncludeClothing" , check); gSavedSettings.setBOOL("BulkChangeIncludeGestures" , check); - gSavedSettings.setBOOL("BulkChangeIncludeLandmarks" , check); gSavedSettings.setBOOL("BulkChangeIncludeNotecards" , check); gSavedSettings.setBOOL("BulkChangeIncludeObjects" , check); gSavedSettings.setBOOL("BulkChangeIncludeScripts" , check); @@ -267,7 +272,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, Invent ( asstype == LLAssetType::AT_BODYPART && gSavedSettings.getBOOL("BulkChangeIncludeBodyParts" )) || ( asstype == LLAssetType::AT_CLOTHING && gSavedSettings.getBOOL("BulkChangeIncludeClothing" )) || ( asstype == LLAssetType::AT_GESTURE && gSavedSettings.getBOOL("BulkChangeIncludeGestures" )) || - ( asstype == LLAssetType::AT_LANDMARK && gSavedSettings.getBOOL("BulkChangeIncludeLandmarks" )) || + ( asstype == LLAssetType::AT_FAVORITE && gSavedSettings.getBOOL("BulkChangeIncludeFavourite" )) || ( asstype == LLAssetType::AT_NOTECARD && gSavedSettings.getBOOL("BulkChangeIncludeNotecards" )) || ( asstype == LLAssetType::AT_OBJECT && gSavedSettings.getBOOL("BulkChangeIncludeObjects" )) || ( asstype == LLAssetType::AT_LSL_TEXT && gSavedSettings.getBOOL("BulkChangeIncludeScripts" )) || @@ -317,7 +322,7 @@ void LLFloaterBulkPermission::handleInventory(LLViewerObject* viewer_obj, Invent status_text.setArg("[STATUS]", ""); } - list->addCommentText(status_text.getString()); + list->setCommentText(status_text.getString()); //TODO if we are an object inside an object we should check a recuse flag and if set //open the inventory of the object and recurse - Michelle2 Zenovka diff --git a/indra/newview/llfloaterbulkpermission.h b/indra/newview/llfloaterbulkpermission.h index a26b5b4f79..c34e4413cc 100644 --- a/indra/newview/llfloaterbulkpermission.h +++ b/indra/newview/llfloaterbulkpermission.h @@ -46,13 +46,16 @@ #include "llviewerinventory.h" -class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener, public LLFloaterSingleton +class LLFloaterBulkPermission : public LLFloater, public LLVOInventoryListener { + friend class LLFloaterReg; public: - LLFloaterBulkPermission(const LLSD& seed); + BOOL postBuild(); private: + + LLFloaterBulkPermission(const LLSD& seed); virtual ~LLFloaterBulkPermission() {} BOOL start(); // returns TRUE if the queue has started, otherwise FALSE. @@ -76,12 +79,12 @@ private: U8 key, bool is_new); - static void onHelpBtn(void* user_data); - static void onCloseBtn(void* user_data); - static void onApplyBtn(void* user_data); - static void onCommitCopy(LLUICtrl* ctrl, void* data); - static void onCheckAll( void* user_data) { ((LLFloaterBulkPermission*)user_data)->doCheckUncheckAll(TRUE); } - static void onUncheckAll(void* user_data) { ((LLFloaterBulkPermission*)user_data)->doCheckUncheckAll(FALSE); } +// static void onHelpBtn(void* user_data); + void onCloseBtn(); + void onApplyBtn(); + void onCommitCopy(); + void onCheckAll() { doCheckUncheckAll(TRUE); } + void onUncheckAll() { doCheckUncheckAll(FALSE); } // returns true if this is done BOOL isDone() const { return (mCurrentObjectID.isNull() || (mObjectIDs.count() == 0)); } diff --git a/indra/newview/llfloaterbump.cpp b/indra/newview/llfloaterbump.cpp index 96e51c2fa2..8b64f913e0 100644 --- a/indra/newview/llfloaterbump.cpp +++ b/indra/newview/llfloaterbump.cpp @@ -37,55 +37,41 @@ #include "llscrolllistctrl.h" +#include "llsd.h" #include "lluictrlfactory.h" #include "llviewermessage.h" #include "llappviewer.h" // gPacificDaylightTime -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- -LLFloaterBump* LLFloaterBump::sInstance = NULL; - ///---------------------------------------------------------------------------- /// Class LLFloaterBump ///---------------------------------------------------------------------------- +extern BOOL gNoRender; // Default constructor -LLFloaterBump::LLFloaterBump() -: LLFloater() +LLFloaterBump::LLFloaterBump(const LLSD& key) +: LLFloater(key) { - sInstance = this; - - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_bumps.xml"); + if(gNoRender) return; + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_bumps.xml"); } // Destroys the object LLFloaterBump::~LLFloaterBump() { - sInstance = NULL; } -// static -void LLFloaterBump::show(void *contents) +// virtual +void LLFloaterBump::onOpen(const LLSD& key) { - if (gNoRender) - { + LLScrollListCtrl* list = getChild("bump_list"); + if (!list) return; - } - - if (!sInstance) - { - sInstance = new LLFloaterBump(); - } - - LLScrollListCtrl* list = sInstance->getChild("bump_list"); - if (!list) return; list->deleteAllItems(); if (gMeanCollisionList.empty()) { - std::string none_detected = sInstance->getString("none_detected"); + std::string none_detected = getString("none_detected"); LLSD row; row["columns"][0]["value"] = none_detected; row["columns"][0]["font"] = "SansSerifBold"; @@ -97,33 +83,23 @@ void LLFloaterBump::show(void *contents) iter != gMeanCollisionList.end(); ++iter) { LLMeanCollisionData *mcd = *iter; - LLFloaterBump::add(list, mcd); + add(list, mcd); } } - - sInstance->open(); /*Flawfinder: ignore*/ } void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd) { - if (!sInstance) - { - new LLFloaterBump(); - } - if (mcd->mFirstName.empty() || list->getItemCount() >= 20) { return; } - // There's only one internal tm buffer. - struct tm* timep; - - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - timep = utc_to_pacific_time(mcd->mTime, gPacificDaylightTime); - - std::string time = llformat("[%d:%02d]", timep->tm_hour, timep->tm_min); + std::string timeStr = getString ("timeStr"); + LLSD substitution; + + substitution["datetime"] = (S32) mcd->mTime; + LLStringUtil::format (timeStr, substitution); std::string action; switch(mcd->mType) @@ -150,8 +126,8 @@ void LLFloaterBump::add(LLScrollListCtrl* list, LLMeanCollisionData* mcd) } // All above action strings are in XML file - LLUIString text = sInstance->getString(action); - text.setArg("[TIME]", time); + LLUIString text = getString(action); + text.setArg("[TIME]", timeStr); text.setArg("[FIRST]", mcd->mFirstName); text.setArg("[LAST]", mcd->mLastName); diff --git a/indra/newview/llfloaterbump.h b/indra/newview/llfloaterbump.h index eb15671d41..1f2cb6d6ab 100644 --- a/indra/newview/llfloaterbump.h +++ b/indra/newview/llfloaterbump.h @@ -42,16 +42,17 @@ class LLScrollListCtrl; class LLFloaterBump : public LLFloater { -public: - static void show(void *); + friend class LLFloaterReg; +protected: + void add(LLScrollListCtrl* list, LLMeanCollisionData *mcd); -private: - LLFloaterBump(); - virtual ~LLFloaterBump(); - static void add(LLScrollListCtrl* list, LLMeanCollisionData *mcd); +public: + /*virtual*/ void onOpen(const LLSD& key); private: - static LLFloaterBump* sInstance; + + LLFloaterBump(const LLSD& key); + virtual ~LLFloaterBump(); }; #endif diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index a33cabc749..a7aaf71ef6 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -43,32 +43,43 @@ #include "llagent.h" // for agent id #include "llalertdialog.h" #include "llinventorymodel.h" // for gInventory -#include "llinventoryview.h" // for get_item_icon +#include "llfloaterreg.h" +#include "llfloaterinventory.h" // for get_item_icon #include "llselectmgr.h" #include "llscrolllistctrl.h" #include "llviewerobject.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" +#include "lltrans.h" -LLFloaterBuy* LLFloaterBuy::sInstance = NULL; - -LLFloaterBuy::LLFloaterBuy() -: LLFloater(std::string("floater_buy_object"), std::string("FloaterBuyRect"), LLStringUtil::null) +LLFloaterBuy::LLFloaterBuy(const LLSD& key) +: LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_object.xml"); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_object.xml"); +} +BOOL LLFloaterBuy::postBuild() +{ childDisable("object_list"); childDisable("item_list"); - childSetAction("cancel_btn", onClickCancel, this); - childSetAction("buy_btn", onClickBuy, this); + getChild("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuy::onClickCancel, this)); + getChild("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuy::onClickBuy, this)); setDefaultBtn("cancel_btn"); // to avoid accidental buy (SL-43130) + + // Always center the dialog. User can change the size, + // but purchases are important and should be center screen. + // This also avoids problems where the user resizes the application window + // mid-session and the saved rect is off-center. + center(); + + return TRUE; } LLFloaterBuy::~LLFloaterBuy() { - sInstance = NULL; + mObjectSelection = NULL; } void LLFloaterBuy::reset() @@ -90,47 +101,34 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) LLNotifications::instance().add("BuyOneObjectOnly"); return; } - - // Create a new instance only if one doesn't exist - if (sInstance) - { - // Clean up the lists... - sInstance->reset(); - } - else - { - sInstance = new LLFloaterBuy(); - } - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->setFocus(TRUE); - sInstance->mSaleInfo = sale_info; - sInstance->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - - // Always center the dialog. User can change the size, - // but purchases are important and should be center screen. - // This also avoids problems where the user resizes the application window - // mid-session and the saved rect is off-center. - sInstance->center(); - + LLFloaterBuy* floater = LLFloaterReg::showTypedInstance("buy_object"); + if (!floater) + return; + + // Clean up the lists... + floater->reset(); + floater->mSaleInfo = sale_info; + floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); + LLSelectNode* node = selection->getFirstRootNode(); if (!node) return; - + // Set title based on sale type LLUIString title; switch (sale_info.getSaleType()) { case LLSaleInfo::FS_ORIGINAL: - title = sInstance->getString("title_buy_text"); + title = floater->getString("title_buy_text"); break; case LLSaleInfo::FS_COPY: default: - title = sInstance->getString("title_buy_copy_text"); + title = floater->getString("title_buy_copy_text"); break; } title.setArg("[NAME]", node->mName); - sInstance->setTitle(title); + floater->setTitle(title); LLUUID owner_id; std::string owner_name; @@ -141,7 +139,7 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) return; } - LLCtrlListInterface *object_list = sInstance->childGetListInterface("object_list"); + LLCtrlListInterface *object_list = floater->childGetListInterface("object_list"); if (!object_list) { return; @@ -166,15 +164,15 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) std::string text = node->mName; if (!(next_owner_mask & PERM_COPY)) { - text.append(sInstance->getString("no_copy_text")); + text.append(floater->getString("no_copy_text")); } if (!(next_owner_mask & PERM_MODIFY)) { - text.append(sInstance->getString("no_modify_text")); + text.append(floater->getString("no_modify_text")); } if (!(next_owner_mask & PERM_TRANSFER)) { - text.append(sInstance->getString("no_transfer_text")); + text.append(floater->getString("no_transfer_text")); } row["columns"][1]["column"] = "text"; @@ -184,15 +182,15 @@ void LLFloaterBuy::show(const LLSaleInfo& sale_info) // Add after columns added so appropriate heights are correct. object_list->addElement(row); - sInstance->childSetTextArg("buy_text", "[AMOUNT]", llformat("%d", sale_info.getSalePrice())); - sInstance->childSetTextArg("buy_text", "[NAME]", owner_name); + floater->childSetTextArg("buy_text", "[AMOUNT]", llformat("%d", sale_info.getSalePrice())); + floater->childSetTextArg("buy_text", "[NAME]", owner_name); // Must do this after the floater is created, because // sometimes the inventory is already there and // the callback is called immediately. LLViewerObject* obj = selection->getFirstRootObject(); - sInstance->registerVOInventoryListener(obj,NULL); - sInstance->requestVOInventory(); + floater->registerVOInventoryListener(obj,NULL); + floater->requestVOInventory(); } void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, @@ -270,15 +268,15 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, std::string text = obj->getName(); if (!(next_owner_mask & PERM_COPY)) { - text.append(" (no copy)"); + text.append(LLTrans::getString("no_copy")); } if (!(next_owner_mask & PERM_MODIFY)) { - text.append(" (no modify)"); + text.append(LLTrans::getString("no_modify")); } if (!(next_owner_mask & PERM_TRANSFER)) { - text.append(" (no transfer)"); + text.append(LLTrans::getString("no_transfer")); } row["columns"][1]["column"] = "text"; @@ -290,16 +288,8 @@ void LLFloaterBuy::inventoryChanged(LLViewerObject* obj, removeVOInventoryListener(); } - -// static -void LLFloaterBuy::onClickBuy(void*) +void LLFloaterBuy::onClickBuy() { - if (!sInstance) - { - llinfos << "LLFloaterBuy::onClickBuy no sInstance!" << llendl; - return; - } - // Put the items where we put new folders. LLUUID category_id; category_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_OBJECT); @@ -307,24 +297,13 @@ void LLFloaterBuy::onClickBuy(void*) // *NOTE: doesn't work for multiple object buy, which UI does not // currently support sale info is used for verification only, if // it doesn't match region info then sale is canceled. - LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, sInstance->mSaleInfo ); + LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, mSaleInfo ); - sInstance->close(); + closeFloater(); } -// static -void LLFloaterBuy::onClickCancel(void*) +void LLFloaterBuy::onClickCancel() { - if (sInstance) - { - sInstance->close(); - } -} - -void LLFloaterBuy::onClose(bool app_quitting) -{ - // drop reference to current selection so selection goes away - mObjectSelection = NULL; - LLFloater::onClose(app_quitting); + closeFloater(); } diff --git a/indra/newview/llfloaterbuy.h b/indra/newview/llfloaterbuy.h index 7473e6c855..ee54303267 100644 --- a/indra/newview/llfloaterbuy.h +++ b/indra/newview/llfloaterbuy.h @@ -52,13 +52,14 @@ class LLFloaterBuy : public LLFloater, public LLVOInventoryListener { public: + LLFloaterBuy(const LLSD& key); + ~LLFloaterBuy(); + + /*virtual*/ BOOL postBuild(); + static void show(const LLSaleInfo& sale_info); protected: - LLFloaterBuy(); - ~LLFloaterBuy(); - - /*virtual*/ void onClose(bool app_quitting); void reset(); void requestObjectInventories(); @@ -67,12 +68,10 @@ protected: S32 serial_num, void* data); - static void onClickBuy(void*); - static void onClickCancel(void*); + void onClickBuy(); + void onClickCancel(); private: - static LLFloaterBuy* sInstance; - LLSafeHandle mObjectSelection; LLSaleInfo mSaleInfo; }; diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index 95a8caac53..3a4171c6be 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -46,7 +46,8 @@ #include "llalertdialog.h" #include "llcheckboxctrl.h" #include "llinventorymodel.h" // for gInventory -#include "llinventoryview.h" // for get_item_icon +#include "llfloaterreg.h" +#include "llfloaterinventory.h" // for get_item_icon #include "llselectmgr.h" #include "llscrolllistctrl.h" #include "llviewerobject.h" @@ -54,26 +55,35 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -LLFloaterBuyContents* LLFloaterBuyContents::sInstance = NULL; - -LLFloaterBuyContents::LLFloaterBuyContents() -: LLFloater(std::string("floater_buy_contents"), std::string("FloaterBuyContentsRect"), LLStringUtil::null) +LLFloaterBuyContents::LLFloaterBuyContents(const LLSD& key) +: LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_contents.xml"); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_buy_contents.xml"); +} - childSetAction("cancel_btn", onClickCancel, this); - childSetAction("buy_btn", onClickBuy, this); +BOOL LLFloaterBuyContents::postBuild() +{ + + getChild("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickCancel, this)); + getChild("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyContents::onClickBuy, this)); childDisable("item_list"); childDisable("buy_btn"); childDisable("wear_check"); setDefaultBtn("cancel_btn"); // to avoid accidental buy (SL-43130) + + // Always center the dialog. User can change the size, + // but purchases are important and should be center screen. + // This also avoids problems where the user resizes the application window + // mid-session and the saved rect is off-center. + center(); + + return TRUE; } LLFloaterBuyContents::~LLFloaterBuyContents() { - sInstance = NULL; } @@ -87,27 +97,16 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) LLNotifications::instance().add("BuyContentsOneOnly"); return; } + + LLFloaterBuyContents* floater = LLFloaterReg::showTypedInstance("buy_object_contents"); + if (!floater) + return; + + LLScrollListCtrl* list = floater->getChild("item_list"); + if (list) + list->deleteAllItems(); - // Create a new instance only if needed - if (sInstance) - { - LLScrollListCtrl* list = sInstance->getChild("item_list"); - if (list) list->deleteAllItems(); - } - else - { - sInstance = new LLFloaterBuyContents(); - } - - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->setFocus(TRUE); - sInstance->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - - // Always center the dialog. User can change the size, - // but purchases are important and should be center screen. - // This also avoids problems where the user resizes the application window - // mid-session and the saved rect is off-center. - sInstance->center(); + floater->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); LLUUID owner_id; std::string owner_name; @@ -118,7 +117,7 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) return; } - sInstance->mSaleInfo = sale_info; + floater->mSaleInfo = sale_info; // Update the display LLSelectNode* node = selection->getFirstRootNode(); @@ -128,16 +127,16 @@ void LLFloaterBuyContents::show(const LLSaleInfo& sale_info) gCacheName->getGroupName(owner_id, owner_name); } - sInstance->childSetTextArg("contains_text", "[NAME]", node->mName); - sInstance->childSetTextArg("buy_text", "[AMOUNT]", llformat("%d", sale_info.getSalePrice())); - sInstance->childSetTextArg("buy_text", "[NAME]", owner_name); + floater->childSetTextArg("contains_text", "[NAME]", node->mName); + floater->childSetTextArg("buy_text", "[AMOUNT]", llformat("%d", sale_info.getSalePrice())); + floater->childSetTextArg("buy_text", "[NAME]", owner_name); // Must do this after the floater is created, because // sometimes the inventory is already there and // the callback is called immediately. LLViewerObject* obj = selection->getFirstRootObject(); - sInstance->registerVOInventoryListener(obj,NULL); - sInstance->requestVOInventory(); + floater->registerVOInventoryListener(obj,NULL); + floater->requestVOInventory(); } @@ -267,22 +266,21 @@ void LLFloaterBuyContents::inventoryChanged(LLViewerObject* obj, } -// static -void LLFloaterBuyContents::onClickBuy(void*) +void LLFloaterBuyContents::onClickBuy() { // Make sure this wasn't selected through other mechanisms // (ie, being the default button and pressing enter. - if(!sInstance->childIsEnabled("buy_btn")) + if(!childIsEnabled("buy_btn")) { // We shouldn't be enabled. Just close. - sInstance->close(); + closeFloater(); return; } // We may want to wear this item - if (sInstance->childGetValue("wear_check")) + if (childGetValue("wear_check")) { - LLInventoryView::sWearNewClothing = TRUE; + LLFloaterInventory::sWearNewClothing = TRUE; } // Put the items where we put new folders. @@ -292,14 +290,12 @@ void LLFloaterBuyContents::onClickBuy(void*) // *NOTE: doesn't work for multiple object buy, which UI does not // currently support sale info is used for verification only, if // it doesn't match region info then sale is canceled. - LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, sInstance->mSaleInfo); + LLSelectMgr::getInstance()->sendBuy(gAgent.getID(), category_id, mSaleInfo); - sInstance->close(); + closeFloater(); } - -// static -void LLFloaterBuyContents::onClickCancel(void*) +void LLFloaterBuyContents::onClickCancel() { - sInstance->close(); + closeFloater(); } diff --git a/indra/newview/llfloaterbuycontents.h b/indra/newview/llfloaterbuycontents.h index 908ff134e6..8045a46c9f 100644 --- a/indra/newview/llfloaterbuycontents.h +++ b/indra/newview/llfloaterbuycontents.h @@ -52,22 +52,21 @@ class LLFloaterBuyContents public: static void show(const LLSaleInfo& sale_info); -protected: - LLFloaterBuyContents(); + LLFloaterBuyContents(const LLSD& key); ~LLFloaterBuyContents(); - + /*virtual*/ BOOL postBuild(); + +protected: void requestObjectInventories(); /*virtual*/ void inventoryChanged(LLViewerObject* obj, InventoryObjectList* inv, S32 serial_num, void* data); - - static void onClickBuy(void*); - static void onClickCancel(void*); + + void onClickBuy(); + void onClickCancel(); protected: - static LLFloaterBuyContents* sInstance; - LLSafeHandle mObjectSelection; LLSaleInfo mSaleInfo; }; diff --git a/indra/newview/llfloaterbuycurrency.cpp b/indra/newview/llfloaterbuycurrency.cpp index cfbc5da761..0107cb6fe2 100644 --- a/indra/newview/llfloaterbuycurrency.cpp +++ b/indra/newview/llfloaterbuycurrency.cpp @@ -37,6 +37,7 @@ // viewer includes #include "llcurrencyuimanager.h" #include "llfloater.h" +#include "llfloaterreg.h" #include "llstatusbar.h" #include "lltextbox.h" #include "llviewchildren.h" @@ -53,12 +54,7 @@ class LLFloaterBuyCurrencyUI : public LLFloater { public: - static LLFloaterBuyCurrencyUI* soleInstance(bool createIfNeeded); - -private: - static LLFloaterBuyCurrencyUI* sInstance; - - LLFloaterBuyCurrencyUI(); + LLFloaterBuyCurrencyUI(const LLSD& key); virtual ~LLFloaterBuyCurrencyUI(); @@ -80,32 +76,18 @@ public: virtual void draw(); virtual BOOL canClose(); - virtual void onClose(bool app_quitting); - static void onClickBuy(void* data); - static void onClickCancel(void* data); - static void onClickErrorWeb(void* data); + void onClickBuy(); + void onClickCancel(); + void onClickErrorWeb(); }; - -// static -LLFloaterBuyCurrencyUI* LLFloaterBuyCurrencyUI::sInstance = NULL; - -// static -LLFloaterBuyCurrencyUI* LLFloaterBuyCurrencyUI::soleInstance(bool createIfNeeded) +LLFloater* LLFloaterBuyCurrency::buildFloater(const LLSD& key) { - if (!sInstance && createIfNeeded) - { - sInstance = new LLFloaterBuyCurrencyUI(); - - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_buy_currency.xml"); - sInstance->center(); - } - - return sInstance; + LLFloaterBuyCurrencyUI* floater = new LLFloaterBuyCurrencyUI(key); + return floater; } - #if LL_WINDOWS // passing 'this' during construction generates a warning. The callee // only uses the pointer to hold a reference to 'this' which is @@ -113,8 +95,8 @@ LLFloaterBuyCurrencyUI* LLFloaterBuyCurrencyUI::soleInstance(bool createIfNeeded // warning so that we can compile without generating a warning. #pragma warning(disable : 4355) #endif -LLFloaterBuyCurrencyUI::LLFloaterBuyCurrencyUI() -: LLFloater(std::string("Buy Currency")), +LLFloaterBuyCurrencyUI::LLFloaterBuyCurrencyUI(const LLSD& key) +: LLFloater(key), mChildren(*this), mManager(*this) { @@ -122,10 +104,6 @@ LLFloaterBuyCurrencyUI::LLFloaterBuyCurrencyUI() LLFloaterBuyCurrencyUI::~LLFloaterBuyCurrencyUI() { - if (sInstance == this) - { - sInstance = NULL; - } } @@ -157,10 +135,12 @@ BOOL LLFloaterBuyCurrencyUI::postBuild() { mManager.prepare(); - childSetAction("buy_btn", onClickBuy, this); - childSetAction("cancel_btn", onClickCancel, this); - childSetAction("error_web", onClickErrorWeb, this); - + getChild("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickBuy, this)); + getChild("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickCancel, this)); + getChild("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyCurrencyUI::onClickErrorWeb, this)); + + center(); + updateUI(); return TRUE; @@ -172,7 +152,7 @@ void LLFloaterBuyCurrencyUI::draw() { if (mManager.bought()) { - close(); + closeFloater(); return; } @@ -187,12 +167,6 @@ BOOL LLFloaterBuyCurrencyUI::canClose() return mManager.canCancel(); } -void LLFloaterBuyCurrencyUI::onClose(bool app_quitting) -{ - LLFloater::onClose(app_quitting); - destroy(); -} - void LLFloaterBuyCurrencyUI::updateUI() { bool hasError = mManager.hasError(); @@ -320,57 +294,41 @@ void LLFloaterBuyCurrencyUI::updateUI() } } -// static -void LLFloaterBuyCurrencyUI::onClickBuy(void* data) +void LLFloaterBuyCurrencyUI::onClickBuy() { - LLFloaterBuyCurrencyUI* self = LLFloaterBuyCurrencyUI::soleInstance(false); - if (self) - { - self->mManager.buy(self->getString("buy_currency")); - self->updateUI(); - // JC: updateUI() doesn't get called again until progress is made - // with transaction processing, so the "Purchase" button would be - // left enabled for some time. Pre-emptively disable. - self->childSetEnabled("buy_btn", false); - } + mManager.buy(getString("buy_currency")); + updateUI(); + // JC: updateUI() doesn't get called again until progress is made + // with transaction processing, so the "Purchase" button would be + // left enabled for some time. Pre-emptively disable. + childSetEnabled("buy_btn", false); } -// static -void LLFloaterBuyCurrencyUI::onClickCancel(void* data) +void LLFloaterBuyCurrencyUI::onClickCancel() { - LLFloaterBuyCurrencyUI* self = LLFloaterBuyCurrencyUI::soleInstance(false); - if (self) - { - self->close(); - } + closeFloater(); } -// static -void LLFloaterBuyCurrencyUI::onClickErrorWeb(void* data) +void LLFloaterBuyCurrencyUI::onClickErrorWeb() { - LLFloaterBuyCurrencyUI* self = LLFloaterBuyCurrencyUI::soleInstance(false); - if (self) - { - LLWeb::loadURLExternal(self->mManager.errorURI()); - self->close(); - } + LLWeb::loadURLExternal(mManager.errorURI()); + closeFloater(); } // static void LLFloaterBuyCurrency::buyCurrency() { - LLFloaterBuyCurrencyUI* ui = LLFloaterBuyCurrencyUI::soleInstance(true); + LLFloaterBuyCurrencyUI* ui = LLFloaterReg::showTypedInstance("buy_currency"); ui->noTarget(); ui->updateUI(); - ui->open(); } +// static void LLFloaterBuyCurrency::buyCurrency(const std::string& name, S32 price) { - LLFloaterBuyCurrencyUI* ui = LLFloaterBuyCurrencyUI::soleInstance(true); + LLFloaterBuyCurrencyUI* ui = LLFloaterReg::showTypedInstance("buy_currency"); ui->target(name, price); ui->updateUI(); - ui->open(); } diff --git a/indra/newview/llfloaterbuycurrency.h b/indra/newview/llfloaterbuycurrency.h index 756acd2f0c..9b3f9b43d0 100644 --- a/indra/newview/llfloaterbuycurrency.h +++ b/indra/newview/llfloaterbuycurrency.h @@ -35,6 +35,8 @@ #include "stdtypes.h" +class LLFloater; + class LLFloaterBuyCurrency { public: @@ -46,6 +48,8 @@ public: "Uploading costs" a space and the price will be appended */ + + static LLFloater* buildFloater(const LLSD& key); }; diff --git a/indra/newview/llfloaterbuyland.cpp b/indra/newview/llfloaterbuyland.cpp index 29506e21d5..7075719299 100644 --- a/indra/newview/llfloaterbuyland.cpp +++ b/indra/newview/llfloaterbuyland.cpp @@ -43,6 +43,7 @@ #include "llconfirmationmanager.h" #include "llcurrencyuimanager.h" #include "llfloater.h" +#include "llfloaterreg.h" #include "llfloatertools.h" #include "llframetimer.h" #include "lliconctrl.h" @@ -75,10 +76,22 @@ const F64 CURRENCY_ESTIMATE_FREQUENCY = 0.5; class LLFloaterBuyLandUI : public LLFloater { -private: - LLFloaterBuyLandUI(); +public: + LLFloaterBuyLandUI(const LLSD& key); virtual ~LLFloaterBuyLandUI(); - + +private: + class SelectionObserver : public LLParcelObserver + { + public: + SelectionObserver(LLFloaterBuyLandUI* floater) : mFloater(floater) {} + virtual void changed(); + private: + LLFloaterBuyLandUI* mFloater; + }; + +private: + SelectionObserver mParcelSelectionObserver; LLViewerRegion* mRegion; LLParcelSelectionHandle mParcel; bool mIsClaim; @@ -144,11 +157,7 @@ private: LLViewerParcelMgr::ParcelBuyInfo* mParcelBuyInfo; - static LLFloaterBuyLandUI* sInstance; - public: - static LLFloaterBuyLandUI* soleInstance(bool createIfNeeded); - void setForGroup(bool is_for_group); void setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel); @@ -156,10 +165,10 @@ public: void updateParcelInfo(); void updateCovenantInfo(); static void onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data); - void updateCovenantText(const std::string& string, const LLUUID &asset_id); - void updateEstateName(const std::string& name); - void updateLastModified(const std::string& text); - void updateEstateOwnerName(const std::string& name); + void updateFloaterCovenantText(const std::string& string, const LLUUID &asset_id); + void updateFloaterEstateName(const std::string& name); + void updateFloaterLastModified(const std::string& text); + void updateFloaterEstateOwnerName(const std::string& name); void updateWebSiteInfo(); void finishWebSiteInfo(); @@ -171,7 +180,7 @@ public: void refreshUI(); - void startTransaction(TransactionType type, LLXMLRPCValue params); + void startTransaction(TransactionType type, const LLXMLRPCValue& params); bool checkTransaction(); void tellUserError(const std::string& message, const std::string& uri); @@ -181,27 +190,21 @@ public: void startBuyPreConfirm(); void startBuyPostConfirm(const std::string& password); - static void onClickBuy(void* data); - static void onClickCancel(void* data); - static void onClickErrorWeb(void* data); + void onClickBuy(); + void onClickCancel(); + void onClickErrorWeb(); virtual void draw(); virtual BOOL canClose(); - virtual void onClose(bool app_quitting); - /*virtual*/ void setMinimized(BOOL b); + + void onVisibilityChange ( const LLSD& new_visibility ); -private: - class SelectionObserver : public LLParcelObserver - { - public: - virtual void changed(); - }; }; static void cacheNameUpdateRefreshesBuyLand(const LLUUID&, - const std::string&, const std::string&, BOOL, void* data) + const std::string&, const std::string&, BOOL) { - LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false); + LLFloaterBuyLandUI* ui = LLFloaterReg::findTypedInstance("buy_land"); if (ui) { ui->updateNames(); @@ -218,101 +221,64 @@ void LLFloaterBuyLand::buyLand( return; } - LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(true); - ui->setForGroup(is_for_group); - ui->setParcel(region, parcel); - ui->open(); /*Flawfinder: ignore*/ + LLFloaterBuyLandUI* ui = LLFloaterReg::showTypedInstance("buy_land"); + if (ui) + { + ui->setForGroup(is_for_group); + ui->setParcel(region, parcel); + } } // static void LLFloaterBuyLand::updateCovenantText(const std::string& string, const LLUUID &asset_id) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE); + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance("buy_land"); if (floater) { - floater->updateCovenantText(string, asset_id); + floater->updateFloaterCovenantText(string, asset_id); } } // static void LLFloaterBuyLand::updateEstateName(const std::string& name) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE); + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance("buy_land"); if (floater) { - floater->updateEstateName(name); + floater->updateFloaterEstateName(name); } } // static void LLFloaterBuyLand::updateLastModified(const std::string& text) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE); + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance("buy_land"); if (floater) { - floater->updateLastModified(text); + floater->updateFloaterLastModified(text); } } // static void LLFloaterBuyLand::updateEstateOwnerName(const std::string& name) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE); + LLFloaterBuyLandUI* floater = LLFloaterReg::findTypedInstance("buy_land"); if (floater) { - floater->updateEstateOwnerName(name); + floater->updateFloaterEstateOwnerName(name); } } // static -BOOL LLFloaterBuyLand::isOpen() +LLFloater* LLFloaterBuyLand::buildFloater(const LLSD& key) { - LLFloaterBuyLandUI* floater = LLFloaterBuyLandUI::soleInstance(FALSE); - if (floater) - { - return floater->getVisible(); - } - return FALSE; -} - -// static -LLFloaterBuyLandUI* LLFloaterBuyLandUI::sInstance = NULL; - -// static -LLFloaterBuyLandUI* LLFloaterBuyLandUI::soleInstance(bool createIfNeeded) -{ -#if !LL_RELEASE_FOR_DOWNLOAD - if (createIfNeeded) - { - delete sInstance; - sInstance = NULL; - } -#endif - if (!sInstance && createIfNeeded) - { - sInstance = new LLFloaterBuyLandUI(); - - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_buy_land.xml"); - sInstance->center(); - - static bool observingCacheName = false; - if (!observingCacheName) - { - gCacheName->addObserver(cacheNameUpdateRefreshesBuyLand); - observingCacheName = true; - } - - static SelectionObserver* parcelSelectionObserver = NULL; - if (!parcelSelectionObserver) - { - parcelSelectionObserver = new SelectionObserver; - LLViewerParcelMgr::getInstance()->addObserver(parcelSelectionObserver); - } - } - - return sInstance; + LLFloaterBuyLandUI* floater = new LLFloaterBuyLandUI(key); + return floater; } +//---------------------------------------------------------------------------- +// LLFloaterBuyLandUI +//---------------------------------------------------------------------------- #if LL_WINDOWS // passing 'this' during construction generates a warning. The callee @@ -321,42 +287,45 @@ LLFloaterBuyLandUI* LLFloaterBuyLandUI::soleInstance(bool createIfNeeded) // warning so that we can compile without generating a warning. #pragma warning(disable : 4355) #endif -LLFloaterBuyLandUI::LLFloaterBuyLandUI() -: LLFloater(std::string("Buy Land")), +LLFloaterBuyLandUI::LLFloaterBuyLandUI(const LLSD& key) +: LLFloater(LLSD()), + mParcelSelectionObserver(this), mParcel(0), mBought(false), mParcelValid(false), mSiteValid(false), mChildren(*this), mCurrency(*this), mTransaction(0), mParcelBuyInfo(0) { + static bool observingCacheName = false; + if (!observingCacheName) + { + gCacheName->addObserver(&cacheNameUpdateRefreshesBuyLand); + observingCacheName = true; + } + + LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver); + +// LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_buy_land.xml"); } LLFloaterBuyLandUI::~LLFloaterBuyLandUI() { - delete mTransaction; - + LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver); LLViewerParcelMgr::getInstance()->deleteParcelBuy(mParcelBuyInfo); - if (sInstance == this) - { - sInstance = NULL; - } + delete mTransaction; } void LLFloaterBuyLandUI::SelectionObserver::changed() { - LLFloaterBuyLandUI* ui = LLFloaterBuyLandUI::soleInstance(false); - if (ui) + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) { - if (LLViewerParcelMgr::getInstance()->selectionEmpty()) - { - ui->close(); - } - else { - ui->setParcel( - LLViewerParcelMgr::getInstance()->getSelectionRegion(), - LLViewerParcelMgr::getInstance()->getParcelSelection()); - } + mFloater->closeFloater(); + } + else + { + mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(), + LLViewerParcelMgr::getInstance()->getParcelSelection()); } } @@ -566,8 +535,7 @@ void LLFloaterBuyLandUI::updateCovenantInfo() { check->set(false); check->setEnabled(true); - check->setCallbackUserData(this); - check->setCommitCallback(onChangeAgreeCovenant); + check->setCommitCallback(onChangeAgreeCovenant, this); } LLTextBox* box = getChild("covenant_text"); @@ -595,51 +563,44 @@ void LLFloaterBuyLandUI::onChangeAgreeCovenant(LLUICtrl* ctrl, void* user_data) } } -void LLFloaterBuyLandUI::updateCovenantText(const std::string &string, const LLUUID& asset_id) +void LLFloaterBuyLandUI::updateFloaterCovenantText(const std::string &string, const LLUUID& asset_id) { LLViewerTextEditor* editor = getChild("covenant_editor"); - if (editor) + editor->setText(string); + + LLCheckBoxCtrl* check = getChild("agree_covenant"); + LLTextBox* box = getChild("covenant_text"); + if (asset_id.isNull()) { - editor->setHandleEditKeysDirectly(FALSE); - editor->setText(string); + check->set(true); + check->setEnabled(false); + refreshUI(); - LLCheckBoxCtrl* check = getChild("agree_covenant"); - LLTextBox* box = getChild("covenant_text"); - if(check && box) - { - if (asset_id.isNull()) - { - check->set(true); - check->setEnabled(false); - refreshUI(); + // remove the line stating that you must agree + box->setVisible(FALSE); + } + else + { + check->setEnabled(true); - // remove the line stating that you must agree - box->setVisible(FALSE); - } - else - { - check->setEnabled(true); - - // remove the line stating that you must agree - box->setVisible(TRUE); - } - } + // remove the line stating that you must agree + box->setVisible(TRUE); } } -void LLFloaterBuyLandUI::updateEstateName(const std::string& name) +void LLFloaterBuyLandUI::updateFloaterEstateName(const std::string& name) { LLTextBox* box = getChild("estate_name_text"); if (box) box->setText(name); } -void LLFloaterBuyLandUI::updateLastModified(const std::string& text) +void LLFloaterBuyLandUI::updateFloaterLastModified(const std::string& text) { LLTextBox* editor = getChild("covenant_timestamp_text"); if (editor) editor->setText(text); } -void LLFloaterBuyLandUI::updateEstateOwnerName(const std::string& name) +void LLFloaterBuyLandUI::updateFloaterEstateOwnerName(const std::string& name) { LLTextBox* box = getChild("estate_owner_text"); if (box) box->setText(name); @@ -836,8 +797,7 @@ void LLFloaterBuyLandUI::updateNames() } -void LLFloaterBuyLandUI::startTransaction(TransactionType type, - LLXMLRPCValue params) +void LLFloaterBuyLandUI::startTransaction(TransactionType type, const LLXMLRPCValue& params) { delete mTransaction; mTransaction = NULL; @@ -918,11 +878,15 @@ void LLFloaterBuyLandUI::tellUserError( // virtual BOOL LLFloaterBuyLandUI::postBuild() { + mVisibleSignal.connect(boost::bind(&LLFloaterBuyLandUI::onVisibilityChange, this, _2)); + mCurrency.prepare(); - childSetAction("buy_btn", onClickBuy, this); - childSetAction("cancel_btn", onClickCancel, this); - childSetAction("error_web", onClickErrorWeb, this); + getChild("buy_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickBuy, this)); + getChild("cancel_btn")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickCancel, this)); + getChild("error_web")->setCommitCallback( boost::bind(&LLFloaterBuyLandUI::onClickErrorWeb, this)); + + center(); return TRUE; } @@ -963,7 +927,7 @@ void LLFloaterBuyLandUI::draw() if (mBought) { - close(); + closeFloater(); } else if (needsUpdate) { @@ -988,24 +952,14 @@ BOOL LLFloaterBuyLandUI::canClose() return can_close; } -// virtual -void LLFloaterBuyLandUI::setMinimized(BOOL minimize) +void LLFloaterBuyLandUI::onVisibilityChange ( const LLSD& new_visibility ) { - bool restored = (isMinimized() && !minimize); - LLFloater::setMinimized(minimize); - if (restored) + if (new_visibility.asBoolean()) { refreshUI(); } } -void LLFloaterBuyLandUI::onClose(bool app_quitting) -{ - LLFloater::onClose(app_quitting); - destroy(); -} - - void LLFloaterBuyLandUI::refreshUI() { // section zero: title area @@ -1155,7 +1109,7 @@ void LLFloaterBuyLandUI::refreshUI() if (mIsForGroup) { LLStringUtil::format_map_t string_args; - string_args["[GROUP]"] = std::string(gAgent.mGroupName); + string_args["[GROUP]"] = std::string(gAgent.getGroupName()); message += getString("insufficient_land_credits", string_args); @@ -1169,7 +1123,7 @@ void LLFloaterBuyLandUI::refreshUI() if (!mParcelValid) { - message += "(no parcel selected)"; + message += getString("no_parcel_selected"); } else if (mParcelBillableArea == mParcelActualArea) { @@ -1225,12 +1179,10 @@ void LLFloaterBuyLandUI::refreshUI() ? LLViewChildren::BADGE_NOTE : LLViewChildren::BADGE_OK); - childSetText("purchase_action", - llformat( - "Pay L$ %d to %s for this land", - mParcelPrice, - mParcelSellerName.c_str() - )); + LLStringUtil::format_map_t string_args; + string_args["[AMOUNT]"] = llformat("%d", mParcelPrice); + string_args["[SELLER]"] = mParcelSellerName; + childSetText("purchase_action", getString("pay_to_for_land", string_args)); childSetVisible("purchase_action", mParcelValid); std::string reasonString; @@ -1357,26 +1309,20 @@ void LLFloaterBuyLandUI::startBuyPostConfirm(const std::string& password) } -// static -void LLFloaterBuyLandUI::onClickBuy(void* data) +void LLFloaterBuyLandUI::onClickBuy() { - LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data; - self->startBuyPreConfirm(); + startBuyPreConfirm(); } -// static -void LLFloaterBuyLandUI::onClickCancel(void* data) +void LLFloaterBuyLandUI::onClickCancel() { - LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data; - self->close(); + closeFloater(); } -// static -void LLFloaterBuyLandUI::onClickErrorWeb(void* data) +void LLFloaterBuyLandUI::onClickErrorWeb() { - LLFloaterBuyLandUI* self = (LLFloaterBuyLandUI*)data; - LLWeb::loadURLExternal(self->mCannotBuyURI); - self->close(); + LLWeb::loadURLExternal(mCannotBuyURI); + closeFloater(); } diff --git a/indra/newview/llfloaterbuyland.h b/indra/newview/llfloaterbuyland.h index 82e59a0bcc..00d44035ae 100644 --- a/indra/newview/llfloaterbuyland.h +++ b/indra/newview/llfloaterbuyland.h @@ -33,8 +33,8 @@ #ifndef LL_LLFLOATERBUYLAND_H #define LL_LLFLOATERBUYLAND_H +class LLFloater; class LLViewerRegion; -class LLViewerTextEditor; class LLParcelSelection; class LLFloaterBuyLand @@ -47,7 +47,8 @@ public: static void updateEstateName(const std::string& name); static void updateLastModified(const std::string& text); static void updateEstateOwnerName(const std::string& name); - static BOOL isOpen(); + + static LLFloater* buildFloater(const LLSD& key); }; #endif diff --git a/indra/newview/llfloatercamera.cpp b/indra/newview/llfloatercamera.cpp index 7a4e5147fe..94ea20893a 100644 --- a/indra/newview/llfloatercamera.cpp +++ b/indra/newview/llfloatercamera.cpp @@ -35,87 +35,308 @@ #include "llfloatercamera.h" // Library includes -#include "lluictrlfactory.h" +#include "llfloaterreg.h" // Viewer includes #include "lljoystickbutton.h" +#include "llfirsttimetipmanager.h" #include "llviewercontrol.h" +#include "llbottomtray.h" +#include "llagent.h" +#include "lltoolmgr.h" +#include "lltoolfocus.h" // Constants const F32 CAMERA_BUTTON_DELAY = 0.0f; +#define ORBIT "cam_rotate_stick" +#define PAN "cam_track_stick" +#define CONTROLS "controls" + + +void show_tip(LLFirstTimeTipsManager::EFirstTimeTipType tipType, LLView* anchorView) +{ + LLFirstTimeTipsManager::showTipsFor(tipType, anchorView, LLFirstTimeTipsManager::TPA_POS_RIGHT_ALIGN_TOP); +} // // Member functions // -LLFloaterCamera::LLFloaterCamera(const LLSD& val) -: LLFloater("camera floater") // uses "FloaterCameraRect3" +/*static*/ bool LLFloaterCamera::inFreeCameraMode() { - setIsChrome(TRUE); - - // For now, only used for size and tooltip strings - const BOOL DONT_OPEN = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_camera.xml", NULL, DONT_OPEN); - - S32 top = getRect().getHeight(); - S32 bottom = 0; - S32 left = 16; - - const S32 ROTATE_WIDTH = 64; - mRotate = new LLJoystickCameraRotate(std::string("cam rotate stick"), - LLRect( left, top, left + ROTATE_WIDTH, bottom ), - std::string("cam_rotate_out.tga"), - std::string("cam_rotate_in.tga") ); - mRotate->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); - mRotate->setHeldDownDelay(CAMERA_BUTTON_DELAY); - mRotate->setToolTip( getString("rotate_tooltip") ); - mRotate->setSoundFlags(MOUSE_DOWN | MOUSE_UP); - addChild(mRotate); - - left += ROTATE_WIDTH; - - const S32 ZOOM_WIDTH = 16; - mZoom = new LLJoystickCameraZoom( - std::string("zoom"), - LLRect( left, top, left + ZOOM_WIDTH, bottom ), - std::string("cam_zoom_out.tga"), - std::string("cam_zoom_plus_in.tga"), - std::string("cam_zoom_minus_in.tga")); - mZoom->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); - mZoom->setHeldDownDelay(CAMERA_BUTTON_DELAY); - mZoom->setToolTip( getString("zoom_tooltip") ); - mZoom->setSoundFlags(MOUSE_DOWN | MOUSE_UP); - addChild(mZoom); - - left += ZOOM_WIDTH; - - const S32 TRACK_WIDTH = 64; - mTrack = new LLJoystickCameraTrack(std::string("cam track stick"), - LLRect( left, top, left + TRACK_WIDTH, bottom ), - std::string("cam_tracking_out.tga"), - std::string("cam_tracking_in.tga")); - mTrack->setFollows(FOLLOWS_TOP | FOLLOWS_LEFT); - mTrack->setHeldDownDelay(CAMERA_BUTTON_DELAY); - mTrack->setToolTip( getString("move_tooltip") ); - mTrack->setSoundFlags(MOUSE_DOWN | MOUSE_UP); - addChild(mTrack); -} - -// virtual -void LLFloaterCamera::onOpen() -{ - LLFloater::onOpen(); - - gSavedSettings.setBOOL("ShowCameraControls", TRUE); -} - -// virtual -void LLFloaterCamera::onClose(bool app_quitting) -{ - LLFloater::onClose(app_quitting); - - if (!app_quitting) + LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); + if (floater_camera && floater_camera->mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA) { - gSavedSettings.setBOOL("ShowCameraControls", FALSE); + return true; + } + return false; +} + +bool LLFloaterCamera::inAvatarViewMode() +{ + return mCurrMode == CAMERA_CTRL_MODE_AVATAR_VIEW; +} + +void LLFloaterCamera::resetFreeCameraMode() +{ + if (mCurrMode == CAMERA_CTRL_MODE_FREE_CAMERA) + { + /* Camera Tool can be deselected when we are mouse wheel scrolling into Mouse Look + In such case we are unable to determine that we will be into Mouse Look view */ + if (mPrevMode == CAMERA_CTRL_MODE_AVATAR_VIEW) + { + setMode(CAMERA_CTRL_MODE_ORBIT); + } + else + { + setMode(mPrevMode); + } } } + +void LLFloaterCamera::update() +{ + ECameraControlMode mode = determineMode(); + if (mode != mCurrMode) setMode(mode); + updatePosition(); + show_tip(mMode2TipType[mode], this); +} + + +/*static*/ void LLFloaterCamera::updateIfNotInAvatarViewMode() +{ + LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); + if (floater_camera && !floater_camera->inAvatarViewMode()) + { + floater_camera->update(); + } +} + + +void LLFloaterCamera::toPrevMode() +{ + switchMode(mPrevMode); +} + +/*static*/ void LLFloaterCamera::toPrevModeIfInAvatarViewMode() +{ + LLFloaterCamera* floater_camera = LLFloaterCamera::findInstance(); + if (floater_camera && floater_camera->inAvatarViewMode()) + { + floater_camera->toPrevMode(); + } +} + +LLFloaterCamera* LLFloaterCamera::findInstance() +{ + return LLFloaterReg::findTypedInstance("camera"); +} + +/*static*/ +void LLFloaterCamera::onClickCameraPresets(LLUICtrl* ctrl, const LLSD& param) +{ + std::string name = param.asString(); + + if ("rear_view" == name) + { + LLFirstTimeTipsManager::showTipsFor(LLFirstTimeTipsManager::FTT_CAMERA_PRESET_REAR, ctrl); + gAgent.switchCameraPreset(CAMERA_PRESET_REAR_VIEW); + } + else if ("group_view" == name) + { + LLFirstTimeTipsManager::showTipsFor(LLFirstTimeTipsManager::FTT_CAMERA_PRESET_GROUP); + gAgent.switchCameraPreset(CAMERA_PRESET_GROUP_VIEW); + } + else if ("front_view" == name) + { + LLFirstTimeTipsManager::showTipsFor(LLFirstTimeTipsManager::FTT_CAMERA_PRESET_FRONT); + gAgent.switchCameraPreset(CAMERA_PRESET_FRONT_VIEW); + } + +} + +void LLFloaterCamera::onOpen(const LLSD& key) +{ + updatePosition(); +} + +void LLFloaterCamera::updatePosition() +{ + LLBottomTray* tray = LLBottomTray::getInstance(); + if (!tray) return; + + LLButton* camera_button = tray->getChild("camera_btn"); + + //align centers of a button and a floater + S32 x = camera_button->calcScreenRect().getCenterX() - getRect().getWidth()/2; + setOrigin(x, 0); +} + +LLFloaterCamera::LLFloaterCamera(const LLSD& val) +: LLFloater(val), + mCurrMode(CAMERA_CTRL_MODE_ORBIT), + mPrevMode(CAMERA_CTRL_MODE_ORBIT) +{ +} + +// virtual +BOOL LLFloaterCamera::postBuild() +{ + setIsChrome(TRUE); + + mRotate = getChild(ORBIT); + mZoom = getChild("zoom"); + mTrack = getChild(PAN); + + initMode2TipTypeMap(); + + assignButton2Mode(CAMERA_CTRL_MODE_ORBIT, "orbit_btn"); + assignButton2Mode(CAMERA_CTRL_MODE_PAN, "pan_btn"); + assignButton2Mode(CAMERA_CTRL_MODE_FREE_CAMERA, "freecamera_btn"); + assignButton2Mode(CAMERA_CTRL_MODE_AVATAR_VIEW, "avatarview_btn"); + + update(); + + return TRUE; +} + +ECameraControlMode LLFloaterCamera::determineMode() +{ + LLTool* curr_tool = LLToolMgr::getInstance()->getCurrentTool(); + if (curr_tool == LLToolCamera::getInstance()) + { + return CAMERA_CTRL_MODE_FREE_CAMERA; + } + + if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) + { + return CAMERA_CTRL_MODE_AVATAR_VIEW; + } + + return CAMERA_CTRL_MODE_ORBIT; +} + + +void clear_camera_tool() +{ + LLToolMgr* tool_mgr = LLToolMgr::getInstance(); + if (tool_mgr->usingTransientTool() && + tool_mgr->getCurrentTool() == LLToolCamera::getInstance()) + { + tool_mgr->clearTransientTool(); + } +} + + +void LLFloaterCamera::setMode(ECameraControlMode mode) +{ + if (mode != mCurrMode) + { + mPrevMode = mCurrMode; + mCurrMode = mode; + } + + updateState(); +} + +void LLFloaterCamera::switchMode(ECameraControlMode mode) +{ + setMode(mode); + + switch (mode) + { + case CAMERA_CTRL_MODE_ORBIT: + clear_camera_tool(); + break; + + case CAMERA_CTRL_MODE_PAN: + clear_camera_tool(); + break; + + case CAMERA_CTRL_MODE_FREE_CAMERA: + LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance()); + break; + + case CAMERA_CTRL_MODE_AVATAR_VIEW: + gAgent.changeCameraToMouselook(); + break; + + default: + //normally we won't occur here + llassert_always(FALSE); + } +} + + +void LLFloaterCamera::onClickBtn(ECameraControlMode mode) +{ + // check for a click on active button + if (mCurrMode == mode) mMode2Button[mode]->setToggleState(TRUE); + + switchMode(mode); + + show_tip(mMode2TipType[mode], this); +} + +void LLFloaterCamera::assignButton2Mode(ECameraControlMode mode, const std::string& button_name) +{ + LLButton* button = getChild(button_name); + + button->setClickedCallback(boost::bind(&LLFloaterCamera::onClickBtn, this, mode)); + mMode2Button[mode] = button; +} + +void LLFloaterCamera::initMode2TipTypeMap() +{ + mMode2TipType[CAMERA_CTRL_MODE_ORBIT] = LLFirstTimeTipsManager::FTT_CAMERA_ORBIT_MODE; + mMode2TipType[CAMERA_CTRL_MODE_PAN] = LLFirstTimeTipsManager::FTT_CAMERA_PAN_MODE; + mMode2TipType[CAMERA_CTRL_MODE_FREE_CAMERA] = LLFirstTimeTipsManager::FTT_CAMERA_FREE_MODE; + mMode2TipType[CAMERA_CTRL_MODE_AVATAR_VIEW] = LLFirstTimeTipsManager::FTT_AVATAR_FREE_MODE; +} + + +void LLFloaterCamera::updateState() +{ + //updating buttons + std::map::const_iterator iter = mMode2Button.begin(); + for (; iter != mMode2Button.end(); ++iter) + { + iter->second->setToggleState(iter->first == mCurrMode); + } + + //updating controls + bool isOrbitMode = CAMERA_CTRL_MODE_ORBIT == mCurrMode; + bool isPanMode = CAMERA_CTRL_MODE_PAN == mCurrMode; + + childSetVisible(ORBIT, isOrbitMode); + childSetVisible(PAN, isPanMode); + + //hiding or showing the panel with controls by reshaping the floater + bool showControls = isOrbitMode || isPanMode; + if (showControls == childIsVisible(CONTROLS)) return; + + childSetVisible(CONTROLS, showControls); + + LLRect rect = getRect(); + LLRect controls_rect; + if (childGetRect(CONTROLS, controls_rect)) + { + static S32 height = controls_rect.getHeight(); + S32 newHeight = rect.getHeight(); + + if (showControls) + { + newHeight += height; + } + else + { + newHeight -= height; + } + + rect.setOriginAndSize(rect.mLeft, rect.mBottom, rect.getWidth(), newHeight); + reshape(rect.getWidth(), rect.getHeight()); + setRect(rect); + + } +} + diff --git a/indra/newview/llfloatercamera.h b/indra/newview/llfloatercamera.h index 6862db7068..04554c6493 100644 --- a/indra/newview/llfloatercamera.h +++ b/indra/newview/llfloatercamera.h @@ -35,27 +35,94 @@ #include "llfloater.h" +#include "llfirsttimetipmanager.h" + class LLJoystickCameraRotate; class LLJoystickCameraZoom; class LLJoystickCameraTrack; +class LLFloaterReg; + +enum ECameraControlMode +{ + CAMERA_CTRL_MODE_ORBIT, + CAMERA_CTRL_MODE_PAN, + CAMERA_CTRL_MODE_FREE_CAMERA, + CAMERA_CTRL_MODE_AVATAR_VIEW +}; class LLFloaterCamera - : public LLFloater, - public LLFloaterSingleton + : public LLFloater { - friend class LLUISingleton >; - -private: - LLFloaterCamera(const LLSD& val); - ~LLFloaterCamera() {}; - - /*virtual*/ void onOpen(); - /*virtual*/ void onClose(bool app_quitting); + friend class LLFloaterReg; public: + + /* whether in free camera mode */ + static bool inFreeCameraMode(); + + static void toPrevModeIfInAvatarViewMode(); + + /* resets free camera mode to the previous mode */ + //*TODO remove, if it won't be used by LLToolCamera::handleDeselect() + void resetFreeCameraMode(); + + /* determines actual mode and updates ui */ + void update(); + + static void updateIfNotInAvatarViewMode(); + + static void onClickCameraPresets(LLUICtrl* ctrl, const LLSD& param); + + virtual void onOpen(const LLSD& key); + + // *HACK: due to hard enough to have this control aligned with "Camera" button while resizing + // let update its position in each frame + /*virtual*/ void draw(){updatePosition(); LLFloater::draw();} + LLJoystickCameraRotate* mRotate; LLJoystickCameraZoom* mZoom; LLJoystickCameraTrack* mTrack; + +private: + + LLFloaterCamera(const LLSD& val); + ~LLFloaterCamera() {}; + + /* return instance if it exists - created by LLFloaterReg */ + static LLFloaterCamera* findInstance(); + + /*virtual*/ BOOL postBuild(); + + ECameraControlMode determineMode(); + + /* whether in avatar view (first person) mode */ + bool inAvatarViewMode(); + + /* resets to the previous mode */ + void toPrevMode(); + + /* sets a new mode and performs related actions */ + void switchMode(ECameraControlMode mode); + + /* sets a new mode preserving previous one and updates ui*/ + void setMode(ECameraControlMode mode); + + /* updates the state (UI) according to the current mode */ + void updateState(); + + void onClickBtn(ECameraControlMode mode); + void assignButton2Mode(ECameraControlMode mode, const std::string& button_name); + void initMode2TipTypeMap(); + + /*Updates position of the floater to be center aligned with "Camera" button.*/ + void updatePosition(); + + + ECameraControlMode mPrevMode; + ECameraControlMode mCurrMode; + std::map mMode2Button; + std::map mMode2TipType; + }; #endif diff --git a/indra/newview/llfloaterchat.cpp b/indra/newview/llfloaterchat.cpp index 0e9295f9f8..0dee3a1e83 100644 --- a/indra/newview/llfloaterchat.cpp +++ b/indra/newview/llfloaterchat.cpp @@ -38,15 +38,6 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterchat.h" -#include "llfloateractivespeakers.h" -#include "llfloaterscriptdebug.h" - -#include "llchat.h" -#include "llfontgl.h" -#include "llrect.h" -#include "llerror.h" -#include "llstring.h" -#include "message.h" // project include #include "llagent.h" @@ -54,13 +45,17 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "llconsole.h" +#include "llfloateractivespeakers.h" #include "llfloaterchatterbox.h" #include "llfloatermute.h" +#include "llfloaterreg.h" +#include "llfloaterscriptdebug.h" #include "llkeyboard.h" //#include "lllineeditor.h" #include "llmutelist.h" //#include "llresizehandle.h" #include "llchatbar.h" +#include "llrecentpeople.h" #include "llstatusbar.h" #include "llviewertexteditor.h" #include "llviewergesture.h" // for triggering gestures @@ -68,7 +63,6 @@ #include "llviewerwindow.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llchatbar.h" #include "lllogchat.h" #include "lltexteditor.h" #include "lltextparser.h" @@ -76,16 +70,22 @@ #include "llweb.h" #include "llstylemap.h" -// Used for LCD display -extern void AddNewIMToLCD(const std::string &newLine); -extern void AddNewChatToLCD(const std::string &newLine); +// linden library includes +#include "llaudioengine.h" +#include "llchat.h" +#include "llfontgl.h" +#include "llrect.h" +#include "llerror.h" +#include "llstring.h" +#include "llwindow.h" +#include "message.h" + // // Constants // const F32 INSTANT_MSG_SIZE = 8.0f; const F32 CHAT_MSG_SIZE = 8.0f; -const LLColor4 MUTED_MSG_COLOR(0.5f, 0.5f, 0.5f, 1.f); -const S32 MAX_CHATTER_COUNT = 16; + // // Global statics @@ -96,20 +96,13 @@ LLColor4 get_text_color(const LLChat& chat); // Member Functions // LLFloaterChat::LLFloaterChat(const LLSD& seed) -: LLFloater(std::string("chat floater"), std::string("FloaterChatRect"), LLStringUtil::null, - RESIZE_YES, 440, 100, DRAG_ON_TOP, MINIMIZE_NO, CLOSE_YES), - mPanel(NULL) + : LLFloater(seed), + mPanel(NULL) { mFactoryMap["chat_panel"] = LLCallbackMap(createChatPanel, NULL); mFactoryMap["active_speakers_panel"] = LLCallbackMap(createSpeakersPanel, NULL); - // do not automatically open singleton floaters (as result of getInstance()) - BOOL no_open = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_chat_history.xml",&getFactoryMap(),no_open); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_chat_history.xml"); - childSetCommitCallback("show mutes",onClickToggleShowMute,this); //show mutes - childSetVisible("Chat History Editor with mute",FALSE); - childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); - setDefaultBtn("Chat"); } LLFloaterChat::~LLFloaterChat() @@ -117,20 +110,13 @@ LLFloaterChat::~LLFloaterChat() // Children all cleaned up by default view destructor. } -void LLFloaterChat::setVisible(BOOL visible) -{ - LLFloater::setVisible( visible ); - - gSavedSettings.setBOOL("ShowChatHistory", visible); -} - void LLFloaterChat::draw() { // enable say and shout only when text available childSetValue("toggle_active_speakers_btn", childIsVisible("active_speakers_panel")); - LLChatBar* chat_barp = getChild("chat_panel", TRUE); + LLChatBar* chat_barp = findChild("chat_panel", TRUE); if (chat_barp) { chat_barp->refresh(); @@ -142,47 +128,18 @@ void LLFloaterChat::draw() BOOL LLFloaterChat::postBuild() { + // Hide the chat overlay when our history is visible. + mVisibleSignal.connect(boost::bind(&LLFloaterChat::updateConsoleVisibility, this)); + mPanel = (LLPanelActiveSpeakers*)getChild("active_speakers_panel"); - LLChatBar* chat_barp = getChild("chat_panel", TRUE); - if (chat_barp) - { - chat_barp->setGestureCombo(getChild( "Gesture")); - } + childSetCommitCallback("show mutes",onClickToggleShowMute,this); //show mutes + childSetVisible("Chat History Editor with mute",FALSE); + childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); + return TRUE; } -// public virtual -void LLFloaterChat::onClose(bool app_quitting) -{ - if (!app_quitting) - { - gSavedSettings.setBOOL("ShowChatHistory", FALSE); - } - setVisible(FALSE); -} - -void LLFloaterChat::onVisibilityChange(BOOL new_visibility) -{ - // Hide the chat overlay when our history is visible. - updateConsoleVisibility(); - - // stop chat history tab from flashing when it appears - if (new_visibility) - { - LLFloaterChatterBox::getInstance()->setFloaterFlashing(this, FALSE); - } - - LLFloater::onVisibilityChange(new_visibility); -} - -void LLFloaterChat::setMinimized(BOOL minimized) -{ - LLFloater::setMinimized(minimized); - updateConsoleVisibility(); -} - - void LLFloaterChat::updateConsoleVisibility() { // determine whether we should show console due to not being visible @@ -215,8 +172,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& { std::string start_line = line.substr(0, chat.mFromName.length() + 1); line = line.substr(chat.mFromName.length() + 1); - const LLStyleSP &sourceStyle = LLStyleMap::instance().lookup(chat.mFromID,chat.mURL); - edit->appendStyledText(start_line, false, prepend_newline, sourceStyle); + edit->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL)); prepend_newline = false; } edit->appendColoredText(line, false, prepend_newline, color); @@ -225,7 +181,7 @@ void add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& void log_chat_text(const LLChat& chat) { std::string histstr; - if (gSavedPerAccountSettings.getBOOL("LogChatTimestamp")) + if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + chat.mText; else histstr = chat.mText; @@ -235,7 +191,7 @@ void log_chat_text(const LLChat& chat) // static void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) { - if ( gSavedPerAccountSettings.getBOOL("LogChat") && log_to_file) + if ( (gSavedPerAccountSettings.getS32("IMLogOptions")!=LOG_IM) && log_to_file) { log_chat_text(chat); } @@ -257,7 +213,7 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) } // could flash the chat button in the status bar here. JC - LLFloaterChat* chat_floater = LLFloaterChat::getInstance(LLSD()); + LLFloaterChat* chat_floater = LLFloaterChat::getInstance(); LLViewerTextEditor* history_editor = chat_floater->getChild("Chat History Editor"); LLViewerTextEditor* history_editor_with_mute = chat_floater->getChild("Chat History Editor with mute"); @@ -295,8 +251,8 @@ void LLFloaterChat::addChatHistory(const LLChat& chat, bool log_to_file) // static void LLFloaterChat::setHistoryCursorAndScrollToEnd() { - LLViewerTextEditor* history_editor = LLFloaterChat::getInstance(LLSD())->getChild("Chat History Editor"); - LLViewerTextEditor* history_editor_with_mute = LLFloaterChat::getInstance(LLSD())->getChild("Chat History Editor with mute"); + LLViewerTextEditor* history_editor = LLFloaterChat::getInstance()->getChild("Chat History Editor"); + LLViewerTextEditor* history_editor_with_mute = LLFloaterChat::getInstance()->getChild("Chat History Editor with mute"); if (history_editor) { @@ -324,8 +280,7 @@ void LLFloaterChat::onClickMute(void *data) LLMute mute(id); mute.setFromDisplayName(name); LLMuteList::getInstance()->add(mute); - - LLFloaterMute::showInstance(); + LLFloaterReg::showInstance("mute"); } //static @@ -368,20 +323,6 @@ void LLFloaterChat::addChat(const LLChat& chat, chat.mChatType == CHAT_TYPE_DEBUG_MSG && !gSavedSettings.getBOOL("ScriptErrorsAsChat"); -#if LL_LCD_COMPILE - // add into LCD displays - if (!invisible_script_debug_chat) - { - if (!from_instant_message) - { - AddNewChatToLCD(chat.mText); - } - else - { - AddNewIMToLCD(chat.mText); - } - } -#endif if (!invisible_script_debug_chat && !chat.mMuted && gConsole @@ -390,33 +331,81 @@ void LLFloaterChat::addChat(const LLChat& chat, F32 size = CHAT_MSG_SIZE; if (chat.mSourceType == CHAT_SOURCE_SYSTEM) { - text_color = gSavedSettings.getColor("SystemChatColor"); + text_color = LLUIColorTable::instance().getColor("SystemChatColor"); } else if(from_instant_message) { - text_color = gSavedSettings.getColor("IMChatColor"); + text_color = LLUIColorTable::instance().getColor("IMChatColor"); size = INSTANT_MSG_SIZE; } + // Disabling the console for 2.0 - SJB +#if 0 // We display anything if it's not an IM. If it's an IM, check pref... if ( !from_instant_message || gSavedSettings.getBOOL("IMInChatConsole") ) { gConsole->addLine(chat.mText, size, text_color); } +#endif } - if(from_instant_message && gSavedPerAccountSettings.getBOOL("LogChatIM")) + if(from_instant_message && (gSavedPerAccountSettings.getS32("IMLogOptions")== LOG_BOTH_TOGETHER)) log_chat_text(chat); if(from_instant_message && gSavedSettings.getBOOL("IMInChatHistory")) addChatHistory(chat,false); - LLTextParser* highlight = LLTextParser::getInstance(); - highlight->triggerAlerts(gAgent.getID(), gAgent.getPositionGlobal(), chat.mText, gViewerWindow->getWindow()); + triggerAlerts(chat.mText); + + // Add the sender to the list of people with which we've recently interacted. + if(chat.mSourceType == CHAT_SOURCE_AGENT && chat.mFromID.notNull()) + LLRecentPeople::instance().add(chat.mFromID); if(!from_instant_message) addChatHistory(chat); } +// Moved from lltextparser.cpp to break llui/llaudio library dependency. +//static +void LLFloaterChat::triggerAlerts(const std::string& text) +{ + LLTextParser* parser = LLTextParser::getInstance(); +// bool spoken=FALSE; + for (S32 i=0;imHighlights.size();i++) + { + LLSD& highlight = parser->mHighlights[i]; + if (parser->findPattern(text,highlight) >= 0 ) + { + if(gAudiop) + { + if ((std::string)highlight["sound_lluuid"] != LLUUID::null.asString()) + { + gAudiop->triggerSound(highlight["sound_lluuid"].asUUID(), + gAgent.getID(), + 1.f, + LLAudioEngine::AUDIO_TYPE_UI, + gAgent.getPositionGlobal() ); + } +/* + if (!spoken) + { + LLTextToSpeech* text_to_speech = NULL; + text_to_speech = LLTextToSpeech::getInstance(); + spoken = text_to_speech->speak((LLString)highlight["voice"],text); + } + */ + } + if (highlight["flash"]) + { + LLWindow* viewer_window = gViewerWindow->getWindow(); + if (viewer_window && viewer_window->getMinimized()) + { + viewer_window->flashIcon(5.f); + } + } + } + } +} + LLColor4 get_text_color(const LLChat& chat) { LLColor4 text_color; @@ -430,37 +419,37 @@ LLColor4 get_text_color(const LLChat& chat) switch(chat.mSourceType) { case CHAT_SOURCE_SYSTEM: - text_color = gSavedSettings.getColor4("SystemChatColor"); + text_color = LLUIColorTable::instance().getColor("SystemChatColor"); break; case CHAT_SOURCE_AGENT: if (chat.mFromID.isNull()) { - text_color = gSavedSettings.getColor4("SystemChatColor"); + text_color = LLUIColorTable::instance().getColor("SystemChatColor"); } else { if(gAgent.getID() == chat.mFromID) { - text_color = gSavedSettings.getColor4("UserChatColor"); + text_color = LLUIColorTable::instance().getColor("UserChatColor"); } else { - text_color = gSavedSettings.getColor4("AgentChatColor"); + text_color = LLUIColorTable::instance().getColor("AgentChatColor"); } } break; case CHAT_SOURCE_OBJECT: if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) { - text_color = gSavedSettings.getColor4("ScriptErrorColor"); + text_color = LLUIColorTable::instance().getColor("ScriptErrorColor"); } else if ( chat.mChatType == CHAT_TYPE_OWNER ) { - text_color = gSavedSettings.getColor4("llOwnerSayChatColor"); + text_color = LLUIColorTable::instance().getColor("llOwnerSayChatColor"); } else { - text_color = gSavedSettings.getColor4("ObjectChatColor"); + text_color = LLUIColorTable::instance().getColor("ObjectChatColor"); } break; default: @@ -485,7 +474,7 @@ LLColor4 get_text_color(const LLChat& chat) //static void LLFloaterChat::loadHistory() { - LLLogChat::loadHistory(std::string("chat"), &chatFromLogFile, (void *)LLFloaterChat::getInstance(LLSD())); + LLLogChat::loadHistory(std::string("chat"), &chatFromLogFile, (void *)LLFloaterChat::getInstance()); } //static @@ -501,6 +490,7 @@ void LLFloaterChat::chatFromLogFile(LLLogChat::ELogLineType type , std::string l { LLChat chat; chat.mText = line; + get_text_color(chat); addChatHistory(chat, FALSE); } break; @@ -531,27 +521,9 @@ void LLFloaterChat::onClickToggleActiveSpeakers(void* userdata) self->childSetVisible("active_speakers_panel", !self->childIsVisible("active_speakers_panel")); } -//static -bool LLFloaterChat::visible(LLFloater* instance, const LLSD& key) -{ - return VisibilityPolicy::visible(instance, key); -} - -//static -void LLFloaterChat::show(LLFloater* instance, const LLSD& key) -{ - VisibilityPolicy::show(instance, key); -} - -//static -void LLFloaterChat::hide(LLFloater* instance, const LLSD& key) -{ - if(instance->getHost()) - { - LLFloaterChatterBox::hideInstance(); - } - else - { - VisibilityPolicy::hide(instance, key); - } -} +//static + LLFloaterChat* LLFloaterChat::getInstance() + { + return LLFloaterReg::getTypedInstance("chat", LLSD()) ; + + } diff --git a/indra/newview/llfloaterchat.h b/indra/newview/llfloaterchat.h index b5393866b8..6ba3165d6a 100644 --- a/indra/newview/llfloaterchat.h +++ b/indra/newview/llfloaterchat.h @@ -40,41 +40,41 @@ #include "llfloater.h" #include "lllogchat.h" -class LLButton; + class LLChat; -class LLComboBox; -class LLLineEditor; -class LLViewerTextEditor; -class LLMessageSystem; -class LLUUID; -class LLCheckBoxCtrl; class LLPanelActiveSpeakers; class LLLogChat; -class LLFloaterChat - : public LLFloater, public LLUISingleton +enum ELogOptions +{ + LOG_CHAT = 0, + LOG_IM = 1, + LOG_BOTH_TOGETHER = 2, + LOG_BOTH_SEPARATE = 3 +}; + +class LLFloaterChat : public LLFloater { public: LLFloaterChat(const LLSD& seed); ~LLFloaterChat(); - virtual void setVisible( BOOL b ); virtual void draw(); virtual BOOL postBuild(); - virtual void onClose(bool app_quitting); - virtual void onVisibilityChange(BOOL cur_visibility); - virtual void setMinimized(BOOL); + void updateConsoleVisibility(); static void setHistoryCursorAndScrollToEnd(); - + + // *TODO:Skinning - move these to LLChat (or LLViewerChat?) // Add chat to console and history list. // Color based on source, type, distance. static void addChat(const LLChat& chat, BOOL from_im = FALSE, BOOL local_agent = FALSE); - // Add chat to history alone. static void addChatHistory(const LLChat& chat, bool log_to_file = true); + static void triggerAlerts(const std::string& text); + static void onClickMute(void *data); static void onClickToggleShowMute(LLUICtrl* caller, void *data); static void onClickToggleActiveSpeakers(void* userdata); @@ -82,12 +82,9 @@ public: static void loadHistory(); static void* createSpeakersPanel(void* data); static void* createChatPanel(void* data); - - // visibility policy for LLUISingleton - static bool visible(LLFloater* instance, const LLSD& key); - static void show(LLFloater* instance, const LLSD& key); - static void hide(LLFloater* instance, const LLSD& key); - + + static LLFloaterChat* getInstance(); // *TODO:Skinning Deprecate + LLPanelActiveSpeakers* mPanel; BOOL mScrolledToEnd; }; diff --git a/indra/newview/llfloaterchatterbox.cpp b/indra/newview/llfloaterchatterbox.cpp index 0fa1aa15e6..05ea800d0e 100644 --- a/indra/newview/llfloaterchatterbox.cpp +++ b/indra/newview/llfloaterchatterbox.cpp @@ -35,6 +35,7 @@ #include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" #include "llfloaterchatterbox.h" #include "lluictrlfactory.h" #include "llfloaterchat.h" @@ -49,12 +50,11 @@ // LLFloaterMyFriends::LLFloaterMyFriends(const LLSD& seed) + : LLFloater(seed) { mFactoryMap["friends_panel"] = LLCallbackMap(LLFloaterMyFriends::createFriendsPanel, NULL); mFactoryMap["groups_panel"] = LLCallbackMap(LLFloaterMyFriends::createGroupsPanel, NULL); - // do not automatically open singleton floaters (as result of getInstance()) - BOOL no_open = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_my_friends.xml", &getFactoryMap(), no_open); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_my_friends.xml"); } LLFloaterMyFriends::~LLFloaterMyFriends() @@ -63,15 +63,19 @@ LLFloaterMyFriends::~LLFloaterMyFriends() BOOL LLFloaterMyFriends::postBuild() { - mTabs = getChild("friends_and_groups"); - return TRUE; } - -void LLFloaterMyFriends::onClose(bool app_quitting) +void LLFloaterMyFriends::onOpen(const LLSD& key) { - setVisible(FALSE); + if (key.asString() == "friends") + { + childShowTab("friends_and_groups", "friends_panel"); + } + else if (key.asString() == "groups") + { + childShowTab("friends_and_groups", "groups_panel"); + } } //static @@ -86,47 +90,67 @@ void* LLFloaterMyFriends::createGroupsPanel(void* data) return new LLPanelGroups(); } +//static +LLFloaterMyFriends* LLFloaterMyFriends::getInstance() +{ + return LLFloaterReg::getTypedInstance("contacts", "friends") ; +} + // // LLFloaterChatterBox // -LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) : +LLFloaterChatterBox::LLFloaterChatterBox(const LLSD& seed) +: LLMultiFloater(seed), mActiveVoiceFloater(NULL) { mAutoResize = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_chatterbox.xml", NULL, FALSE); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_chatterbox.xml", FALSE); +} + +LLFloaterChatterBox::~LLFloaterChatterBox() +{ +} + +BOOL LLFloaterChatterBox::postBuild() +{ + mVisibleSignal.connect(boost::bind(&LLFloaterChatterBox::onVisibilityChange, this, _2)); + if (gSavedSettings.getBOOL("ContactsTornOff")) { - LLFloaterMyFriends* floater_contacts = LLFloaterMyFriends::getInstance(0); - // add then remove to set up relationship for re-attach - addFloater(floater_contacts, FALSE); - removeFloater(floater_contacts); - // reparent to floater view - gFloaterView->addChild(floater_contacts); + LLFloaterMyFriends* floater_contacts = LLFloaterMyFriends::getInstance(); + if(floater_contacts) + { + // add then remove to set up relationship for re-attach + addFloater(floater_contacts, FALSE); + removeFloater(floater_contacts); + // reparent to floater view + gFloaterView->addChild(floater_contacts); + } } else { - addFloater(LLFloaterMyFriends::getInstance(0), TRUE); + addFloater(LLFloaterMyFriends::getInstance(), TRUE); } if (gSavedSettings.getBOOL("ChatHistoryTornOff")) { LLFloaterChat* floater_chat = LLFloaterChat::getInstance(); - // add then remove to set up relationship for re-attach - addFloater(floater_chat, FALSE); - removeFloater(floater_chat); - // reparent to floater view - gFloaterView->addChild(floater_chat); + if(floater_chat) + { + // add then remove to set up relationship for re-attach + addFloater(floater_chat, FALSE); + removeFloater(floater_chat); + // reparent to floater view + gFloaterView->addChild(floater_chat); + } } else { - addFloater(LLFloaterChat::getInstance(LLSD()), FALSE); + addFloater(LLFloaterChat::getInstance(), FALSE); } mTabContainer->lockTabs(); -} - -LLFloaterChatterBox::~LLFloaterChatterBox() -{ + return TRUE; } BOOL LLFloaterChatterBox::handleKeyHere(KEY key, MASK mask) @@ -139,13 +163,13 @@ BOOL LLFloaterChatterBox::handleKeyHere(KEY key, MASK mask) { if (floater->isCloseable()) { - floater->close(); + floater->closeFloater(); } else { // close chatterbox window if frontmost tab is reserved, non-closeable tab // such as contacts or near me - close(); + closeFloater(); } } return TRUE; @@ -200,26 +224,38 @@ void LLFloaterChatterBox::draw() LLMultiFloater::draw(); } -void LLFloaterChatterBox::onOpen() +void LLFloaterChatterBox::onOpen(const LLSD& key) { - gSavedSettings.setBOOL("ShowCommunicate", TRUE); + //*TODO:Skinning show the session id associated with key + if (key.asString() == "local") + { + LLFloaterChat* chat = LLFloaterReg::findTypedInstance("chat"); + chat->openFloater(); + } + else if (key.isDefined()) + { + LLFloaterIMPanel* impanel = gIMMgr->findFloaterBySession(key.asUUID()); + if (impanel) + { + impanel->openFloater(); + } + } } -void LLFloaterChatterBox::onClose(bool app_quitting) +void LLFloaterChatterBox::onVisibilityChange ( const LLSD& new_visibility ) { - setVisible(FALSE); - gSavedSettings.setBOOL("ShowCommunicate", FALSE); -} - -void LLFloaterChatterBox::setMinimized(BOOL minimized) -{ - LLFloater::setMinimized(minimized); // HACK: potentially need to toggle console - LLFloaterChat::getInstance()->updateConsoleVisibility(); + LLFloaterChat* instance = LLFloaterChat::getInstance(); + if(instance) + { + instance->updateConsoleVisibility(); + } } void LLFloaterChatterBox::removeFloater(LLFloater* floaterp) { + if(!floaterp) return; + if (floaterp->getName() == "chat floater") { // only my friends floater now locked @@ -241,10 +277,16 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point) { + if(!floaterp) return; + S32 num_locked_tabs = mTabContainer->getNumLockedTabs(); // already here - if (floaterp->getHost() == this) return; + if (floaterp->getHost() == this) + { + openFloater(floaterp->getKey()); + return; + } // make sure my friends and chat history both locked when re-attaching chat history if (floaterp->getName() == "chat floater") @@ -281,6 +323,7 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp, else { LLMultiFloater::addFloater(floaterp, select_added_floater, insertion_point); + // openFloater(floaterp->getKey()); } // make sure active voice icon shows up for new tab @@ -290,6 +333,12 @@ void LLFloaterChatterBox::addFloater(LLFloater* floaterp, } } +//static +LLFloaterChatterBox* LLFloaterChatterBox::getInstance() +{ + return LLFloaterReg::getTypedInstance("communicate", LLSD()) ; +} + //static LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater() { @@ -300,11 +349,12 @@ LLFloater* LLFloaterChatterBox::getCurrentVoiceFloater() if (LLVoiceChannelProximal::getInstance() == LLVoiceChannel::getCurrentVoiceChannel()) { // show near me tab if in proximal channel - return LLFloaterChat::getInstance(LLSD()); + return LLFloaterChat::getInstance(); } else { - LLFloaterChatterBox* floater = LLFloaterChatterBox::getInstance(LLSD()); + LLFloaterChatterBox* floater = LLFloaterChatterBox::getInstance(); + if(!floater) return NULL; // iterator over all IM tabs (skip friends and near me) for (S32 i = 0; i < floater->getFloaterCount(); i++) { diff --git a/indra/newview/llfloaterchatterbox.h b/indra/newview/llfloaterchatterbox.h index 3adbd14370..3929e6e36c 100644 --- a/indra/newview/llfloaterchatterbox.h +++ b/indra/newview/llfloaterchatterbox.h @@ -42,125 +42,45 @@ class LLTabContainer; -class LLFloaterChatterBox : public LLMultiFloater, public LLUISingleton +class LLFloaterChatterBox : public LLMultiFloater { public: LLFloaterChatterBox(const LLSD& seed); virtual ~LLFloaterChatterBox(); - + + /*virtual*/ BOOL postBuild(); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); /*virtual*/ void draw(); - /*virtual*/ void onOpen(); - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ void setMinimized(BOOL minimized); + /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void removeFloater(LLFloater* floaterp); /*virtual*/ void addFloater(LLFloater* floaterp, BOOL select_added_floater, LLTabContainer::eInsertionPoint insertion_point = LLTabContainer::END); + static LLFloaterChatterBox* getInstance(); // *TODO:Skinning Deprecate static LLFloater* getCurrentVoiceFloater(); - // visibility policy for LLUISingleton - static bool visible(LLFloater* instance, const LLSD& key) - { - LLFloater* floater_to_check = ((LLFloaterChatterBox*)instance)->getFloater(key); - - if (floater_to_check) - { - return floater_to_check->isInVisibleChain(); - } - - // otherwise use default visibility rule for chatterbox - return VisibilityPolicy::visible(instance, key); - } - - static void show(LLFloater* instance, const LLSD& key) - { - LLFloater* floater_to_show = ((LLFloaterChatterBox*)instance)->getFloater(key); - VisibilityPolicy::show(instance, key); - - if (floater_to_show) - { - floater_to_show->open(); - } - } - - static void hide(LLFloater* instance, const LLSD& key) - { - VisibilityPolicy::hide(instance, key); - } - -private: - LLFloater* getFloater(const LLSD& key) - { - LLFloater* floater = NULL; - - //try to show requested session - LLUUID session_id = key.asUUID(); - if (session_id.notNull()) - { - floater = LLIMMgr::getInstance()->findFloaterBySession(session_id); - } - - // if TRUE, show tab for active voice channel, otherwise, just show last tab - if (key.asBoolean()) - { - floater = getCurrentVoiceFloater(); - } - - return floater; - } - protected: + void onVisibilityChange ( const LLSD& new_visibility ); + LLFloater* mActiveVoiceFloater; }; -class LLFloaterMyFriends : public LLFloater, public LLUISingleton +class LLFloaterMyFriends : public LLFloater { public: LLFloaterMyFriends(const LLSD& seed); virtual ~LLFloaterMyFriends(); - virtual BOOL postBuild(); - - void onClose(bool app_quitting); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + static LLFloaterMyFriends* getInstance(); // *TODO:Skinning Deprecate + static void* createFriendsPanel(void* data); static void* createGroupsPanel(void* data); - - // visibility policy for LLUISingleton - static bool visible(LLFloater* instance, const LLSD& key) - { - LLFloaterMyFriends* floaterp = (LLFloaterMyFriends*)instance; - return floaterp->isInVisibleChain() && floaterp->mTabs->getCurrentPanelIndex() == key.asInteger(); - } - - static void show(LLFloater* instance, const LLSD& key) - { - VisibilityPolicy::show(instance, key); - // garbage values in id will be interpreted as 0, or the friends tab - ((LLFloaterMyFriends*)instance)->mTabs->selectTab(key); - } - - static void hide(LLFloater* instance, const LLSD& key) - { - if (visible(instance, key)) - { - if(instance->getHost()) - { - LLFloaterChatterBox::hideInstance(); - } - else - { - VisibilityPolicy::hide(instance, key); - } - } - } - -protected: - LLTabContainer* mTabs; }; #endif // LL_LLFLOATERCHATTERBOX_H diff --git a/indra/newview/llfloatercolorpicker.cpp b/indra/newview/llfloatercolorpicker.cpp index f82d692dd3..8e385fca78 100644 --- a/indra/newview/llfloatercolorpicker.cpp +++ b/indra/newview/llfloatercolorpicker.cpp @@ -32,11 +32,15 @@ #include "llviewerprecompiledheaders.h" -#include -#include - #include "llfloatercolorpicker.h" +// Viewer project includes +#include "lltoolmgr.h" +#include "lltoolpipette.h" +#include "llviewercontrol.h" +#include "llworld.h" + +// Linden library includes #include "llfontgl.h" #include "llsys.h" #include "llgl.h" @@ -47,23 +51,22 @@ #include "lllineeditor.h" #include "v4coloru.h" #include "llbutton.h" -#include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llviewerwindow.h" #include "llgl.h" -#include "llmemory.h" +#include "llpointer.h" #include "llimage.h" #include "llmousehandler.h" -#include "llimagegl.h" #include "llglheaders.h" #include "llcheckboxctrl.h" -#include "llworld.h" #include "lltextbox.h" #include "lluiconstants.h" #include "llfocusmgr.h" -#include "lltoolmgr.h" -#include "lltoolpipette.h" #include "lldraghandle.h" +#include "llwindow.h" + +// System includes +#include +#include const F32 CONTEXT_CONE_IN_ALPHA = 0.0f; const F32 CONTEXT_CONE_OUT_ALPHA = 1.f; @@ -75,11 +78,8 @@ const F32 CONTEXT_FADE_TIME = 0.08f; // ////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// -// default ctor -LLFloaterColorPicker:: -LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate ) - : LLFloater (std::string("Color Picker Floater")), +LLFloaterColorPicker::LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate ) + : LLFloater(LLSD()), mComponents ( 3 ), mMouseDownInLumRegion ( FALSE ), mMouseDownInHueRegion ( FALSE ), @@ -113,6 +113,9 @@ LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate ) mCanApplyImmediately ( show_apply_immediate ), mContextConeOpacity ( 0.f ) { + // build the majority of the gui using the factory builder + LLUICtrlFactory::getInstance()->buildFloater ( this, "floater_color_picker.xml", NULL ); + // create user interface for this picker createUI (); @@ -123,10 +126,7 @@ LLFloaterColorPicker (LLColorSwatchCtrl* swatch, BOOL show_apply_immediate ) } } -////////////////////////////////////////////////////////////////////////////// -// dtor -LLFloaterColorPicker:: -~LLFloaterColorPicker() +LLFloaterColorPicker::~LLFloaterColorPicker() { // destroy the UI we created destroyUI (); @@ -134,14 +134,8 @@ LLFloaterColorPicker:: ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -createUI () +void LLFloaterColorPicker::createUI () { - // build the majority of the gui using the factory builder - LLUICtrlFactory::getInstance()->buildFloater ( this, "floater_color_picker.xml" ); - setVisible ( FALSE ); - // create RGB type area (not really RGB but it's got R,G & B in it.,.. LLPointer raw = new LLImageRaw ( mRGBViewerImageWidth, mRGBViewerImageHeight, mComponents ); @@ -165,7 +159,7 @@ createUI () * ( bits + x + y * linesize + 2 ) = ( U8 )( bVal * 255.0f ); } } - mRGBImage = new LLImageGL ( (LLImageRaw*)raw, FALSE ); + mRGBImage = LLViewerTextureManager::getLocalTexture( (LLImageRaw*)raw, FALSE ); gGL.getTexUnit(0)->bind(mRGBImage); mRGBImage->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -177,19 +171,17 @@ createUI () // argh! const std::string s ( codec.str () ); - mPalette.push_back ( new LLColor4 ( gSavedSettings.getColor4 ( s ) ) ); + mPalette.push_back ( new LLColor4 ( LLUIColorTable::instance().getColor ( s ) ) ); } } ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -showUI () +void LLFloaterColorPicker::showUI () { setVisible ( TRUE ); setFocus ( TRUE ); - open(); /*Flawfinder: ignore*/ + openFloater(getKey()); // HACK: if system color picker is required - close the SL one we made and use default system dialog if ( gSavedSettings.getBOOL ( "UseDefaultColorPicker" ) ) @@ -203,7 +195,7 @@ showUI () { LLColor4 curCol = swatch->get (); send_agent_pause(); - gViewerWindow->getWindow ()->dialog_color_picker ( &curCol [ 0 ], &curCol [ 1 ], &curCol [ 2 ] ); + getWindow()->dialogColorPicker( &curCol [ 0 ], &curCol [ 1 ], &curCol [ 2 ] ); send_agent_resume(); setOrigRgb ( curCol [ 0 ], curCol [ 1 ], curCol [ 2 ] ); @@ -212,36 +204,30 @@ showUI () LLColorSwatchCtrl::onColorChanged ( swatch, LLColorSwatchCtrl::COLOR_CHANGE ); } - close(); + closeFloater(); } } ////////////////////////////////////////////////////////////////////////////// // called after the dialog is rendered -BOOL -LLFloaterColorPicker:: -postBuild() +BOOL LLFloaterColorPicker::postBuild() { mCancelBtn = getChild( "cancel_btn" ); - mCancelBtn->setClickedCallback ( onClickCancel ); - mCancelBtn->setCallbackUserData ( this ); + mCancelBtn->setClickedCallback ( onClickCancel, this ); mSelectBtn = getChild( "select_btn"); - mSelectBtn->setClickedCallback ( onClickSelect ); - mSelectBtn->setCallbackUserData ( this ); + mSelectBtn->setClickedCallback ( onClickSelect, this ); mSelectBtn->setFocus ( TRUE ); mPipetteBtn = getChild("color_pipette" ); mPipetteBtn->setImages(std::string("eye_button_inactive.tga"), std::string("eye_button_active.tga")); - mPipetteBtn->setClickedCallback( onClickPipette ); - mPipetteBtn->setCallbackUserData ( this ); + mPipetteBtn->setCommitCallback( boost::bind(&LLFloaterColorPicker::onClickPipette, this )); mApplyImmediateCheck = getChild("apply_immediate"); mApplyImmediateCheck->set(gSavedSettings.getBOOL("ApplyColorImmediately")); - mApplyImmediateCheck->setCommitCallback(onImmediateCheck); - mApplyImmediateCheck->setCallbackUserData(this); + mApplyImmediateCheck->setCommitCallback(onImmediateCheck, this); childSetCommitCallback("rspin", onTextCommit, (void*)this ); childSetCommitCallback("gspin", onTextCommit, (void*)this ); @@ -250,18 +236,15 @@ postBuild() childSetCommitCallback("sspin", onTextCommit, (void*)this ); childSetCommitCallback("lspin", onTextCommit, (void*)this ); + LLToolPipette::getInstance()->setToolSelectCallback(boost::bind(&LLFloaterColorPicker::onColorSelect, this, _1)); + return TRUE; } ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -initUI ( F32 rValIn, F32 gValIn, F32 bValIn ) +void LLFloaterColorPicker::initUI ( F32 rValIn, F32 gValIn, F32 bValIn ) { - // start catching lose-focus events from entry widgets - enableTextCallbacks ( TRUE ); - // under some circumstances, we get rogue values that can be calmed by clamping... rValIn = llclamp ( rValIn, 0.0f, 1.0f ); gValIn = llclamp ( gValIn, 0.0f, 1.0f ); @@ -279,9 +262,7 @@ initUI ( F32 rValIn, F32 gValIn, F32 bValIn ) ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -destroyUI () +void LLFloaterColorPicker::destroyUI () { // shut down pipette tool if active stopUsingPipette(); @@ -305,9 +286,7 @@ destroyUI () ////////////////////////////////////////////////////////////////////////////// // -F32 -LLFloaterColorPicker:: -hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) +F32 LLFloaterColorPicker::hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) { if ( valHUeIn < 0.0f ) valHUeIn += 1.0f; if ( valHUeIn > 1.0f ) valHUeIn -= 1.0f; @@ -319,9 +298,7 @@ hueToRgb ( F32 val1In, F32 val2In, F32 valHUeIn ) ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -hslToRgb ( F32 hValIn, F32 sValIn, F32 lValIn, F32& rValOut, F32& gValOut, F32& bValOut ) +void LLFloaterColorPicker::hslToRgb ( F32 hValIn, F32 sValIn, F32 lValIn, F32& rValOut, F32& gValOut, F32& bValOut ) { if ( sValIn < 0.00001f ) { @@ -349,9 +326,7 @@ hslToRgb ( F32 hValIn, F32 sValIn, F32 lValIn, F32& rValOut, F32& gValOut, F32& ////////////////////////////////////////////////////////////////////////////// // mutator for original RGB value -void -LLFloaterColorPicker:: -setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn ) +void LLFloaterColorPicker::setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn ) { origR = origRIn; origG = origGIn; @@ -360,9 +335,7 @@ setOrigRgb ( F32 origRIn, F32 origGIn, F32 origBIn ) ////////////////////////////////////////////////////////////////////////////// // accessor for original RGB value -void -LLFloaterColorPicker:: -getOrigRgb ( F32& origROut, F32& origGOut, F32& origBOut ) +void LLFloaterColorPicker::getOrigRgb ( F32& origROut, F32& origGOut, F32& origBOut ) { origROut = origR; origGOut = origG; @@ -371,9 +344,7 @@ getOrigRgb ( F32& origROut, F32& origGOut, F32& origBOut ) ////////////////////////////////////////////////////////////////////////////// // mutator for current RGB value -void -LLFloaterColorPicker:: -setCurRgb ( F32 curRIn, F32 curGIn, F32 curBIn ) +void LLFloaterColorPicker::setCurRgb ( F32 curRIn, F32 curGIn, F32 curBIn ) { // save current RGB curR = curRIn; @@ -383,19 +354,13 @@ setCurRgb ( F32 curRIn, F32 curGIn, F32 curBIn ) // update corresponding HSL values and LLColor3(curRIn, curGIn, curBIn).calcHSL(&curH, &curS, &curL); - // color changed so update text fields (fixes SL-16968) - // HACK: turn off the call back wilst we update the text or we recurse ourselves into oblivion - // CP: this was required when I first wrote the code but this may not be necessary anymore - leaving it there just in case - enableTextCallbacks( FALSE ); + // color changed so update text fields updateTextEntry(); - enableTextCallbacks( TRUE ); } ////////////////////////////////////////////////////////////////////////////// // accessor for current RGB value -void -LLFloaterColorPicker:: -getCurRgb ( F32& curROut, F32& curGOut, F32& curBOut ) +void LLFloaterColorPicker::getCurRgb ( F32& curROut, F32& curGOut, F32& curBOut ) { curROut = curR; curGOut = curG; @@ -404,9 +369,7 @@ getCurRgb ( F32& curROut, F32& curGOut, F32& curBOut ) ////////////////////////////////////////////////////////////////////////////// // mutator for current HSL value -void -LLFloaterColorPicker:: -setCurHsl ( F32 curHIn, F32 curSIn, F32 curLIn ) +void LLFloaterColorPicker::setCurHsl ( F32 curHIn, F32 curSIn, F32 curLIn ) { // save current HSL curH = curHIn; @@ -419,9 +382,7 @@ setCurHsl ( F32 curHIn, F32 curSIn, F32 curLIn ) ////////////////////////////////////////////////////////////////////////////// // accessor for current HSL value -void -LLFloaterColorPicker:: -getCurHsl ( F32& curHOut, F32& curSOut, F32& curLOut ) +void LLFloaterColorPicker::getCurHsl ( F32& curHOut, F32& curSOut, F32& curLOut ) { curHOut = curH; curSOut = curS; @@ -430,9 +391,7 @@ getCurHsl ( F32& curHOut, F32& curSOut, F32& curLOut ) ////////////////////////////////////////////////////////////////////////////// // called when 'cancel' clicked -void -LLFloaterColorPicker:: -onClickCancel ( void* data ) +void LLFloaterColorPicker::onClickCancel ( void* data ) { if (data) { @@ -441,16 +400,14 @@ onClickCancel ( void* data ) if ( self ) { self->cancelSelection (); - self->close(); + self->closeFloater(); } } } ////////////////////////////////////////////////////////////////////////////// // called when 'select' clicked -void -LLFloaterColorPicker:: -onClickSelect ( void* data ) +void LLFloaterColorPicker::onClickSelect ( void* data ) { if (data) { @@ -460,36 +417,28 @@ onClickSelect ( void* data ) { // apply to selection LLColorSwatchCtrl::onColorChanged ( self->getSwatch (), LLColorSwatchCtrl::COLOR_SELECT ); - self->close(); + self->closeFloater(); } } } -void LLFloaterColorPicker::onClickPipette( void* data ) +void LLFloaterColorPicker::onClickPipette( ) { - LLFloaterColorPicker* self = ( LLFloaterColorPicker* )data; - - if ( self) + BOOL pipette_active = mPipetteBtn->getToggleState(); + pipette_active = !pipette_active; + if (pipette_active) { - BOOL pipette_active = self->mPipetteBtn->getToggleState(); - pipette_active = !pipette_active; - if (pipette_active) - { - LLToolPipette::getInstance()->setSelectCallback(onColorSelect, self); - LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance()); - } - else - { - LLToolMgr::getInstance()->clearTransientTool(); - } + LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance()); + } + else + { + LLToolMgr::getInstance()->clearTransientTool(); } } ////////////////////////////////////////////////////////////////////////////// // called when 'text is committed' - i,e. focus moves from a text field -void -LLFloaterColorPicker:: -onTextCommit ( LLUICtrl* ctrl, void* data ) +void LLFloaterColorPicker::onTextCommit ( LLUICtrl* ctrl, void* data ) { if ( data ) { @@ -515,16 +464,12 @@ void LLFloaterColorPicker::onImmediateCheck( LLUICtrl* ctrl, void* data) } } -void LLFloaterColorPicker::onColorSelect( const LLTextureEntry& te, void *data ) +void LLFloaterColorPicker::onColorSelect( const LLTextureEntry& te ) { - LLFloaterColorPicker* self = (LLFloaterColorPicker*)data; - if (self) + setCurRgb(te.getColor().mV[VRED], te.getColor().mV[VGREEN], te.getColor().mV[VBLUE]); + if (mApplyImmediateCheck->get()) { - self->setCurRgb(te.getColor().mV[VRED], te.getColor().mV[VGREEN], te.getColor().mV[VBLUE]); - if (self->mApplyImmediateCheck->get()) - { - LLColorSwatchCtrl::onColorChanged ( self->getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE ); - } + LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE ); } } @@ -673,9 +618,7 @@ void LLFloaterColorPicker::draw() ////////////////////////////////////////////////////////////////////////////// // find a complimentary color to the one passed in that can be used to highlight -const LLColor4& -LLFloaterColorPicker:: -getComplimentaryColor ( const LLColor4& backgroundColor ) +const LLColor4& LLFloaterColorPicker::getComplimentaryColor ( const LLColor4& backgroundColor ) { // going to base calculation on luminance F32 hVal, sVal, lVal; @@ -695,9 +638,7 @@ getComplimentaryColor ( const LLColor4& backgroundColor ) ////////////////////////////////////////////////////////////////////////////// // draw color palette -void -LLFloaterColorPicker:: -drawPalette () +void LLFloaterColorPicker::drawPalette () { S32 curEntry = 0; @@ -748,9 +689,7 @@ drawPalette () ////////////////////////////////////////////////////////////////////////////// // update text entry values for RGB/HSL (can't be done in ::draw () since this overwrites input -void -LLFloaterColorPicker:: -updateTextEntry () +void LLFloaterColorPicker::updateTextEntry () { // set values in spinners childSetValue("rspin", ( getCurR () * 255.0f ) ); @@ -761,38 +700,9 @@ updateTextEntry () childSetValue("lspin", ( getCurL () * 100.0f ) ); } -////////////////////////////////////////////////////////////////////////////// -// turns on or off text entry commit call backs -void -LLFloaterColorPicker:: -enableTextCallbacks ( BOOL stateIn ) -{ - if ( stateIn ) - { - childSetCommitCallback("rspin", onTextCommit, (void*)this ); - childSetCommitCallback("gspin", onTextCommit, (void*)this ); - childSetCommitCallback("bspin", onTextCommit, (void*)this ); - childSetCommitCallback("hspin", onTextCommit, (void*)this ); - childSetCommitCallback("sspin", onTextCommit, (void*)this ); - childSetCommitCallback("lspin", onTextCommit, (void*)this ); - } - else - { - childSetCommitCallback("rspin", 0, (void*)this ); - childSetCommitCallback("gspin", 0, (void*)this ); - childSetCommitCallback("bspin", 0, (void*)this ); - childSetCommitCallback("hspin", 0, (void*)this ); - childSetCommitCallback("sspin", 0, (void*)this ); - childSetCommitCallback("lspin", 0, (void*)this ); - } -} - - ////////////////////////////////////////////////////////////////////////////// // -void -LLFloaterColorPicker:: -onTextEntryChanged ( LLUICtrl* ctrl ) +void LLFloaterColorPicker::onTextEntryChanged ( LLUICtrl* ctrl ) { // value in RGB boxes changed std::string name = ctrl->getName(); @@ -821,10 +731,7 @@ onTextEntryChanged ( LLUICtrl* ctrl ) // update current RGB (and implicitly HSL) setCurRgb ( rVal, gVal, bVal ); - // HACK: turn off the call back wilst we update the text or we recurse ourselves into oblivion - enableTextCallbacks ( FALSE ); updateTextEntry (); - enableTextCallbacks ( TRUE ); } else // value in HSL boxes changed @@ -847,10 +754,7 @@ onTextEntryChanged ( LLUICtrl* ctrl ) // update current HSL (and implicitly RGB) setCurHsl ( hVal, sVal, lVal ); - // HACK: turn off the call back wilst we update the text or we recurse ourselves into oblivion - enableTextCallbacks ( FALSE ); updateTextEntry (); - enableTextCallbacks ( TRUE ); } if (mApplyImmediateCheck->get()) @@ -861,9 +765,7 @@ onTextEntryChanged ( LLUICtrl* ctrl ) ////////////////////////////////////////////////////////////////////////////// // -BOOL -LLFloaterColorPicker:: -updateRgbHslFromPoint ( S32 xPosIn, S32 yPosIn ) +BOOL LLFloaterColorPicker::updateRgbHslFromPoint ( S32 xPosIn, S32 yPosIn ) { if ( xPosIn >= mRGBViewerImageLeft && xPosIn <= mRGBViewerImageLeft + mRGBViewerImageWidth && @@ -899,9 +801,7 @@ updateRgbHslFromPoint ( S32 xPosIn, S32 yPosIn ) ////////////////////////////////////////////////////////////////////////////// // -BOOL -LLFloaterColorPicker:: -handleMouseDown ( S32 x, S32 y, MASK mask ) +BOOL LLFloaterColorPicker::handleMouseDown ( S32 x, S32 y, MASK mask ) { // make it the frontmost gFloaterView->bringToFront(this); @@ -987,10 +887,7 @@ handleMouseDown ( S32 x, S32 y, MASK mask ) LLColorSwatchCtrl::onColorChanged ( getSwatch (), LLColorSwatchCtrl::COLOR_CHANGE ); } - // HACK: turn off the call back wilst we update the text or we recurse ourselves into oblivion - enableTextCallbacks ( FALSE ); updateTextEntry (); - enableTextCallbacks ( TRUE ); } return TRUE; @@ -1003,9 +900,7 @@ handleMouseDown ( S32 x, S32 y, MASK mask ) ////////////////////////////////////////////////////////////////////////////// // -BOOL -LLFloaterColorPicker:: -handleHover ( S32 x, S32 y, MASK mask ) +BOOL LLFloaterColorPicker::handleHover ( S32 x, S32 y, MASK mask ) { // if we're the front most window if ( isFrontmost () ) @@ -1071,19 +966,9 @@ handleHover ( S32 x, S32 y, MASK mask ) return LLFloater::handleHover ( x, y, mask ); } -void LLFloaterColorPicker::onClose(bool app_quitting) -{ - //RN: this is consistent with texture picker in that closing the window leaves the current selection - // to change this to "close to cancel", uncomment the following line - //cancelSelection(); - LLFloater::onClose(app_quitting); -} - ////////////////////////////////////////////////////////////////////////////// // reverts state once mouse button is released -BOOL -LLFloaterColorPicker:: -handleMouseUp ( S32 x, S32 y, MASK mask ) +BOOL LLFloaterColorPicker::handleMouseUp ( S32 x, S32 y, MASK mask ) { getWindow()->setCursor ( UI_CURSOR_ARROW ); @@ -1130,7 +1015,7 @@ handleMouseUp ( S32 x, S32 y, MASK mask ) std::ostringstream codec; codec << "ColorPaletteEntry" << std::setfill ( '0' ) << std::setw ( 2 ) << curEntry + 1; const std::string s ( codec.str () ); - gSavedSettings.setColor4( s, *mPalette [ curEntry ] ); + LLUIColorTable::instance().setColor(s, *mPalette [ curEntry ] ); } } @@ -1158,16 +1043,11 @@ handleMouseUp ( S32 x, S32 y, MASK mask ) ////////////////////////////////////////////////////////////////////////////// // cancel current color selection, revert to original and close picker -void -LLFloaterColorPicker:: -cancelSelection () +void LLFloaterColorPicker::cancelSelection () { // restore the previous color selection setCurRgb ( getOrigR (), getOrigG (), getOrigB () ); - // we're going away and when we do and the entry widgets lose focus, they do bad things so turn them off - enableTextCallbacks ( FALSE ); - // update in world item with original color via current swatch LLColorSwatchCtrl::onColorChanged( getSwatch(), LLColorSwatchCtrl::COLOR_CANCEL ); diff --git a/indra/newview/llfloatercolorpicker.h b/indra/newview/llfloatercolorpicker.h index 7c8d36a7c7..a16cde7f10 100644 --- a/indra/newview/llfloatercolorpicker.h +++ b/indra/newview/llfloatercolorpicker.h @@ -36,7 +36,7 @@ #include #include "llfloater.h" -#include "llmemory.h" +#include "llpointer.h" #include "llcolorswatch.h" #include "llspinctrl.h" #include "lltextureentry.h" @@ -61,7 +61,6 @@ class LLFloaterColorPicker virtual BOOL handleMouseUp ( S32 x, S32 y, MASK mask ); virtual BOOL handleHover ( S32 x, S32 y, MASK mask ); virtual void onMouseCaptureLost(); - virtual void onClose(bool app_quitting); // implicit methods void createUI (); @@ -123,14 +122,11 @@ class LLFloaterColorPicker // callbacks static void onClickCancel ( void* data ); static void onClickSelect ( void* data ); - static void onClickPipette ( void* data ); + void onClickPipette ( ); static void onTextCommit ( LLUICtrl* ctrl, void* data ); static void onImmediateCheck ( LLUICtrl* ctrl, void* data ); - static void onColorSelect( const LLTextureEntry& te, void *data ); + void onColorSelect( const LLTextureEntry& te ); private: - // turns on or off text entry commit call backs - void enableTextCallbacks ( BOOL stateIn ); - // draws color selection palette void drawPalette (); @@ -179,7 +175,7 @@ class LLFloaterColorPicker const S32 mPaletteRegionHeight; // image used to compose color grid - LLPointer mRGBImage; + LLPointer mRGBImage; // current swatch in use LLColorSwatchCtrl* mSwatch; diff --git a/indra/newview/llfloaterdaycycle.cpp b/indra/newview/llfloaterdaycycle.cpp index 58876a8dec..7f3b988dfe 100644 --- a/indra/newview/llfloaterdaycycle.cpp +++ b/indra/newview/llfloaterdaycycle.cpp @@ -59,19 +59,23 @@ #include "llfloaterwindlight.h" -LLFloaterDayCycle* LLFloaterDayCycle::sDayCycle = NULL; std::map LLFloaterDayCycle::sSliderToKey; const F32 LLFloaterDayCycle::sHoursPerDay = 24.0f; -LLFloaterDayCycle::LLFloaterDayCycle() : LLFloater(std::string("Day Cycle Floater")) +LLFloaterDayCycle::LLFloaterDayCycle(const LLSD& key) +: LLFloater(key) +{ + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_day_cycle_options.xml"); +} + +BOOL LLFloaterDayCycle::postBuild() { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_day_cycle_options.xml"); - // add the combo boxes LLComboBox* keyCombo = getChild("WLKeyPresets"); if(keyCombo != NULL) { + keyCombo->removeall(); std::map::iterator mIt = LLWLParamManager::instance()->mParamList.begin(); for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) @@ -90,23 +94,25 @@ LLFloaterDayCycle::LLFloaterDayCycle() : LLFloater(std::string("Day Cycle Floate // load it up initCallbacks(); + + syncMenu(); + syncSliderTrack(); + + return TRUE; } LLFloaterDayCycle::~LLFloaterDayCycle() { } -void LLFloaterDayCycle::onClickHelp(void* data) +void LLFloaterDayCycle::onClickHelp(std::string xml_alert) { - LLFloaterDayCycle* self = LLFloaterDayCycle::instance(); - - std::string xml_alert = *(std::string *) data; - LLNotifications::instance().add(self->contextualNotification(xml_alert)); + LLNotifications::instance().add(contextualNotification(xml_alert)); } void LLFloaterDayCycle::initHelpBtn(const std::string& name, const std::string& xml_alert) { - childSetAction(name, onClickHelp, new std::string(xml_alert)); + getChild(name)->setClickedCallback(boost::bind(&LLFloaterDayCycle::onClickHelp, this, xml_alert)); } void LLFloaterDayCycle::initCallbacks(void) @@ -114,24 +120,24 @@ void LLFloaterDayCycle::initCallbacks(void) initHelpBtn("WLDayCycleHelp", "HelpDayCycle"); // WL Day Cycle - childSetCommitCallback("WLTimeSlider", onTimeSliderMoved, NULL); - childSetCommitCallback("WLDayCycleKeys", onKeyTimeMoved, NULL); - childSetCommitCallback("WLCurKeyHour", onKeyTimeChanged, NULL); - childSetCommitCallback("WLCurKeyMin", onKeyTimeChanged, NULL); - childSetCommitCallback("WLKeyPresets", onKeyPresetChanged, NULL); + getChild("WLTimeSlider")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeSliderMoved, this, _1)); + getChild("WLDayCycleKeys")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeMoved, this, _1)); + getChild("WLCurKeyHour")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeChanged, this, _1)); + getChild("WLCurKeyMin")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyTimeChanged, this, _1)); + getChild("WLKeyPresets")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onKeyPresetChanged, this, _1)); - childSetCommitCallback("WLLengthOfDayHour", onTimeRateChanged, NULL); - childSetCommitCallback("WLLengthOfDayMin", onTimeRateChanged, NULL); - childSetCommitCallback("WLLengthOfDaySec", onTimeRateChanged, NULL); - childSetAction("WLUseLindenTime", onUseLindenTime, NULL); - childSetAction("WLAnimSky", onRunAnimSky, NULL); - childSetAction("WLStopAnimSky", onStopAnimSky, NULL); + getChild("WLLengthOfDayHour")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1)); + getChild("WLLengthOfDayMin")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1)); + getChild("WLLengthOfDaySec")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onTimeRateChanged, this, _1)); + getChild("WLUseLindenTime")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onUseLindenTime, this, _1)); + getChild("WLAnimSky")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onRunAnimSky, this, _1)); + getChild("WLStopAnimSky")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onStopAnimSky, this, _1)); - childSetAction("WLLoadDayCycle", onLoadDayCycle, NULL); - childSetAction("WLSaveDayCycle", onSaveDayCycle, NULL); + getChild("WLLoadDayCycle")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onLoadDayCycle, this, _1)); + getChild("WLSaveDayCycle")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onSaveDayCycle, this, _1)); - childSetAction("WLAddKey", onAddKey, NULL); - childSetAction("WLDeleteKey", onDeleteKey, NULL); + getChild("WLAddKey")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onAddKey, this, _1)); + getChild("WLDeleteKey")->setCommitCallback(boost::bind(&LLFloaterDayCycle::onDeleteKey, this, _1)); } void LLFloaterDayCycle::syncMenu() @@ -139,12 +145,12 @@ void LLFloaterDayCycle::syncMenu() // std::map & currentParams = LLWLParamManager::instance()->mCurParams.mParamValues; // set time - LLMultiSliderCtrl* sldr = LLFloaterDayCycle::sDayCycle->getChild("WLTimeSlider"); + LLMultiSliderCtrl* sldr = getChild("WLTimeSlider"); sldr->setCurSliderValue((F32)LLWLParamManager::instance()->mAnimator.getDayTime() * sHoursPerDay); - LLSpinCtrl* secSpin = sDayCycle->getChild("WLLengthOfDaySec"); - LLSpinCtrl* minSpin = sDayCycle->getChild("WLLengthOfDayMin"); - LLSpinCtrl* hourSpin = sDayCycle->getChild("WLLengthOfDayHour"); + LLSpinCtrl* secSpin = getChild("WLLengthOfDaySec"); + LLSpinCtrl* minSpin = getChild("WLLengthOfDayMin"); + LLSpinCtrl* hourSpin = getChild("WLLengthOfDayHour"); F32 curRate; F32 hours, min, sec; @@ -164,18 +170,18 @@ void LLFloaterDayCycle::syncMenu() // turn off Use Estate Time button if it's already being used if( LLWLParamManager::instance()->mAnimator.mUseLindenTime == true) { - LLFloaterDayCycle::sDayCycle->childDisable("WLUseLindenTime"); + childDisable("WLUseLindenTime"); } else { - LLFloaterDayCycle::sDayCycle->childEnable("WLUseLindenTime"); + childEnable("WLUseLindenTime"); } } void LLFloaterDayCycle::syncSliderTrack() { // clear the slider - LLMultiSliderCtrl* kSldr = sDayCycle->getChild("WLDayCycleKeys"); + LLMultiSliderCtrl* kSldr = getChild("WLDayCycleKeys"); kSldr->clear(); sSliderToKey.clear(); @@ -198,12 +204,12 @@ void LLFloaterDayCycle::syncTrack() } LLMultiSliderCtrl* sldr; - sldr = sDayCycle->getChild( + sldr = getChild( "WLDayCycleKeys"); llassert_always(sSliderToKey.size() == sldr->getValue().size()); LLMultiSliderCtrl* tSldr; - tSldr = sDayCycle->getChild( + tSldr = getChild( "WLTimeSlider"); // create a new animation track @@ -225,50 +231,7 @@ void LLFloaterDayCycle::syncTrack() LLWLParamManager::instance()->mCurParams); } -// static -LLFloaterDayCycle* LLFloaterDayCycle::instance() -{ - if (!sDayCycle) - { - sDayCycle = new LLFloaterDayCycle(); - sDayCycle->open(); - sDayCycle->setFocus(TRUE); - } - return sDayCycle; -} - -bool LLFloaterDayCycle::isOpen() -{ - if (sDayCycle != NULL) - { - return true; - } - return false; -} - -void LLFloaterDayCycle::show() -{ - LLFloaterDayCycle* dayCycle = instance(); - dayCycle->syncMenu(); - syncSliderTrack(); - - // comment in if you want the menu to rebuild each time - //LLUICtrlFactory::getInstance()->buildFloater(dayCycle, "floater_day_cycle_options.xml"); - //dayCycle->initCallbacks(); - - dayCycle->open(); -} - -// virtual -void LLFloaterDayCycle::onClose(bool app_quitting) -{ - if (sDayCycle) - { - sDayCycle->setVisible(FALSE); - } -} - -void LLFloaterDayCycle::onRunAnimSky(void* userData) +void LLFloaterDayCycle::onRunAnimSky(LLUICtrl* ctrl) { // if no keys, do nothing if(sSliderToKey.size() == 0) @@ -277,11 +240,11 @@ void LLFloaterDayCycle::onRunAnimSky(void* userData) } LLMultiSliderCtrl* sldr; - sldr = sDayCycle->getChild("WLDayCycleKeys"); + sldr = getChild("WLDayCycleKeys"); llassert_always(sSliderToKey.size() == sldr->getValue().size()); LLMultiSliderCtrl* tSldr; - tSldr = sDayCycle->getChild("WLTimeSlider"); + tSldr = getChild("WLTimeSlider"); // turn off linden time LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; @@ -293,7 +256,7 @@ void LLFloaterDayCycle::onRunAnimSky(void* userData) llassert_always(LLWLParamManager::instance()->mAnimator.mTimeTrack.size() == sldr->getValue().size()); } -void LLFloaterDayCycle::onStopAnimSky(void* userData) +void LLFloaterDayCycle::onStopAnimSky(LLUICtrl* ctrl) { // if no keys, do nothing if(sSliderToKey.size() == 0) { @@ -305,17 +268,16 @@ void LLFloaterDayCycle::onStopAnimSky(void* userData) LLWLParamManager::instance()->mAnimator.mUseLindenTime = false; } -void LLFloaterDayCycle::onUseLindenTime(void* userData) +void LLFloaterDayCycle::onUseLindenTime(LLUICtrl* ctrl) { - LLFloaterWindLight* wl = LLFloaterWindLight::instance(); - LLComboBox* box = wl->getChild("WLPresetsCombo"); + LLComboBox* box = getChild("WLPresetsCombo"); box->selectByValue(""); LLWLParamManager::instance()->mAnimator.mIsRunning = true; LLWLParamManager::instance()->mAnimator.mUseLindenTime = true; } -void LLFloaterDayCycle::onLoadDayCycle(void* userData) +void LLFloaterDayCycle::onLoadDayCycle(LLUICtrl* ctrl) { LLWLParamManager::instance()->mDay.loadDayCycle("Default.xml"); @@ -325,7 +287,7 @@ void LLFloaterDayCycle::onLoadDayCycle(void* userData) // set the param manager's track to the new one LLMultiSliderCtrl* tSldr; - tSldr = sDayCycle->getChild( + tSldr = getChild( "WLTimeSlider"); LLWLParamManager::instance()->resetAnimator( tSldr->getCurSliderValue() / sHoursPerDay, false); @@ -335,15 +297,15 @@ void LLFloaterDayCycle::onLoadDayCycle(void* userData) LLWLParamManager::instance()->mCurParams); } -void LLFloaterDayCycle::onSaveDayCycle(void* userData) +void LLFloaterDayCycle::onSaveDayCycle(LLUICtrl* ctrl) { LLWLParamManager::instance()->mDay.saveDayCycle("Default.xml"); } -void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl) { - LLMultiSliderCtrl* sldr = sDayCycle->getChild( + LLMultiSliderCtrl* sldr = getChild( "WLTimeSlider"); /// get the slider value @@ -359,12 +321,12 @@ void LLFloaterDayCycle::onTimeSliderMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams); } -void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl) { - LLComboBox* comboBox = sDayCycle->getChild("WLKeyPresets"); - LLMultiSliderCtrl* sldr = sDayCycle->getChild("WLDayCycleKeys"); - LLSpinCtrl* hourSpin = sDayCycle->getChild("WLCurKeyHour"); - LLSpinCtrl* minSpin = sDayCycle->getChild("WLCurKeyMin"); + LLComboBox* comboBox = getChild("WLKeyPresets"); + LLMultiSliderCtrl* sldr = getChild("WLDayCycleKeys"); + LLSpinCtrl* hourSpin = getChild("WLCurKeyHour"); + LLSpinCtrl* minSpin = getChild("WLCurKeyMin"); if(sldr->getValue().size() == 0) { return; @@ -402,18 +364,18 @@ void LLFloaterDayCycle::onKeyTimeMoved(LLUICtrl* ctrl, void* userData) } -void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl, void* userData) +void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl) { // if no keys, skipped if(sSliderToKey.size() == 0) { return; } - LLMultiSliderCtrl* sldr = sDayCycle->getChild( + LLMultiSliderCtrl* sldr = getChild( "WLDayCycleKeys"); - LLSpinCtrl* hourSpin = sDayCycle->getChild( + LLSpinCtrl* hourSpin = getChild( "WLCurKeyHour"); - LLSpinCtrl* minSpin = sDayCycle->getChild( + LLSpinCtrl* minSpin = getChild( "WLCurKeyMin"); F32 hour = hourSpin->get(); @@ -431,12 +393,12 @@ void LLFloaterDayCycle::onKeyTimeChanged(LLUICtrl* ctrl, void* userData) syncTrack(); } -void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl, void* userData) +void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl) { // get the time - LLComboBox* comboBox = sDayCycle->getChild( + LLComboBox* comboBox = getChild( "WLKeyPresets"); - LLMultiSliderCtrl* sldr = sDayCycle->getChild( + LLMultiSliderCtrl* sldr = getChild( "WLDayCycleKeys"); // do nothing if no sliders @@ -458,16 +420,16 @@ void LLFloaterDayCycle::onKeyPresetChanged(LLUICtrl* ctrl, void* userData) syncTrack(); } -void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl, void* userData) +void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl) { // get the time - LLSpinCtrl* secSpin = sDayCycle->getChild( + LLSpinCtrl* secSpin = getChild( "WLLengthOfDaySec"); - LLSpinCtrl* minSpin = sDayCycle->getChild( + LLSpinCtrl* minSpin = getChild( "WLLengthOfDayMin"); - LLSpinCtrl* hourSpin = sDayCycle->getChild( + LLSpinCtrl* hourSpin = getChild( "WLLengthOfDayHour"); F32 hour; @@ -486,13 +448,13 @@ void LLFloaterDayCycle::onTimeRateChanged(LLUICtrl* ctrl, void* userData) syncTrack(); } -void LLFloaterDayCycle::onAddKey(void* userData) +void LLFloaterDayCycle::onAddKey(LLUICtrl* ctrl) { - LLComboBox* comboBox = sDayCycle->getChild( + LLComboBox* comboBox = getChild( "WLKeyPresets"); - LLMultiSliderCtrl* kSldr = sDayCycle->getChild( + LLMultiSliderCtrl* kSldr = getChild( "WLDayCycleKeys"); - LLMultiSliderCtrl* tSldr = sDayCycle->getChild( + LLMultiSliderCtrl* tSldr = getChild( "WLTimeSlider"); llassert_always(sSliderToKey.size() == kSldr->getValue().size()); @@ -508,7 +470,7 @@ void LLFloaterDayCycle::onAddKey(void* userData) void LLFloaterDayCycle::addSliderKey(F32 time, const std::string & presetName) { - LLMultiSliderCtrl* kSldr = sDayCycle->getChild( + LLMultiSliderCtrl* kSldr = getChild( "WLDayCycleKeys"); // make a slider @@ -533,7 +495,7 @@ void LLFloaterDayCycle::addSliderKey(F32 time, const std::string & presetName) void LLFloaterDayCycle::deletePreset(std::string& presetName) { - LLMultiSliderCtrl* sldr = sDayCycle->getChild("WLDayCycleKeys"); + LLMultiSliderCtrl* sldr = getChild("WLDayCycleKeys"); /// delete any reference std::map::iterator curr_preset, next_preset; @@ -549,15 +511,15 @@ void LLFloaterDayCycle::deletePreset(std::string& presetName) } } -void LLFloaterDayCycle::onDeleteKey(void* userData) +void LLFloaterDayCycle::onDeleteKey(LLUICtrl* ctrl) { if(sSliderToKey.size() == 0) { return; } - LLComboBox* comboBox = sDayCycle->getChild( + LLComboBox* comboBox = getChild( "WLKeyPresets"); - LLMultiSliderCtrl* sldr = sDayCycle->getChild("WLDayCycleKeys"); + LLMultiSliderCtrl* sldr = getChild("WLDayCycleKeys"); // delete from map const std::string& sldrName = sldr->getCurSlider(); @@ -574,8 +536,8 @@ void LLFloaterDayCycle::onDeleteKey(void* userData) comboBox->selectByValue(sSliderToKey[name].presetName); F32 time = sSliderToKey[name].time; - LLSpinCtrl* hourSpin = sDayCycle->getChild("WLCurKeyHour"); - LLSpinCtrl* minSpin = sDayCycle->getChild("WLCurKeyMin"); + LLSpinCtrl* hourSpin = getChild("WLCurKeyHour"); + LLSpinCtrl* minSpin = getChild("WLCurKeyMin"); // now set the spinners F32 hour = (F32)((S32)time); diff --git a/indra/newview/llfloaterdaycycle.h b/indra/newview/llfloaterdaycycle.h index d230035545..43c347d4f2 100644 --- a/indra/newview/llfloaterdaycycle.h +++ b/indra/newview/llfloaterdaycycle.h @@ -56,87 +56,69 @@ class LLFloaterDayCycle : public LLFloater { public: - LLFloaterDayCycle(); + LLFloaterDayCycle(const LLSD& key); virtual ~LLFloaterDayCycle(); - + /*virtual*/ BOOL postBuild(); /// help button stuff - static void onClickHelp(void* data); + void onClickHelp(std::string xml_alert); void initHelpBtn(const std::string& name, const std::string& xml_alert); /// initialize all void initCallbacks(void); - /// one and one instance only - static LLFloaterDayCycle* instance(); - /// on time slider moved - static void onTimeSliderMoved(LLUICtrl* ctrl, void* userData); + void onTimeSliderMoved(LLUICtrl* ctrl); /// what happens when you move the key frame - static void onKeyTimeMoved(LLUICtrl* ctrl, void* userData); + void onKeyTimeMoved(LLUICtrl* ctrl); /// what happens when you change the key frame's time - static void onKeyTimeChanged(LLUICtrl* ctrl, void* userData); + void onKeyTimeChanged(LLUICtrl* ctrl); /// if you change the combo box, change the frame - static void onKeyPresetChanged(LLUICtrl* ctrl, void* userData); + void onKeyPresetChanged(LLUICtrl* ctrl); /// run this when user says to run the sky animation - static void onRunAnimSky(void* userData); + void onRunAnimSky(LLUICtrl* ctrl); /// run this when user says to stop the sky animation - static void onStopAnimSky(void* userData); + void onStopAnimSky(LLUICtrl* ctrl); /// if you change the combo box, change the frame - static void onTimeRateChanged(LLUICtrl* ctrl, void* userData); + void onTimeRateChanged(LLUICtrl* ctrl); /// add a new key on slider - static void onAddKey(void* userData); + void onAddKey(LLUICtrl* ctrl); /// delete any and all reference to a preset void deletePreset(std::string& presetName); /// delete a key frame - static void onDeleteKey(void* userData); + void onDeleteKey(LLUICtrl* ctrl); /// button to load day - static void onLoadDayCycle(void* userData); + void onLoadDayCycle(LLUICtrl* ctrl); /// button to save day - static void onSaveDayCycle(void* userData); + void onSaveDayCycle(LLUICtrl* ctrl); /// toggle for Linden time - static void onUseLindenTime(void* userData); - - - //// menu management - - /// show off our menu - static void show(); - - /// return if the menu exists or not - static bool isOpen(); - - /// stuff to do on exit - virtual void onClose(bool app_quitting); + void onUseLindenTime(LLUICtrl* ctrl); /// sync up sliders with day cycle structure - static void syncMenu(); + void syncMenu(); // makes sure key slider has what's in day cycle - static void syncSliderTrack(); + void syncSliderTrack(); /// makes sure day cycle data structure has what's in menu - static void syncTrack(); + void syncTrack(); /// add a slider to the track - static void addSliderKey(F32 time, const std::string& presetName); + void addSliderKey(F32 time, const std::string& presetName); private: - // one instance on the inside - static LLFloaterDayCycle* sDayCycle; - // map of sliders to parameters static std::map sSliderToKey; diff --git a/indra/newview/llfloaterenvsettings.cpp b/indra/newview/llfloaterenvsettings.cpp index 661c3988c0..a520df36de 100644 --- a/indra/newview/llfloaterenvsettings.cpp +++ b/indra/newview/llfloaterenvsettings.cpp @@ -34,6 +34,7 @@ #include "llfloaterenvsettings.h" +#include "llfloaterreg.h" #include "llfloaterwindlight.h" #include "llfloaterwater.h" #include "lluictrlfactory.h" @@ -52,43 +53,43 @@ #include -LLFloaterEnvSettings* LLFloaterEnvSettings::sEnvSettings = NULL; - -LLFloaterEnvSettings::LLFloaterEnvSettings() : LLFloater(std::string("Environment Settings Floater")) +LLFloaterEnvSettings::LLFloaterEnvSettings(const LLSD& key) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_env_settings.xml"); - - // load it up - initCallbacks(); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_env_settings.xml"); } - +// virtual LLFloaterEnvSettings::~LLFloaterEnvSettings() { } - -void LLFloaterEnvSettings::onClickHelp(void* data) +// virtual +BOOL LLFloaterEnvSettings::postBuild() +{ + // load it up + initCallbacks(); + syncMenu(); + return TRUE; +} +void LLFloaterEnvSettings::onClickHelp() { - LLFloaterEnvSettings* self = (LLFloaterEnvSettings*)data; - LLNotifications::instance().add(self->contextualNotification("EnvSettingsHelpButton")); + LLNotifications::instance().add(contextualNotification("EnvSettingsHelpButton")); } void LLFloaterEnvSettings::initCallbacks(void) { // our three sliders - childSetCommitCallback("EnvTimeSlider", onChangeDayTime, NULL); - childSetCommitCallback("EnvCloudSlider", onChangeCloudCoverage, NULL); - childSetCommitCallback("EnvWaterFogSlider", onChangeWaterFogDensity, - &LLWaterParamManager::instance()->mFogDensity); + getChild("EnvTimeSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeDayTime, this, _1)); + getChild("EnvCloudSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeCloudCoverage, this, _1)); + getChild("EnvWaterFogSlider")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeWaterFogDensity, this, _1, &LLWaterParamManager::instance()->mFogDensity)); // color picker - childSetCommitCallback("EnvWaterColor", onChangeWaterColor, - &LLWaterParamManager::instance()->mFogColor); + getChild("EnvWaterColor")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onChangeWaterColor, this, _1, &LLWaterParamManager::instance()->mFogColor)); // WL Top - childSetAction("EnvAdvancedSkyButton", onOpenAdvancedSky, NULL); - childSetAction("EnvAdvancedWaterButton", onOpenAdvancedWater, NULL); - childSetAction("EnvUseEstateTimeButton", onUseEstateTime, NULL); - childSetAction("EnvSettingsHelpButton", onClickHelp, this); + getChild("EnvAdvancedSkyButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onOpenAdvancedSky, this)); + getChild("EnvAdvancedWaterButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onOpenAdvancedWater, this)); + getChild("EnvUseEstateTimeButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onUseEstateTime, this)); + getChild("EnvSettingsHelpButton")->setCommitCallback(boost::bind(&LLFloaterEnvSettings::onClickHelp, this)); } @@ -97,14 +98,14 @@ void LLFloaterEnvSettings::initCallbacks(void) void LLFloaterEnvSettings::syncMenu() { LLSliderCtrl* sldr; - sldr = sEnvSettings->getChild("EnvTimeSlider"); + sldr = getChild("EnvTimeSlider"); // sync the clock F32 val = (F32)LLWLParamManager::instance()->mAnimator.getDayTime(); std::string timeStr = timeToString(val); LLTextBox* textBox; - textBox = sEnvSettings->getChild("EnvTimeText"); + textBox = getChild("EnvTimeText"); textBox->setValue(timeStr); @@ -123,7 +124,7 @@ void LLFloaterEnvSettings::syncMenu() LLWaterParamManager * param_mgr = LLWaterParamManager::instance(); // sync water params LLColor4 col = param_mgr->getFogColor(); - LLColorSwatchCtrl* colCtrl = sEnvSettings->getChild("EnvWaterColor"); + LLColorSwatchCtrl* colCtrl = getChild("EnvWaterColor"); col.mV[3] = 1.0f; colCtrl->set(col); @@ -167,53 +168,9 @@ void LLFloaterEnvSettings::syncMenu() } } - -// static instance of it -LLFloaterEnvSettings* LLFloaterEnvSettings::instance() +void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl) { - if (!sEnvSettings) - { - sEnvSettings = new LLFloaterEnvSettings(); - sEnvSettings->open(); - sEnvSettings->setFocus(TRUE); - } - return sEnvSettings; -} -void LLFloaterEnvSettings::show() -{ - LLFloaterEnvSettings* envSettings = instance(); - envSettings->syncMenu(); - - // comment in if you want the menu to rebuild each time - //LLUICtrlFactory::getInstance()->buildFloater(envSettings, "floater_env_settings.xml"); - //envSettings->initCallbacks(); - - envSettings->open(); -} - -bool LLFloaterEnvSettings::isOpen() -{ - if (sEnvSettings != NULL) - { - return true; - } - return false; -} - -// virtual -void LLFloaterEnvSettings::onClose(bool app_quitting) -{ - if (sEnvSettings) - { - sEnvSettings->setVisible(FALSE); - } -} - - -void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl, void* userData) -{ - LLSliderCtrl* sldr; - sldr = sEnvSettings->getChild("EnvTimeSlider"); + LLSliderCtrl* sldr = static_cast(ctrl); // deactivate animator LLWLParamManager::instance()->mAnimator.mIsRunning = false; @@ -230,10 +187,9 @@ void LLFloaterEnvSettings::onChangeDayTime(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams); } -void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl, void* userData) +void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl) { - LLSliderCtrl* sldr; - sldr = sEnvSettings->getChild("EnvCloudSlider"); + LLSliderCtrl* sldr = static_cast(ctrl); // deactivate animator //LLWLParamManager::instance()->mAnimator.mIsRunning = false; @@ -243,17 +199,10 @@ void LLFloaterEnvSettings::onChangeCloudCoverage(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams.set("cloud_shadow", val); } -void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData) +void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl) { LLSliderCtrl* sldr; - sldr = sEnvSettings->getChild("EnvWaterFogSlider"); - - if(NULL == userData) - { - return; - } - - WaterExpFloatControl * expFloatControl = static_cast(userData); + sldr = getChild("EnvWaterFogSlider"); F32 val = sldr->getValueF32(); expFloatControl->mExp = val; @@ -263,10 +212,9 @@ void LLFloaterEnvSettings::onChangeWaterFogDensity(LLUICtrl* ctrl, void* userDat LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, void* userData) +void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLColorSwatchCtrl* swatch = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); *colorControl = swatch->get(); colorControl->update(LLWaterParamManager::instance()->mCurParams); @@ -274,23 +222,22 @@ void LLFloaterEnvSettings::onChangeWaterColor(LLUICtrl* ctrl, void* userData) } -void LLFloaterEnvSettings::onOpenAdvancedSky(void* userData) +void LLFloaterEnvSettings::onOpenAdvancedSky() { - LLFloaterWindLight::show(); + LLFloaterReg::showInstance("env_windlight"); } -void LLFloaterEnvSettings::onOpenAdvancedWater(void* userData) +void LLFloaterEnvSettings::onOpenAdvancedWater() { - LLFloaterWater::show(); + LLFloaterReg::showInstance("env_water"); } -void LLFloaterEnvSettings::onUseEstateTime(void* userData) +void LLFloaterEnvSettings::onUseEstateTime() { - if(LLFloaterWindLight::isOpen()) + LLFloaterWindLight* wl = LLFloaterReg::findTypedInstance("env_windlight"); + if(wl) { - // select the blank value in - LLFloaterWindLight* wl = LLFloaterWindLight::instance(); LLComboBox* box = wl->getChild("WLPresetsCombo"); box->selectByValue(""); } @@ -303,7 +250,6 @@ std::string LLFloaterEnvSettings::timeToString(F32 curTime) { S32 hours; S32 min; - bool isPM = false; // get hours and minutes hours = (S32) (24.0 * curTime); @@ -317,46 +263,19 @@ std::string LLFloaterEnvSettings::timeToString(F32 curTime) min = 0; } - // set for PM - if(hours >= 12 && hours < 24) - { - isPM = true; - } + std::string newTime = getString("timeStr"); + struct tm * timeT; + time_t secT = time(0); + timeT = gmtime (&secT); - // convert to non-military notation - if(hours >= 24) - { - hours = 12; - } - else if(hours > 12) - { - hours -= 12; - } - else if(hours == 0) - { - hours = 12; - } + timeT->tm_hour = hours; + timeT->tm_min = min; + secT = mktime (timeT); + secT -= LLStringOps::getLocalTimeOffset (); - // make the string - std::stringstream newTime; - newTime << hours << ":"; - - // double 0 - if(min < 10) - { - newTime << 0; - } - - // finish it - newTime << min << " "; - if(isPM) - { - newTime << "PM"; - } - else - { - newTime << "AM"; - } + LLSD substitution; + substitution["datetime"] = (S32) secT; - return newTime.str(); + LLStringUtil::format (newTime, substitution); + return newTime; } diff --git a/indra/newview/llfloaterenvsettings.h b/indra/newview/llfloaterenvsettings.h index 4cdf6036c6..083e3636d1 100644 --- a/indra/newview/llfloaterenvsettings.h +++ b/indra/newview/llfloaterenvsettings.h @@ -39,59 +39,46 @@ #include "llfloater.h" +struct WaterColorControl; +struct WaterExpFloatControl; /// Menuing system for all of windlight's functionality class LLFloaterEnvSettings : public LLFloater { public: - LLFloaterEnvSettings(); - virtual ~LLFloaterEnvSettings(); - + LLFloaterEnvSettings(const LLSD& key); + /*virtual*/ ~LLFloaterEnvSettings(); + /*virtual*/ BOOL postBuild(); /// initialize all the callbacks for the menu void initCallbacks(void); - /// one and one instance only - static LLFloaterEnvSettings* instance(); - /// callback for the menus help button - static void onClickHelp(void* data); + void onClickHelp(); /// handle if time of day is changed - static void onChangeDayTime(LLUICtrl* ctrl, void* userData); + void onChangeDayTime(LLUICtrl* ctrl); /// handle if cloud coverage is changed - static void onChangeCloudCoverage(LLUICtrl* ctrl, void* userData); + void onChangeCloudCoverage(LLUICtrl* ctrl); /// handle change in water fog density - static void onChangeWaterFogDensity(LLUICtrl* ctrl, void* userData); - - /// handle change in under water fog density - static void onChangeUnderWaterFogMod(LLUICtrl* ctrl, void* userData); + void onChangeWaterFogDensity(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl); /// handle change in water fog color - static void onChangeWaterColor(LLUICtrl* ctrl, void* userData); + void onChangeWaterColor(LLUICtrl* ctrl, WaterColorControl* colorControl); /// open the advanced sky settings menu - static void onOpenAdvancedSky(void* userData); + void onOpenAdvancedSky(); /// open the advanced water settings menu - static void onOpenAdvancedWater(void* userData); + void onOpenAdvancedWater(); /// sync time with the server - static void onUseEstateTime(void* userData); + void onUseEstateTime(); //// menu management - /// show off our menu - static void show(); - - /// return if the menu exists or not - static bool isOpen(); - - /// stuff to do on exit - virtual void onClose(bool app_quitting); - /// sync up sliders with parameters void syncMenu(); @@ -99,8 +86,6 @@ public: std::string timeToString(F32 curTime); private: - // one instance on the inside - static LLFloaterEnvSettings* sEnvSettings; }; diff --git a/indra/newview/llfloaterevent.cpp b/indra/newview/llfloaterevent.cpp deleted file mode 100644 index 485c13c7b6..0000000000 --- a/indra/newview/llfloaterevent.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file llfloaterevent.cpp - * @brief Event information as shown in a floating window from - * secondlife:// command handler. - * - * $LicenseInfo:firstyear=2007&license=viewergpl$ - * - * Copyright (c) 2007-2009, Linden Research, Inc. - * - * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 - * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at - * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. - * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. - * $/LicenseInfo$ - */ - -#include "llviewerprecompiledheaders.h" - -#include "llfloaterevent.h" - -// viewer project includes -#include "llcommandhandler.h" -#include "llpanelevent.h" - -// linden library includes -#include "lluuid.h" -#include "lluictrlfactory.h" - -//////////////////////////////////////////////////////////////////////////// -// LLFloaterEventInfo - -//----------------------------------------------------------------------------- -// Globals -//----------------------------------------------------------------------------- - -LLMap< U32, LLFloaterEventInfo* > gEventInfoInstances; - -class LLEventHandler : public LLCommandHandler -{ -public: - // requires trusted browser to trigger - LLEventHandler() : LLCommandHandler("event", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) - { - if (tokens.size() < 2) - { - return false; - } - U32 event_id = tokens[0].asInteger(); - if (tokens[1].asString() == "about") - { - LLFloaterEventInfo::show(event_id); - return true; - } - return false; - } -}; -LLEventHandler gEventHandler; - -LLFloaterEventInfo::LLFloaterEventInfo(const std::string& name, const U32 event_id) -: LLFloater(name), - mEventID( event_id ) -{ - - mFactoryMap["event_details_panel"] = LLCallbackMap(LLFloaterEventInfo::createEventDetail, this); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_event.xml", &getFactoryMap()); - gEventInfoInstances.addData(event_id, this); -} - -LLFloaterEventInfo::~LLFloaterEventInfo() -{ - // child views automatically deleted - gEventInfoInstances.removeData(mEventID); -} - -void LLFloaterEventInfo::displayEventInfo(const U32 event_id) -{ - mPanelEventp->setEventID(event_id); - this->setFrontmost(true); -} - -// static -void* LLFloaterEventInfo::createEventDetail(void* userdata) -{ - LLFloaterEventInfo *self = (LLFloaterEventInfo*)userdata; - self->mPanelEventp = new LLPanelEvent(); - LLUICtrlFactory::getInstance()->buildPanel(self->mPanelEventp, "panel_event.xml"); - - return self->mPanelEventp; -} - -// static -LLFloaterEventInfo* LLFloaterEventInfo::show(const U32 event_id) -{ - LLFloaterEventInfo *floater; - if (gEventInfoInstances.checkData(event_id)) - { - // ...bring that window to front - floater = gEventInfoInstances.getData(event_id); - floater->open(); /*Flawfinder: ignore*/ - floater->setFrontmost(true); - } - else - { - floater = new LLFloaterEventInfo("eventinfo", event_id ); - floater->center(); - floater->open(); /*Flawfinder: ignore*/ - floater->displayEventInfo(event_id); - floater->setFrontmost(true); - } - - return floater; -} diff --git a/indra/newview/llfloaterfonttest.cpp b/indra/newview/llfloaterfonttest.cpp index 4bb1d9605d..413992910e 100644 --- a/indra/newview/llfloaterfonttest.cpp +++ b/indra/newview/llfloaterfonttest.cpp @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008 Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -41,25 +42,11 @@ #include "lluictrlfactory.h" -LLFloaterFontTest* LLFloaterFontTest::sInstance = NULL; - -LLFloaterFontTest::LLFloaterFontTest() - : LLFloater(std::string("floater_font_test"), LLRect(0,500,700,0), std::string("Font Test")) +LLFloaterFontTest::LLFloaterFontTest(const LLSD& key) + : LLFloater("floater_font_test") { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_font_test.xml"); } LLFloaterFontTest::~LLFloaterFontTest() { - sInstance = NULL; -} - -// static -void LLFloaterFontTest::show(void *unused) -{ - if (!sInstance) - sInstance = new LLFloaterFontTest(); - - sInstance->open(); /*Flawfinder: ignore*/ - sInstance->setFocus(TRUE); } diff --git a/indra/newview/llfloaterfonttest.h b/indra/newview/llfloaterfonttest.h index 45ff890423..4406a9f36a 100644 --- a/indra/newview/llfloaterfonttest.h +++ b/indra/newview/llfloaterfonttest.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2008&license=viewergpl$ * - * Copyright (c) 2008, Linden Research, Inc. + * Copyright (c) 2008-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -38,14 +39,10 @@ class LLFloaterFontTest: public LLFloater { -public: - static void show(void* unused); - + friend class LLFloaterReg; private: - LLFloaterFontTest(); + LLFloaterFontTest(const LLSD& key); ~LLFloaterFontTest(); - - static LLFloaterFontTest* sInstance; }; #endif diff --git a/indra/newview/llfloaterfriends.cpp b/indra/newview/llfloaterfriends.cpp index 014a631a53..eb73bd6d8f 100644 --- a/indra/newview/llfloaterfriends.cpp +++ b/indra/newview/llfloaterfriends.cpp @@ -46,12 +46,14 @@ #include "llfloateravatarpicker.h" #include "llviewerwindow.h" #include "llbutton.h" -#include "llfloateravatarinfo.h" +#include "llavataractions.h" #include "llinventorymodel.h" #include "llnamelistctrl.h" #include "llnotify.h" #include "llresmgr.h" -#include "llimview.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lluictrlfactory.h" #include "llmenucommands.h" #include "llviewercontrol.h" @@ -60,6 +62,8 @@ #include "lltextbox.h" #include "llvoiceclient.h" +// *TODO: Move more common stuff to LLAvatarActions? + //Maximum number of people you can select to do an operation on at once. #define MAX_FRIEND_SELECT 20 #define DEFAULT_PERIOD 5.0 @@ -148,7 +152,7 @@ void LLPanelFriends::updateFriends(U32 changed_mask) // if the maximum amount of friends are selected mShowMaxSelectWarning = false; - LLDynamicArray selected_friends = getSelectedIDs(); + std::vector selected_friends = getSelectedIDs(); if(changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) { refreshNames(changed_mask); @@ -173,7 +177,7 @@ void LLPanelFriends::updateFriends(U32 changed_mask) // but we don't really care here, because refreshUI() will // clean up the interface. friends_list->setCurrentByID(selected_id); - for(LLDynamicArray::iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr) + for(std::vector::iterator itr = selected_friends.begin(); itr != selected_friends.end(); ++itr) { friends_list->setSelectedByValue(*itr, true); } @@ -188,10 +192,10 @@ BOOL LLPanelFriends::postBuild() { mFriendsList = getChild("friend_list"); mFriendsList->setMaxSelectable(MAX_FRIEND_SELECT); - mFriendsList->setMaximumSelectCallback(onMaximumSelect); + mFriendsList->setMaximumSelectCallback(boost::bind(&LLPanelFriends::onMaximumSelect)); mFriendsList->setCommitOnSelectionChange(TRUE); childSetCommitCallback("friend_list", onSelectName, this); - childSetDoubleClickCallback("friend_list", onClickIM); + getChild("friend_list")->setDoubleClickCallback(onClickIM, this); U32 changed_mask = LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE; refreshNames(changed_mask); @@ -233,7 +237,7 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) friend_column["column"] = "friend_name"; friend_column["value"] = fullname; friend_column["font"] = "SANSSERIF"; - friend_column["font-style"] = "NORMAL"; + friend_column["font"]["style"] = "NORMAL"; LLSD& online_status_column = element["columns"][LIST_ONLINE_STATUS]; online_status_column["column"] = "icon_online_status"; @@ -241,12 +245,12 @@ BOOL LLPanelFriends::addFriend(const LLUUID& agent_id) if (isOnline) { - friend_column["font-style"] = "BOLD"; + friend_column["font"]["style"] = "BOLD"; online_status_column["value"] = "icon_avatar_online.tga"; } else if(isOnlineSIP) { - friend_column["font-style"] = "BOLD"; + friend_column["font"]["style"] = "BOLD"; online_status_column["value"] = ONLINE_SIP_ICON_NAME; } @@ -325,31 +329,14 @@ BOOL LLPanelFriends::updateFriendItem(const LLUUID& agent_id, const LLRelationsh void LLPanelFriends::refreshRightsChangeList() { - LLDynamicArray friends = getSelectedIDs(); + std::vector friends = getSelectedIDs(); S32 num_selected = friends.size(); bool can_offer_teleport = num_selected >= 1; bool selected_friends_online = true; - LLTextBox* processing_label = getChild("process_rights_label"); - - if(!mAllowRightsChange) - { - if(processing_label) - { - processing_label->setVisible(true); - // ignore selection for now - friends.clear(); - num_selected = 0; - } - } - else if(processing_label) - { - processing_label->setVisible(false); - } - const LLRelationship* friend_status = NULL; - for(LLDynamicArray::iterator itr = friends.begin(); itr != friends.end(); ++itr) + for(std::vector::iterator itr = friends.begin(); itr != friends.end(); ++itr) { friend_status = LLAvatarTracker::instance().getBuddyInfo(*itr); if (friend_status) @@ -391,7 +378,7 @@ struct SortFriendsByID void LLPanelFriends::refreshNames(U32 changed_mask) { - LLDynamicArray selected_ids = getSelectedIDs(); + std::vector selected_ids = getSelectedIDs(); S32 pos = mFriendsList->getScrollPos(); // get all buddies we know about @@ -417,7 +404,7 @@ void LLPanelFriends::refreshNames(U32 changed_mask) // Changed item in place, need to request sort and update columns // because we might have changed data in a column on which the user // has already sorted. JC - mFriendsList->sortItems(); + mFriendsList->updateSort(); // re-select items mFriendsList->selectMultiple(selected_ids); @@ -499,17 +486,8 @@ void LLPanelFriends::refreshUI() single_selected = TRUE; if(num_selected > 1) { - childSetText("friend_name_label", getString("Multiple")); multiple_selected = TRUE; } - else - { - childSetText("friend_name_label", mFriendsList->getFirstSelected()->getColumn(LIST_FRIEND_NAME)->getValue().asString() + "..."); - } - } - else - { - childSetText("friend_name_label", LLStringUtil::null); } @@ -521,15 +499,15 @@ void LLPanelFriends::refreshUI() //(single_selected will always be true in this situations) childSetEnabled("remove_btn", single_selected); childSetEnabled("im_btn", single_selected); - childSetEnabled("friend_rights", single_selected); +// childSetEnabled("friend_rights", single_selected); refreshRightsChangeList(); } -LLDynamicArray LLPanelFriends::getSelectedIDs() +std::vector LLPanelFriends::getSelectedIDs() { LLUUID selected_id; - LLDynamicArray friend_ids; + std::vector friend_ids; std::vector selected = mFriendsList->getAllSelected(); for(std::vector::iterator itr = selected.begin(); itr != selected.end(); ++itr) { @@ -552,7 +530,7 @@ void LLPanelFriends::onSelectName(LLUICtrl* ctrl, void* user_data) } //static -void LLPanelFriends::onMaximumSelect(void* user_data) +void LLPanelFriends::onMaximumSelect() { LLSD args; args["MAX_SELECT"] = llformat("%d", MAX_FRIEND_SELECT); @@ -564,14 +542,11 @@ void LLPanelFriends::onClickProfile(void* user_data) { LLPanelFriends* panelp = (LLPanelFriends*)user_data; - //llinfos << "LLPanelFriends::onClickProfile()" << llendl; - LLDynamicArray ids = panelp->getSelectedIDs(); + std::vector ids = panelp->getSelectedIDs(); if(ids.size() > 0) { LLUUID agent_id = ids[0]; - BOOL online; - online = LLAvatarTracker::instance().isBuddyOnline(agent_id); - LLFloaterAvatarInfo::showFromFriend(agent_id, online); + LLAvatarActions::showProfile(agent_id); } } @@ -580,72 +555,20 @@ void LLPanelFriends::onClickIM(void* user_data) { LLPanelFriends* panelp = (LLPanelFriends*)user_data; - //llinfos << "LLPanelFriends::onClickIM()" << llendl; - LLDynamicArray ids = panelp->getSelectedIDs(); + std::vector ids = panelp->getSelectedIDs(); if(ids.size() > 0) { if(ids.size() == 1) { - LLUUID agent_id = ids[0]; - const LLRelationship* info = LLAvatarTracker::instance().getBuddyInfo(agent_id); - std::string fullname; - if(info && gCacheName->getFullName(agent_id, fullname)) - { - gIMMgr->setFloaterOpen(TRUE); - gIMMgr->addSession(fullname, IM_NOTHING_SPECIAL, agent_id); - } + LLAvatarActions::startIM(ids[0]); } else { - gIMMgr->setFloaterOpen(TRUE); - gIMMgr->addSession("Friends Conference", IM_SESSION_CONFERENCE_START, ids[0], ids); + LLAvatarActions::startConference(ids); } - make_ui_sound("UISndStartIM"); } } -// static -void LLPanelFriends::requestFriendship(const LLUUID& target_id, const std::string& target_name, const std::string& message) -{ - LLUUID calling_card_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); - send_improved_im(target_id, - target_name, - message, - IM_ONLINE, - IM_FRIENDSHIP_OFFERED, - calling_card_folder_id); -} - -// static -bool LLPanelFriends::callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - requestFriendship(notification["payload"]["id"].asUUID(), - notification["payload"]["name"].asString(), - response["message"].asString()); - } - return false; -} - -bool LLPanelFriends::callbackAddFriend(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - // Servers older than 1.25 require the text of the message to be the - // calling card folder ID for the offering user. JC - LLUUID calling_card_folder_id = - gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); - std::string message = calling_card_folder_id.asString(); - requestFriendship(notification["payload"]["id"].asUUID(), - notification["payload"]["name"].asString(), - message); - } - return false; -} - // static void LLPanelFriends::onPickAvatar(const std::vector& names, const std::vector& ids, @@ -653,35 +576,7 @@ void LLPanelFriends::onPickAvatar(const std::vector& names, { if (names.empty()) return; if (ids.empty()) return; - requestFriendshipDialog(ids[0], names[0]); -} - -// static -void LLPanelFriends::requestFriendshipDialog(const LLUUID& id, - const std::string& name) -{ - if(id == gAgentID) - { - LLNotifications::instance().add("AddSelfFriend"); - return; - } - - LLSD args; - args["NAME"] = name; - LLSD payload; - payload["id"] = id; - payload["name"] = name; - // Look for server versions like: Second Life Server 1.24.4.95600 - if (gLastVersionChannel.find(" 1.24.") != std::string::npos) - { - // Old and busted server version, doesn't support friend - // requests with messages. - LLNotifications::instance().add("AddFriend", args, payload, &callbackAddFriend); - } - else - { - LLNotifications::instance().add("AddFriendWithMessage", args, payload, &callbackAddFriendWithMessage); - } + LLAvatarActions::requestFriendshipDialog(ids[0], names[0]); } // static @@ -700,53 +595,14 @@ void LLPanelFriends::onClickAddFriend(void* user_data) void LLPanelFriends::onClickRemove(void* user_data) { LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - //llinfos << "LLPanelFriends::onClickRemove()" << llendl; - LLDynamicArray ids = panelp->getSelectedIDs(); - LLSD args; - if(ids.size() > 0) - { - std::string msgType = "RemoveFromFriends"; - if(ids.size() == 1) - { - LLUUID agent_id = ids[0]; - std::string first, last; - if(gCacheName->getName(agent_id, first, last)) - { - args["FIRST_NAME"] = first; - args["LAST_NAME"] = last; - } - } - else - { - msgType = "RemoveMultipleFromFriends"; - } - LLSD payload; - - for (LLDynamicArray::iterator it = ids.begin(); - it != ids.end(); - ++it) - { - payload["ids"].append(*it); - } - - LLNotifications::instance().add(msgType, - args, - payload, - &handleRemove); - } + LLAvatarActions::removeFriendsDialog(panelp->getSelectedIDs()); } // static void LLPanelFriends::onClickOfferTeleport(void* user_data) { LLPanelFriends* panelp = (LLPanelFriends*)user_data; - - LLDynamicArray ids = panelp->getSelectedIDs(); - if(ids.size() > 0) - { - handle_lure(ids); - } + LLAvatarActions::offerTeleport(panelp->getSelectedIDs()); } // static @@ -754,7 +610,7 @@ void LLPanelFriends::onClickPay(void* user_data) { LLPanelFriends* panelp = (LLPanelFriends*)user_data; - LLDynamicArray ids = panelp->getSelectedIDs(); + std::vector ids = panelp->getSelectedIDs(); if(ids.size() == 1) { handle_pay_by_id(ids[0]); @@ -955,42 +811,3 @@ void LLPanelFriends::sendRightsGrant(rights_map_t& ids) mNumRightsChanged = ids.size(); gAgent.sendReliableMessage(); } - - - -// static -bool LLPanelFriends::handleRemove(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - const LLSD& ids = notification["payload"]["ids"]; - for(LLSD::array_const_iterator itr = ids.beginArray(); itr != ids.endArray(); ++itr) - { - LLUUID id = itr->asUUID(); - const LLRelationship* ip = LLAvatarTracker::instance().getBuddyInfo(id); - if(ip) - { - switch(option) - { - case 0: // YES - if( ip->isRightGrantedTo(LLRelationship::GRANT_MODIFY_OBJECTS)) - { - LLAvatarTracker::instance().empower(id, FALSE); - LLAvatarTracker::instance().notifyObservers(); - } - LLAvatarTracker::instance().terminateBuddy(id); - LLAvatarTracker::instance().notifyObservers(); - gInventory.addChangedMask(LLInventoryObserver::LABEL | LLInventoryObserver::CALLING_CARD, LLUUID::null); - gInventory.notifyObservers(); - break; - - case 1: // NO - default: - llinfos << "No removal performed." << llendl; - break; - } - } - - } - return false; -} diff --git a/indra/newview/llfloaterfriends.h b/indra/newview/llfloaterfriends.h index a5c94ee485..9242f00c91 100644 --- a/indra/newview/llfloaterfriends.h +++ b/indra/newview/llfloaterfriends.h @@ -74,15 +74,6 @@ public: virtual BOOL postBuild(); - // Show a dialog explaining what friendship entails, then request - // friendship. JC - static void requestFriendshipDialog(const LLUUID& target_id, - const std::string& target_name); - - // Just request friendship, no dialog. - static void requestFriendship(const LLUUID& target_id, - const std::string& target_name, const std::string& message); - private: enum FRIENDS_COLUMN_ORDER @@ -115,15 +106,15 @@ private: void confirmModifyRights(rights_map_t& ids, EGrantRevoke command); void sendRightsGrant(rights_map_t& ids); - // return LLUUID::null if nothing is selected - LLDynamicArray getSelectedIDs(); + // return empty vector if nothing is selected + std::vector getSelectedIDs(); // callback methods static void onSelectName(LLUICtrl* ctrl, void* user_data); static bool callbackAddFriend(const LLSD& notification, const LLSD& response); static bool callbackAddFriendWithMessage(const LLSD& notification, const LLSD& response); static void onPickAvatar(const std::vector& names, const std::vector& ids, void* user_data); - static void onMaximumSelect(void* user_data); + static void onMaximumSelect(); static void onClickIM(void* user_data); static void onClickProfile(void* user_data); @@ -135,7 +126,6 @@ private: static void onClickModifyStatus(LLUICtrl* ctrl, void* user_data); - static bool handleRemove(const LLSD& notification, const LLSD& response); bool modifyRightsConfirmation(const LLSD& notification, const LLSD& response, rights_map_t* rights); private: diff --git a/indra/newview/llfloatergesture.cpp b/indra/newview/llfloatergesture.cpp index 6d39d75663..431bc09d86 100644 --- a/indra/newview/llfloatergesture.cpp +++ b/indra/newview/llfloatergesture.cpp @@ -44,7 +44,7 @@ #include "llcombobox.h" #include "llgesturemgr.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llpreviewgesture.h" @@ -53,17 +53,14 @@ #include "llscrollcontainer.h" #include "llscrolllistctrl.h" #include "lltextbox.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "llviewergesture.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llvoavatar.h" #include "llviewercontrol.h" -// static -LLFloaterGesture* LLFloaterGesture::sInstance = NULL; -LLFloaterGestureObserver* LLFloaterGesture::sObserver = NULL; - BOOL item_name_precedes( LLInventoryItem* a, LLInventoryItem* b ) { return LLStringUtil::precedesDict( a->getName(), b->getName() ); @@ -72,35 +69,31 @@ BOOL item_name_precedes( LLInventoryItem* a, LLInventoryItem* b ) class LLFloaterGestureObserver : public LLGestureManagerObserver { public: - LLFloaterGestureObserver() {} + LLFloaterGestureObserver(LLFloaterGesture* floater) : mFloater(floater) {} virtual ~LLFloaterGestureObserver() {} - virtual void changed() { LLFloaterGesture::refreshAll(); } + virtual void changed() { mFloater->refreshAll(); } + +private: + LLFloaterGesture* mFloater; }; //--------------------------------------------------------------------------- // LLFloaterGesture //--------------------------------------------------------------------------- -LLFloaterGesture::LLFloaterGesture() -: LLFloater(std::string("Gesture Floater")) +LLFloaterGesture::LLFloaterGesture(const LLSD& key) + : LLFloater(key) { - sInstance = this; - - sObserver = new LLFloaterGestureObserver; - gGestureManager.addObserver(sObserver); + mObserver = new LLFloaterGestureObserver(this); + LLGestureManager::instance().addObserver(mObserver); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_gesture.xml"); } // virtual LLFloaterGesture::~LLFloaterGesture() { - gGestureManager.removeObserver(sObserver); - delete sObserver; - sObserver = NULL; - - sInstance = NULL; - - // Custom saving rectangle, since load must be done - // after postBuild. - gSavedSettings.setRect("FloaterGestureRect2", getRect()); + LLGestureManager::instance().removeObserver(mObserver); + delete mObserver; + mObserver = NULL; } // virtual @@ -108,55 +101,31 @@ BOOL LLFloaterGesture::postBuild() { std::string label; - // Translate title label = getTitle(); setTitle(label); - childSetCommitCallback("gesture_list", onCommitList, this); - childSetDoubleClickCallback("gesture_list", onClickPlay); + getChild("gesture_list")->setCommitCallback(boost::bind(&LLFloaterGesture::onCommitList, this)); + getChild("gesture_list")->setDoubleClickCallback(boost::bind(&LLFloaterGesture::onClickPlay, this)); - childSetAction("inventory_btn", onClickInventory, this); + getChild("inventory_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickInventory, this)); - childSetAction("edit_btn", onClickEdit, this); + getChild("edit_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickEdit, this)); - childSetAction("play_btn", onClickPlay, this); - childSetAction("stop_btn", onClickPlay, this); + getChild("play_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this)); + getChild("stop_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickPlay, this)); - childSetAction("new_gesture_btn", onClickNew, this); + getChild("new_gesture_btn")->setCommitCallback(boost::bind(&LLFloaterGesture::onClickNew, this)); childSetVisible("play_btn", true); childSetVisible("stop_btn", false); setDefaultBtn("play_btn"); + + buildGestureList(); + + childSetFocus("gesture_list"); - return TRUE; -} - - -// static -void LLFloaterGesture::show() -{ - if (sInstance) - { - sInstance->open(); /*Flawfinder: ignore*/ - return; - } - - LLFloaterGesture *self = new LLFloaterGesture(); - - // Builds and adds to gFloaterView - LLUICtrlFactory::getInstance()->buildFloater(self, "floater_gesture.xml"); - - // Fix up rectangle - LLRect rect = gSavedSettings.getRect("FloaterGestureRect2"); - self->reshape(rect.getWidth(), rect.getHeight()); - self->setRect(rect); - - self->buildGestureList(); - - self->childSetFocus("gesture_list"); - - LLCtrlListInterface *list = self->childGetListInterface("gesture_list"); + LLCtrlListInterface *list = childGetListInterface("gesture_list"); if (list) { const BOOL ascending = TRUE; @@ -164,51 +133,34 @@ void LLFloaterGesture::show() list->selectFirstItem(); } - self->mSelectedID = LLUUID::null; - // Update button labels - onCommitList(NULL, self); - self->open(); /*Flawfinder: ignore*/ + onCommitList(); + + return TRUE; } -// static -void LLFloaterGesture::toggleVisibility() + +void LLFloaterGesture::refreshAll() { - if(sInstance && sInstance->getVisible()) + buildGestureList(); + + LLCtrlListInterface *list = childGetListInterface("gesture_list"); + if (!list) return; + + if (mSelectedID.isNull()) { - sInstance->close(); + list->selectFirstItem(); } else { - show(); - } -} - -// static -void LLFloaterGesture::refreshAll() -{ - if (sInstance) - { - sInstance->buildGestureList(); - - LLCtrlListInterface *list = sInstance->childGetListInterface("gesture_list"); - if (!list) return; - - if (sInstance->mSelectedID.isNull()) + if (! list->setCurrentByID(mSelectedID)) { list->selectFirstItem(); } - else - { - if (! list->setCurrentByID(sInstance->mSelectedID)) - { - list->selectFirstItem(); - } - } - - // Update button labels - onCommitList(NULL, sInstance); } + + // Update button labels + onCommitList(); } void LLFloaterGesture::buildGestureList() @@ -225,13 +177,13 @@ void LLFloaterGesture::buildGestureList() list->operateOnAll(LLCtrlListInterface::OP_DELETE); LLGestureManager::item_map_t::iterator it; - for (it = gGestureManager.mActive.begin(); it != gGestureManager.mActive.end(); ++it) + for (it = LLGestureManager::instance().mActive.begin(); it != LLGestureManager::instance().mActive.end(); ++it) { const LLUUID& item_id = (*it).first; LLMultiGesture* gesture = (*it).second; // Note: Can have NULL item if inventory hasn't arrived yet. - std::string item_name = "Loading..."; + std::string item_name = getString("loading"); LLInventoryItem* item = gInventory.getItem(item_id); if (item) { @@ -254,7 +206,7 @@ void LLFloaterGesture::buildGestureList() element["columns"][0]["column"] = "trigger"; element["columns"][0]["value"] = gesture->mTrigger; element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["font-style"] = font_style; + element["columns"][0]["font"]["style"] = font_style; std::string key_string = LLKeyboard::stringFromKey(gesture->mKey); std::string buffer; @@ -281,42 +233,42 @@ void LLFloaterGesture::buildGestureList() element["columns"][1]["column"] = "shortcut"; element["columns"][1]["value"] = buffer; element["columns"][1]["font"] = "SANSSERIF"; - element["columns"][1]["font-style"] = font_style; + element["columns"][1]["font"]["style"] = font_style; // hidden column for sorting element["columns"][2]["column"] = "key"; element["columns"][2]["value"] = key_string; element["columns"][2]["font"] = "SANSSERIF"; - element["columns"][2]["font-style"] = font_style; + element["columns"][2]["font"]["style"] = font_style; // Only add "playing" if we've got the name, less confusing. JC if (item && gesture->mPlaying) { - item_name += " (Playing)"; + item_name += " " + getString("playing"); } element["columns"][3]["column"] = "name"; element["columns"][3]["value"] = item_name; element["columns"][3]["font"] = "SANSSERIF"; - element["columns"][3]["font-style"] = font_style; + element["columns"][3]["font"]["style"] = font_style; } else { element["columns"][0]["column"] = "trigger"; element["columns"][0]["value"] = ""; element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["font-style"] = font_style; + element["columns"][0]["font"]["style"] = font_style; element["columns"][0]["column"] = "trigger"; element["columns"][0]["value"] = "---"; element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["font-style"] = font_style; + element["columns"][0]["font"]["style"] = font_style; element["columns"][2]["column"] = "key"; element["columns"][2]["value"] = "~~~"; element["columns"][2]["font"] = "SANSSERIF"; - element["columns"][2]["font-style"] = font_style; + element["columns"][2]["font"]["style"] = font_style; element["columns"][3]["column"] = "name"; element["columns"][3]["value"] = item_name; element["columns"][3]["font"] = "SANSSERIF"; - element["columns"][3]["font-style"] = font_style; + element["columns"][3]["font"]["style"] = font_style; } list->addElement(element, ADD_BOTTOM); } @@ -324,104 +276,80 @@ void LLFloaterGesture::buildGestureList() scroll->setScrollPos(current_scroll_pos); } -// static -void LLFloaterGesture::onClickInventory(void* data) +void LLFloaterGesture::onClickInventory() { - LLFloaterGesture* self = (LLFloaterGesture*)data; - - LLCtrlListInterface *list = self->childGetListInterface("gesture_list"); + LLCtrlListInterface *list = childGetListInterface("gesture_list"); if (!list) return; const LLUUID& item_id = list->getCurrentID(); - LLInventoryView* inv = LLInventoryView::showAgentInventory(); + LLFloaterInventory* inv = LLFloaterInventory::showAgentInventory(); if (!inv) return; inv->getPanel()->setSelection(item_id, TRUE); } -// static -void LLFloaterGesture::onClickPlay(void* data) +void LLFloaterGesture::onClickPlay() { - LLFloaterGesture* self = (LLFloaterGesture*)data; - - LLCtrlListInterface *list = self->childGetListInterface("gesture_list"); + LLCtrlListInterface *list = childGetListInterface("gesture_list"); if (!list) return; const LLUUID& item_id = list->getCurrentID(); - if (gGestureManager.isGesturePlaying(item_id)) + if (LLGestureManager::instance().isGesturePlaying(item_id)) { - gGestureManager.stopGesture(item_id); + LLGestureManager::instance().stopGesture(item_id); } else { - gGestureManager.playGesture(item_id); + LLGestureManager::instance().playGesture(item_id); } } class GestureShowCallback : public LLInventoryCallback { public: - GestureShowCallback(std::string &title) - { - mTitle = title; - } void fire(const LLUUID &inv_item) { - LLPreviewGesture::show(mTitle, inv_item, LLUUID::null); + LLPreviewGesture::show(inv_item, LLUUID::null); } -private: - std::string mTitle; }; -// static -void LLFloaterGesture::onClickNew(void* data) +void LLFloaterGesture::onClickNew() { - std::string title("Gesture: "); - title.append("New Gesture"); - LLPointer cb = new GestureShowCallback(title); + LLPointer cb = new GestureShowCallback(); create_inventory_item(gAgent.getID(), gAgent.getSessionID(), LLUUID::null, LLTransactionID::tnull, "New Gesture", "", LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); } -// static -void LLFloaterGesture::onClickEdit(void* data) +void LLFloaterGesture::onClickEdit() { - LLFloaterGesture* self = (LLFloaterGesture*)data; - - LLCtrlListInterface *list = self->childGetListInterface("gesture_list"); + LLCtrlListInterface *list = childGetListInterface("gesture_list"); if (!list) return; const LLUUID& item_id = list->getCurrentID(); LLInventoryItem* item = gInventory.getItem(item_id); if (!item) return; - std::string title("Gesture: "); - title.append(item->getName()); - - LLPreviewGesture* previewp = LLPreviewGesture::show(title, item_id, LLUUID::null); + LLPreviewGesture* previewp = LLPreviewGesture::show(item_id, LLUUID::null); if (!previewp->getHost()) { - previewp->setRect(gFloaterView->findNeighboringPosition(self, previewp)); + previewp->setRect(gFloaterView->findNeighboringPosition(this, previewp)); } } -// static -void LLFloaterGesture::onCommitList(LLUICtrl* ctrl, void* data) +void LLFloaterGesture::onCommitList() { - LLFloaterGesture* self = (LLFloaterGesture*)data; + const LLUUID& item_id = childGetValue("gesture_list").asUUID(); - const LLUUID& item_id = self->childGetValue("gesture_list").asUUID(); - - self->mSelectedID = item_id; - if (gGestureManager.isGesturePlaying(item_id)) + mSelectedID = item_id; + if (LLGestureManager::instance().isGesturePlaying(item_id)) { - self->childSetVisible("play_btn", false); - self->childSetVisible("stop_btn", true); + childSetVisible("play_btn", false); + childSetVisible("stop_btn", true); } else { - self->childSetVisible("play_btn", true); - self->childSetVisible("stop_btn", false); + childSetVisible("play_btn", true); + childSetVisible("stop_btn", false); } } diff --git a/indra/newview/llfloatergesture.h b/indra/newview/llfloatergesture.h index 4e11a10e61..9c1ab27cb0 100644 --- a/indra/newview/llfloatergesture.h +++ b/indra/newview/llfloatergesture.h @@ -41,7 +41,7 @@ #include "lldarray.h" -class LLScrollableContainerView; +class LLScrollContainer; class LLView; class LLButton; class LLLineEditor; @@ -56,32 +56,28 @@ class LLFloaterGesture : public LLFloater { public: - LLFloaterGesture(); + LLFloaterGesture(const LLSD& key); virtual ~LLFloaterGesture(); virtual BOOL postBuild(); - static void show(); - static void toggleVisibility(); - static void refreshAll(); + void refreshAll(); protected: // Reads from the gesture manager's list of active gestures // and puts them in this list. void buildGestureList(); - static void onClickInventory(void* data); - static void onClickEdit(void* data); - static void onClickPlay(void* data); - static void onClickNew(void* data); - static void onCommitList(LLUICtrl* ctrl, void* data); + void onClickInventory(); + void onClickEdit(); + void onClickPlay(); + void onClickNew(); + void onCommitList(); protected: LLUUID mSelectedID; - static LLFloaterGesture* sInstance; - static LLFloaterGestureObserver* sObserver; - static LLFloaterGestureInventoryObserver* sInventoryObserver; + LLFloaterGestureObserver* mObserver; }; diff --git a/indra/newview/llfloatergodtools.cpp b/indra/newview/llfloatergodtools.cpp index 4959a2913e..886f5ec924 100644 --- a/indra/newview/llfloatergodtools.cpp +++ b/indra/newview/llfloatergodtools.cpp @@ -50,6 +50,7 @@ #include "llcombobox.h" #include "lldraghandle.h" #include "llfloater.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llfloatertopobjects.h" #include "lllineeditor.h" @@ -73,36 +74,39 @@ #include "llsurface.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" +#include "lltrans.h" #include "lltransfertargetfile.h" #include "lltransfersourcefile.h" const F32 SECONDS_BETWEEN_UPDATE_REQUESTS = 5.0f; -static LLFloaterGodTools* sGodTools = NULL; - //***************************************************************************** // LLFloaterGodTools //***************************************************************************** -// static -LLFloaterGodTools* LLFloaterGodTools::instance() +void LLFloaterGodTools::onOpen(const LLSD& key) { - if (!sGodTools) + center(); + setFocus(TRUE); +// LLPanel *panel = childGetVisibleTab("GodTools Tabs"); +// if (panel) +// panel->setFocus(TRUE); + if (mPanelObjectTools) + mPanelObjectTools->setTargetAvatar(LLUUID::null); + + if (gAgent.getRegionHost() != mCurrentHost) { - sGodTools = new LLFloaterGodTools(); - sGodTools->open(); /*Flawfinder: ignore*/ - sGodTools->center(); - sGodTools->setFocus(TRUE); + // we're in a new region + sendRegionInfoRequest(); } - return sGodTools; } // static void LLFloaterGodTools::refreshAll() { - LLFloaterGodTools* god_tools = instance(); + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); if (god_tools) { if (gAgent.getRegionHost() != god_tools->mCurrentHost) @@ -115,39 +119,36 @@ void LLFloaterGodTools::refreshAll() -LLFloaterGodTools::LLFloaterGodTools() -: LLFloater(std::string("godtools floater")), +LLFloaterGodTools::LLFloaterGodTools(const LLSD& key) +: LLFloater(key), mCurrentHost(LLHost::invalid), mUpdateTimer() { - LLCallbackMap::map_t factory_map; - factory_map["grid"] = LLCallbackMap(createPanelGrid, this); - factory_map["region"] = LLCallbackMap(createPanelRegion, this); - factory_map["objects"] = LLCallbackMap(createPanelObjects, this); - factory_map["request"] = LLCallbackMap(createPanelRequest, this); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_god_tools.xml", &factory_map); + mFactoryMap["grid"] = LLCallbackMap(createPanelGrid, this); + mFactoryMap["region"] = LLCallbackMap(createPanelRegion, this); + mFactoryMap["objects"] = LLCallbackMap(createPanelObjects, this); + mFactoryMap["request"] = LLCallbackMap(createPanelRequest, this); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_god_tools.xml"); - childSetTabChangeCallback("GodTools Tabs", "grid", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "region", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "objects", onTabChanged, this); - childSetTabChangeCallback("GodTools Tabs", "request", onTabChanged, this); - - sendRegionInfoRequest(); - - childShowTab("GodTools Tabs", "region"); } +BOOL LLFloaterGodTools::postBuild() +{ + sendRegionInfoRequest(); + childShowTab("GodTools Tabs", "region"); + return TRUE; +} // static void* LLFloaterGodTools::createPanelGrid(void *userdata) { - return new LLPanelGridTools("grid"); + return new LLPanelGridTools(); } // static void* LLFloaterGodTools::createPanelRegion(void *userdata) { LLFloaterGodTools* self = (LLFloaterGodTools*)userdata; - self->mPanelRegionTools = new LLPanelRegionTools("region"); + self->mPanelRegionTools = new LLPanelRegionTools(); return self->mPanelRegionTools; } @@ -155,14 +156,14 @@ void* LLFloaterGodTools::createPanelRegion(void *userdata) void* LLFloaterGodTools::createPanelObjects(void *userdata) { LLFloaterGodTools* self = (LLFloaterGodTools*)userdata; - self->mPanelObjectTools = new LLPanelObjectTools("objects"); + self->mPanelObjectTools = new LLPanelObjectTools(); return self->mPanelObjectTools; } // static void* LLFloaterGodTools::createPanelRequest(void *userdata) { - return new LLPanelRequestTools("region"); + return new LLPanelRequestTools(); } LLFloaterGodTools::~LLFloaterGodTools() @@ -170,6 +171,7 @@ LLFloaterGodTools::~LLFloaterGodTools() // children automatically deleted } + U32 LLFloaterGodTools::computeRegionFlags() const { U32 flags = gAgent.getRegion()->getRegionFlags(); @@ -183,15 +185,6 @@ void LLFloaterGodTools::updatePopup(LLCoordGL center, MASK mask) { } -// virtual -void LLFloaterGodTools::onClose(bool app_quitting) -{ - if (sGodTools) - { - sGodTools->setVisible(FALSE); - } -} - // virtual void LLFloaterGodTools::draw() { @@ -209,42 +202,15 @@ void LLFloaterGodTools::draw() LLFloater::draw(); } -// static -void LLFloaterGodTools::show(void *) -{ - LLFloaterGodTools* god_tools = instance(); - god_tools->open(); - LLPanel *panel = god_tools->childGetVisibleTab("GodTools Tabs"); - if (panel) panel->setFocus(TRUE); - if (god_tools->mPanelObjectTools) god_tools->mPanelObjectTools->setTargetAvatar(LLUUID::null); - - if (gAgent.getRegionHost() != god_tools->mCurrentHost) - { - // we're in a new region - god_tools->sendRegionInfoRequest(); - } -} - void LLFloaterGodTools::showPanel(const std::string& panel_name) { childShowTab("GodTools Tabs", panel_name); - open(); /*Flawfinder: ignore*/ + openFloater(); LLPanel *panel = childGetVisibleTab("GodTools Tabs"); - if (panel) panel->setFocus(TRUE); -} - - -// static -void LLFloaterGodTools::onTabChanged(void* data, bool from_click) -{ - LLPanel* panel = (LLPanel*)data; if (panel) - { panel->setFocus(TRUE); - } } - // static void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg) { @@ -297,16 +263,19 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg) regionp->setWaterHeight(water_height); regionp->setBillableFactor(billable_factor); } + + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); + if (!god_tools) return; // push values to god tools, if available - if (sGodTools - && sGodTools->mPanelRegionTools - && sGodTools->mPanelObjectTools - && msg - && gAgent.isGodlike()) + if ( gAgent.isGodlike() + && LLFloaterReg::instanceVisible("god_tools") + && god_tools->mPanelRegionTools + && god_tools->mPanelObjectTools + && msg ) { - LLPanelRegionTools* rtool = sGodTools->mPanelRegionTools; - sGodTools->mCurrentHost = host; + LLPanelRegionTools* rtool = god_tools->mPanelRegionTools; + god_tools->mCurrentHost = host; // store locally rtool->setSimName(sim_name); @@ -319,7 +288,7 @@ void LLFloaterGodTools::processRegionInfo(LLMessageSystem* msg) rtool->setRedirectGridY(redirect_grid_y); rtool->enableAllWidgets(); - LLPanelObjectTools *otool = sGodTools->mPanelObjectTools; + LLPanelObjectTools *otool = god_tools->mPanelObjectTools; otool->setCheckFlags(region_flags); otool->enableAllWidgets(); @@ -362,14 +331,17 @@ void LLFloaterGodTools::sendRegionInfoRequest() void LLFloaterGodTools::sendGodUpdateRegionInfo() { + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); + if (!god_tools) return; + LLViewerRegion *regionp = gAgent.getRegion(); if (gAgent.isGodlike() - && sGodTools->mPanelRegionTools + && god_tools->mPanelRegionTools && regionp && gAgent.getRegionHost() == mCurrentHost) { LLMessageSystem *msg = gMessageSystem; - LLPanelRegionTools *rtool = sGodTools->mPanelRegionTools; + LLPanelRegionTools *rtool = god_tools->mPanelRegionTools; msg->newMessage("GodUpdateRegionInfo"); msg->nextBlockFast(_PREHASH_AgentData); @@ -426,61 +398,34 @@ const F32 PRICE_PER_METER_MIN = 0.f; const F32 PRICE_PER_METER_MAX = 100.f; -LLPanelRegionTools::LLPanelRegionTools(const std::string& title) -: LLPanel(title) +LLPanelRegionTools::LLPanelRegionTools() +: LLPanel() { + mCommitCallbackRegistrar.add("RegionTools.ChangeAnything", boost::bind(&LLPanelRegionTools::onChangeAnything, this)); + mCommitCallbackRegistrar.add("RegionTools.ChangePrelude", boost::bind(&LLPanelRegionTools::onChangePrelude, this)); + mCommitCallbackRegistrar.add("RegionTools.BakeTerrain", boost::bind(&LLPanelRegionTools::onBakeTerrain, this)); + mCommitCallbackRegistrar.add("RegionTools.RevertTerrain", boost::bind(&LLPanelRegionTools::onRevertTerrain, this)); + mCommitCallbackRegistrar.add("RegionTools.SwapTerrain", boost::bind(&LLPanelRegionTools::onSwapTerrain, this)); + mCommitCallbackRegistrar.add("RegionTools.Refresh", boost::bind(&LLPanelRegionTools::onRefresh, this)); + mCommitCallbackRegistrar.add("RegionTools.ApplyChanges", boost::bind(&LLPanelRegionTools::onApplyChanges, this)); + mCommitCallbackRegistrar.add("RegionTools.SelectRegion", boost::bind(&LLPanelRegionTools::onSelectRegion, this)); + mCommitCallbackRegistrar.add("RegionTools.SaveState", boost::bind(&LLPanelRegionTools::onSaveState, this)); } BOOL LLPanelRegionTools::postBuild() { - childSetCommitCallback("region name", onChangeAnything, this); - childSetKeystrokeCallback("region name", onChangeSimName, this); + getChild("region name")->setKeystrokeCallback(onChangeSimName, this); childSetPrevalidate("region name", &LLLineEditor::prevalidatePrintableNotPipe); - - childSetCommitCallback("check prelude", onChangePrelude, this); - childSetCommitCallback("check fixed sun", onChangeAnything, this); - childSetCommitCallback("check reset home", onChangeAnything, this); - childSetCommitCallback("check visible", onChangeAnything, this); - childSetCommitCallback("check damage", onChangeAnything, this); - childSetCommitCallback("block dwell", onChangeAnything, this); - childSetCommitCallback("block terraform", onChangeAnything, this); - childSetCommitCallback("allow transfer", onChangeAnything, this); - childSetCommitCallback("is sandbox", onChangeAnything, this); - - childSetAction("Bake Terrain", onBakeTerrain, this); - childSetAction("Revert Terrain", onRevertTerrain, this); - childSetAction("Swap Terrain", onSwapTerrain, this); - - childSetCommitCallback("estate", onChangeAnything, this); childSetPrevalidate("estate", &LLLineEditor::prevalidatePositiveS32); - - childSetCommitCallback("parentestate", onChangeAnything, this); childSetPrevalidate("parentestate", &LLLineEditor::prevalidatePositiveS32); childDisable("parentestate"); - - childSetCommitCallback("gridposx", onChangeAnything, this); childSetPrevalidate("gridposx", &LLLineEditor::prevalidatePositiveS32); childDisable("gridposx"); - - childSetCommitCallback("gridposy", onChangeAnything, this); childSetPrevalidate("gridposy", &LLLineEditor::prevalidatePositiveS32); childDisable("gridposy"); - - childSetCommitCallback("redirectx", onChangeAnything, this); + childSetPrevalidate("redirectx", &LLLineEditor::prevalidatePositiveS32); - - childSetCommitCallback("redirecty", onChangeAnything, this); childSetPrevalidate("redirecty", &LLLineEditor::prevalidatePositiveS32); - - childSetCommitCallback("billable factor", onChangeAnything, this); - - childSetCommitCallback("land cost", onChangeAnything, this); - - childSetAction("Refresh", onRefresh, this); - childSetAction("Apply", onApplyChanges, this); - - childSetAction("Select Region", onSelectRegion, this); - childSetAction("Autosave now", onSaveState, this); return TRUE; } @@ -567,8 +512,6 @@ void LLPanelRegionTools::enableAllWidgets() childEnable("Autosave now"); } - -// static void LLPanelRegionTools::onSaveState(void* userdata) { if (gAgent.isGodlike()) @@ -765,92 +708,81 @@ void LLPanelRegionTools::setPricePerMeter(S32 price) childSetValue("land cost", price); } -// static -void LLPanelRegionTools::onChangeAnything(LLUICtrl* ctrl, void* userdata) +void LLPanelRegionTools::onChangeAnything() { - if (sGodTools - && userdata - && gAgent.isGodlike()) + if (gAgent.isGodlike()) { - LLPanelRegionTools* region_tools = (LLPanelRegionTools*) userdata; - region_tools->childEnable("Apply"); + childEnable("Apply"); } } -// static -void LLPanelRegionTools::onChangePrelude(LLUICtrl* ctrl, void* data) +void LLPanelRegionTools::onChangePrelude() { // checking prelude auto-checks fixed sun - LLPanelRegionTools* self = (LLPanelRegionTools*)data; - if (self->childGetValue("check prelude").asBoolean()) + if (childGetValue("check prelude").asBoolean()) { - self->childSetValue("check fixed sun", TRUE); - self->childSetValue("check reset home", TRUE); + childSetValue("check fixed sun", TRUE); + childSetValue("check reset home", TRUE); + onChangeAnything(); } // pass on to default onChange handler - onChangeAnything(ctrl, data); + } // static void LLPanelRegionTools::onChangeSimName(LLLineEditor* caller, void* userdata ) { - if (sGodTools - && userdata - && gAgent.isGodlike()) + if (userdata && gAgent.isGodlike()) { LLPanelRegionTools* region_tools = (LLPanelRegionTools*) userdata; region_tools->childEnable("Apply"); } } -//static -void LLPanelRegionTools::onRefresh(void* userdata) + +void LLPanelRegionTools::onRefresh() { + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); + if(!god_tools) return; LLViewerRegion *region = gAgent.getRegion(); - if (region - && sGodTools - && gAgent.isGodlike()) + if (region && gAgent.isGodlike()) { - sGodTools->sendRegionInfoRequest(); + god_tools->sendRegionInfoRequest(); + //LLFloaterGodTools::getInstance()->sendRegionInfoRequest(); + //LLFloaterReg::getTypedInstance("god_tools")->sendRegionInfoRequest(); } } -// static -void LLPanelRegionTools::onApplyChanges(void* userdata) +void LLPanelRegionTools::onApplyChanges() { + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); + if(!god_tools) return; LLViewerRegion *region = gAgent.getRegion(); - if (region - && sGodTools - && userdata - && gAgent.isGodlike()) + if (region && gAgent.isGodlike()) { - LLPanelRegionTools* region_tools = (LLPanelRegionTools*) userdata; - - region_tools->childDisable("Apply"); - sGodTools->sendGodUpdateRegionInfo(); + childDisable("Apply"); + god_tools->sendGodUpdateRegionInfo(); + //LLFloaterReg::getTypedInstance("god_tools")->sendGodUpdateRegionInfo(); } } -// static -void LLPanelRegionTools::onBakeTerrain(void *userdata) +void LLPanelRegionTools::onBakeTerrain() { LLPanelRequestTools::sendRequest("terrain", "bake", gAgent.getRegionHost()); } -// static -void LLPanelRegionTools::onRevertTerrain(void *userdata) +void LLPanelRegionTools::onRevertTerrain() { LLPanelRequestTools::sendRequest("terrain", "revert", gAgent.getRegionHost()); } -// static -void LLPanelRegionTools::onSwapTerrain(void *userdata) + +void LLPanelRegionTools::onSwapTerrain() { LLPanelRequestTools::sendRequest("terrain", "swap", gAgent.getRegionHost()); } -// static -void LLPanelRegionTools::onSelectRegion(void* userdata) +void LLPanelRegionTools::onSelectRegion() { llinfos << "LLPanelRegionTools::onSelectRegion" << llendl; @@ -890,12 +822,13 @@ void LLPanelRegionTools::onSelectRegion(void* userdata) // LEFT R2 RIGHT const F32 HOURS_TO_RADIANS = (2.f*F_PI)/24.f; -const char FLOATER_GRID_ADMIN_TITLE[] = "Grid Administration"; -LLPanelGridTools::LLPanelGridTools(const std::string& name) : - LLPanel(name) +LLPanelGridTools::LLPanelGridTools() : + LLPanel() { + mCommitCallbackRegistrar.add("GridTools.KickAll", boost::bind(&LLPanelGridTools::onClickKickAll, this)); + mCommitCallbackRegistrar.add("GridTools.FlushMapVisibilityCaches", boost::bind(&LLPanelGridTools::onClickFlushMapVisibilityCaches, this)); } // Destroys the object @@ -905,9 +838,6 @@ LLPanelGridTools::~LLPanelGridTools() BOOL LLPanelGridTools::postBuild() { - childSetAction("Kick all users", onClickKickAll, this); - childSetAction("Flush This Region's Map Visibility Caches", onClickFlushMapVisibilityCaches, this); - return TRUE; } @@ -915,14 +845,8 @@ void LLPanelGridTools::refresh() { } - -// static -void LLPanelGridTools::onClickKickAll(void* userdata) +void LLPanelGridTools::onClickKickAll() { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect(left, top, left+400, top-300); - LLNotifications::instance().add("KickAllUsers", LLSD(), LLSD(), LLPanelGridTools::confirmKick); } @@ -961,9 +885,7 @@ bool LLPanelGridTools::finishKick(const LLSD& notification, const LLSD& response return false; } - -// static -void LLPanelGridTools::onClickFlushMapVisibilityCaches(void* data) +void LLPanelGridTools::onClickFlushMapVisibilityCaches() { LLNotifications::instance().add("FlushMapVisibilityCaches", LLSD(), LLSD(), flushMapVisibilityCachesConfirm); } @@ -1017,9 +939,19 @@ bool LLPanelGridTools::flushMapVisibilityCachesConfirm(const LLSD& notification, // LEFT RIGHT // Default constructor -LLPanelObjectTools::LLPanelObjectTools(const std::string& title) -: LLPanel(title), mTargetAvatar() +LLPanelObjectTools::LLPanelObjectTools() + : LLPanel(), + mTargetAvatar() { + mCommitCallbackRegistrar.add("ObjectTools.ChangeAnything", boost::bind(&LLPanelObjectTools::onChangeAnything, this)); + mCommitCallbackRegistrar.add("ObjectTools.DeletePublicOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeletePublicOwnedBy, this)); + mCommitCallbackRegistrar.add("ObjectTools.DeleteAllScriptedOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy, this)); + mCommitCallbackRegistrar.add("ObjectTools.DeleteAllOwnedBy", boost::bind(&LLPanelObjectTools::onClickDeleteAllOwnedBy, this)); + mCommitCallbackRegistrar.add("ObjectTools.ApplyChanges", boost::bind(&LLPanelObjectTools::onApplyChanges, this)); + mCommitCallbackRegistrar.add("ObjectTools.Set", boost::bind(&LLPanelObjectTools::onClickSet, this)); + mCommitCallbackRegistrar.add("ObjectTools.GetTopColliders", boost::bind(&LLPanelObjectTools::onGetTopColliders, this)); + mCommitCallbackRegistrar.add("ObjectTools.GetTopScripts", boost::bind(&LLPanelObjectTools::onGetTopScripts, this)); + mCommitCallbackRegistrar.add("ObjectTools.GetScriptDigest", boost::bind(&LLPanelObjectTools::onGetScriptDigest, this)); } // Destroys the object @@ -1030,22 +962,6 @@ LLPanelObjectTools::~LLPanelObjectTools() BOOL LLPanelObjectTools::postBuild() { - childSetCommitCallback("disable scripts", onChangeAnything, this); - childSetCommitCallback("disable collisions", onChangeAnything, this); - childSetCommitCallback("disable physics", onChangeAnything, this); - - childSetAction("Apply", onApplyChanges, this); - - childSetAction("Set Target", onClickSet, this); - - childSetAction("Delete Target's Scripted Objects On Others Land", onClickDeletePublicOwnedBy, this); - childSetAction("Delete Target's Scripted Objects On *Any* Land", onClickDeleteAllScriptedOwnedBy, this); - childSetAction("Delete *ALL* Of Target's Objects", onClickDeleteAllOwnedBy, this); - - childSetAction("Get Top Colliders", onGetTopColliders, this); - childSetAction("Get Top Scripts", onGetTopScripts, this); - childSetAction("Scripts digest", onGetScriptDigest, this); - return TRUE; } @@ -1054,7 +970,7 @@ void LLPanelObjectTools::setTargetAvatar(const LLUUID &target_id) mTargetAvatar = target_id; if (target_id.isNull()) { - childSetValue("target_avatar_name", "(no target)"); + childSetValue("target_avatar_name", getString("no_target")); } } @@ -1134,35 +1050,35 @@ void LLPanelObjectTools::enableAllWidgets() } -// static -void LLPanelObjectTools::onGetTopColliders(void* userdata) +void LLPanelObjectTools::onGetTopColliders() { - if (sGodTools - && gAgent.isGodlike()) + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; + + if (gAgent.isGodlike()) { - LLFloaterTopObjects::show(); + LLFloaterReg::showInstance("top_objects"); LLFloaterTopObjects::setMode(STAT_REPORT_TOP_COLLIDERS); - LLFloaterTopObjects::onRefresh(NULL); + instance->onRefresh(); } } -// static -void LLPanelObjectTools::onGetTopScripts(void* userdata) +void LLPanelObjectTools::onGetTopScripts() { - if (sGodTools - && gAgent.isGodlike()) + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; + + if (gAgent.isGodlike()) { - LLFloaterTopObjects::show(); + LLFloaterReg::showInstance("top_objects"); LLFloaterTopObjects::setMode(STAT_REPORT_TOP_SCRIPTS); - LLFloaterTopObjects::onRefresh(NULL); + instance->onRefresh(); } } -// static -void LLPanelObjectTools::onGetScriptDigest(void* userdata) +void LLPanelObjectTools::onGetScriptDigest() { - if (sGodTools - && gAgent.isGodlike()) + if (gAgent.isGodlike()) { // get the list of scripts and number of occurences of each // (useful for finding self-replicating objects) @@ -1170,20 +1086,20 @@ void LLPanelObjectTools::onGetScriptDigest(void* userdata) } } -void LLPanelObjectTools::onClickDeletePublicOwnedBy(void* userdata) +void LLPanelObjectTools::onClickDeletePublicOwnedBy() { // Bring up view-modal dialog - LLPanelObjectTools* panelp = (LLPanelObjectTools*)userdata; - if (!panelp->mTargetAvatar.isNull()) + + if (!mTargetAvatar.isNull()) { - panelp->mSimWideDeletesFlags = + mSimWideDeletesFlags = SWD_SCRIPTED_ONLY | SWD_OTHERS_LAND_ONLY; LLSD args; - args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + args["AVATAR_NAME"] = childGetValue("target_avatar_name").asString(); LLSD payload; - payload["avatar_id"] = panelp->mTargetAvatar; - payload["flags"] = (S32)panelp->mSimWideDeletesFlags; + payload["avatar_id"] = mTargetAvatar; + payload["flags"] = (S32)mSimWideDeletesFlags; LLNotifications::instance().add( "GodDeleteAllScriptedPublicObjectsByUser", args, @@ -1192,20 +1108,18 @@ void LLPanelObjectTools::onClickDeletePublicOwnedBy(void* userdata) } } -// static -void LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy(void* userdata) +void LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy() { // Bring up view-modal dialog - LLPanelObjectTools* panelp = (LLPanelObjectTools*)userdata; - if (!panelp->mTargetAvatar.isNull()) + if (!mTargetAvatar.isNull()) { - panelp->mSimWideDeletesFlags = SWD_SCRIPTED_ONLY; + mSimWideDeletesFlags = SWD_SCRIPTED_ONLY; LLSD args; - args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + args["AVATAR_NAME"] = childGetValue("target_avatar_name").asString(); LLSD payload; - payload["avatar_id"] = panelp->mTargetAvatar; - payload["flags"] = (S32)panelp->mSimWideDeletesFlags; + payload["avatar_id"] = mTargetAvatar; + payload["flags"] = (S32)mSimWideDeletesFlags; LLNotifications::instance().add( "GodDeleteAllScriptedObjectsByUser", args, @@ -1214,20 +1128,18 @@ void LLPanelObjectTools::onClickDeleteAllScriptedOwnedBy(void* userdata) } } -// static -void LLPanelObjectTools::onClickDeleteAllOwnedBy(void* userdata) +void LLPanelObjectTools::onClickDeleteAllOwnedBy() { // Bring up view-modal dialog - LLPanelObjectTools* panelp = (LLPanelObjectTools*)userdata; - if (!panelp->mTargetAvatar.isNull()) + if (!mTargetAvatar.isNull()) { - panelp->mSimWideDeletesFlags = 0; + mSimWideDeletesFlags = 0; LLSD args; - args["AVATAR_NAME"] = panelp->childGetValue("target_avatar_name").asString(); + args["AVATAR_NAME"] = childGetValue("target_avatar_name").asString(); LLSD payload; - payload["avatar_id"] = panelp->mTargetAvatar; - payload["flags"] = (S32)panelp->mSimWideDeletesFlags; + payload["avatar_id"] = mTargetAvatar; + payload["flags"] = (S32)mSimWideDeletesFlags; LLNotifications::instance().add( "GodDeleteAllObjectsByUser", args, @@ -1251,11 +1163,10 @@ bool LLPanelObjectTools::callbackSimWideDeletes( const LLSD& notification, const return false; } -void LLPanelObjectTools::onClickSet(void* data) +void LLPanelObjectTools::onClickSet() { - LLPanelObjectTools* panelp = (LLPanelObjectTools*) data; // grandparent is a floater, which can have a dependent - gFloaterView->getParentFloater(panelp)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, data)); + gFloaterView->getParentFloater(this)->addDependentFloater(LLFloaterAvatarPicker::show(callbackAvatarID, this)); } void LLPanelObjectTools::onClickSetBySelection(void* data) @@ -1272,7 +1183,10 @@ void LLPanelObjectTools::onClickSetBySelection(void* data) LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name); panelp->mTargetAvatar = owner_id; - std::string name = "Object " + node->mName + " owned by " + owner_name; + LLStringUtil::format_map_t args; + args["[OBJECT]"] = node->mName; + args["[OWNER]"] = owner_name; + std::string name = LLTrans::getString("GodToolsObjectOwnedBy", args); panelp->childSetValue("target_avatar_name", name); } @@ -1286,33 +1200,25 @@ void LLPanelObjectTools::callbackAvatarID(const std::vector& names, object_tools->refresh(); } - -// static -void LLPanelObjectTools::onChangeAnything(LLUICtrl* ctrl, void* userdata) +void LLPanelObjectTools::onChangeAnything() { - if (sGodTools - && userdata - && gAgent.isGodlike()) + if (gAgent.isGodlike()) { - LLPanelObjectTools* object_tools = (LLPanelObjectTools*) userdata; - object_tools->childEnable("Apply"); + childEnable("Apply"); } } -// static -void LLPanelObjectTools::onApplyChanges(void* userdata) +void LLPanelObjectTools::onApplyChanges() { + LLFloaterGodTools* god_tools = LLFloaterReg::getTypedInstance("god_tools"); + if(!god_tools) return; LLViewerRegion *region = gAgent.getRegion(); - if (region - && sGodTools - && userdata - && gAgent.isGodlike()) + if (region && gAgent.isGodlike()) { - LLPanelObjectTools* object_tools = (LLPanelObjectTools*) userdata; // TODO -- implement this - - object_tools->childDisable("Apply"); - sGodTools->sendGodUpdateRegionInfo(); + childDisable("Apply"); + god_tools->sendGodUpdateRegionInfo(); + //LLFloaterReg::getTypedInstance("god_tools")->sendGodUpdateRegionInfo(); } } @@ -1324,9 +1230,10 @@ void LLPanelObjectTools::onApplyChanges(void* userdata) const std::string SELECTION = "Selection"; const std::string AGENT_REGION = "Agent Region"; -LLPanelRequestTools::LLPanelRequestTools(const std::string& name): - LLPanel(name) +LLPanelRequestTools::LLPanelRequestTools(): + LLPanel() { + mCommitCallbackRegistrar.add("GodTools.Request", boost::bind(&LLPanelRequestTools::onClickRequest, this)); } LLPanelRequestTools::~LLPanelRequestTools() @@ -1335,8 +1242,6 @@ LLPanelRequestTools::~LLPanelRequestTools() BOOL LLPanelRequestTools::postBuild() { - childSetAction("Make Request", onClickRequest, this); - refresh(); return TRUE; @@ -1348,9 +1253,13 @@ void LLPanelRequestTools::refresh() LLCtrlListInterface *list = childGetListInterface("destination"); if (!list) return; - list->operateOnAll(LLCtrlListInterface::OP_DELETE); - list->addSimpleElement(SELECTION); - list->addSimpleElement(AGENT_REGION); + S32 last_item = list->getItemCount(); + + if (last_item >=3) + { + list->selectItemRange(2,last_item); + list->operateOnSelection(LLCtrlListInterface::OP_DELETE); + } for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { @@ -1367,7 +1276,7 @@ void LLPanelRequestTools::refresh() } else { - list->selectByValue(SELECTION); + list->operateOnSelection(LLCtrlListInterface::OP_DESELECT); } } @@ -1393,21 +1302,19 @@ void LLPanelRequestTools::sendRequest(const std::string& request, msg->sendReliable(host); } -// static -void LLPanelRequestTools::onClickRequest(void* data) +void LLPanelRequestTools::onClickRequest() { - LLPanelRequestTools* self = (LLPanelRequestTools*)data; - const std::string dest = self->childGetValue("destination").asString(); + const std::string dest = childGetValue("destination").asString(); if(dest == SELECTION) { - std::string req = self->childGetValue("request"); + std::string req =childGetValue("request"); req = req.substr(0, req.find_first_of(" ")); - std::string param = self->childGetValue("parameter"); + std::string param = childGetValue("parameter"); LLSelectMgr::getInstance()->sendGodlikeRequest(req, param); } else if(dest == AGENT_REGION) { - self->sendRequest(gAgent.getRegionHost()); + sendRequest(gAgent.getRegionHost()); } else { @@ -1419,7 +1326,7 @@ void LLPanelRequestTools::onClickRequest(void* data) if(dest == regionp->getName()) { // found it - self->sendRequest(regionp->getHost()); + sendRequest(regionp->getHost()); } } } diff --git a/indra/newview/llfloatergodtools.h b/indra/newview/llfloatergodtools.h index 75813ca886..ebab1fde11 100644 --- a/indra/newview/llfloatergodtools.h +++ b/indra/newview/llfloatergodtools.h @@ -57,12 +57,11 @@ class LLTextBox; class LLMessageSystem; class LLFloaterGodTools -: public LLFloater + : public LLFloater { + friend class LLFloaterReg; public: - static LLFloaterGodTools* instance(); - enum EGodPanel { PANEL_GRID, @@ -72,9 +71,6 @@ public: PANEL_COUNT }; - static void show(void *); - static void hide(void *); - static void* createPanelGrid(void *userdata); static void* createPanelRegion(void *userdata); static void* createPanelObjects(void *userdata); @@ -84,7 +80,7 @@ public: void showPanel(const std::string& panel_name); - virtual void onClose(bool app_quitting); + virtual void onOpen(const LLSD& key); virtual void draw(); @@ -101,21 +97,21 @@ public: // Send possibly changed values to simulator. void sendGodUpdateRegionInfo(); - static void onTabChanged(void *data, bool from_click); - +private: + + LLFloaterGodTools(const LLSD& key); + ~LLFloaterGodTools(); + protected: U32 computeRegionFlags() const; protected: - LLFloaterGodTools(); - ~LLFloaterGodTools(); + /*virtual*/ BOOL postBuild(); // When the floater is going away, reset any options that need to be // cleared. void resetToolState(); - static LLFloaterGodTools* sInstance; - public: LLPanelRegionTools *mPanelRegionTools; LLPanelObjectTools *mPanelObjectTools; @@ -133,23 +129,24 @@ class LLPanelRegionTools : public LLPanel { public: - LLPanelRegionTools(const std::string& name); + LLPanelRegionTools(); /*virtual*/ ~LLPanelRegionTools(); BOOL postBuild(); /*virtual*/ void refresh(); - static void onSaveState(void* data); - static void onChangeAnything(LLUICtrl* ctrl, void* userdata); - static void onChangePrelude(LLUICtrl* ctrl, void* data); + static void onSaveState(void* userdata); static void onChangeSimName(LLLineEditor* caller, void* userdata); - static void onApplyChanges(void* userdata); - static void onBakeTerrain(void *userdata); - static void onRevertTerrain(void *userdata); - static void onSwapTerrain(void *userdata); - static void onSelectRegion(void *userdata); - static void onRefresh(void* userdata); + + void onChangeAnything(); + void onChangePrelude(); + void onApplyChanges(); + void onBakeTerrain(); + void onRevertTerrain(); + void onSwapTerrain(); + void onSelectRegion(); + void onRefresh(); // set internal checkboxes/spinners/combos const std::string getSimName() const; @@ -194,18 +191,18 @@ class LLPanelGridTools : public LLPanel { public: - LLPanelGridTools(const std::string& name); + LLPanelGridTools(); virtual ~LLPanelGridTools(); BOOL postBuild(); void refresh(); - static void onClickKickAll(void *data); + void onClickKickAll(); static bool confirmKick(const LLSD& notification, const LLSD& response); static bool finishKick(const LLSD& notification, const LLSD& response); static void onDragSunPhase(LLUICtrl *ctrl, void *userdata); - static void onClickFlushMapVisibilityCaches(void* data); + void onClickFlushMapVisibilityCaches(); static bool flushMapVisibilityCachesConfirm(const LLSD& notification, const LLSD& response); protected: @@ -221,7 +218,7 @@ class LLPanelObjectTools : public LLPanel { public: - LLPanelObjectTools(const std::string& name); + LLPanelObjectTools(); /*virtual*/ ~LLPanelObjectTools(); BOOL postBuild(); @@ -234,17 +231,17 @@ public: void enableAllWidgets(); void setCheckFlags(U32 flags); - static void onChangeAnything(LLUICtrl* ctrl, void* data); - static void onApplyChanges(void* data); - static void onClickSet(void* data); + void onChangeAnything(); + void onApplyChanges(); + void onClickSet(); static void callbackAvatarID(const std::vector& names, const std::vector& ids, void* data); - static void onClickDeletePublicOwnedBy(void* data); - static void onClickDeleteAllScriptedOwnedBy(void* data); - static void onClickDeleteAllOwnedBy(void* data); + void onClickDeletePublicOwnedBy(); + void onClickDeleteAllScriptedOwnedBy(); + void onClickDeleteAllOwnedBy(); static bool callbackSimWideDeletes(const LLSD& notification, const LLSD& response); - static void onGetTopColliders(void* data); - static void onGetTopScripts(void* data); - static void onGetScriptDigest(void* data); + void onGetTopColliders(); + void onGetTopScripts(); + void onGetScriptDigest(); static void onClickSetBySelection(void* data); protected: @@ -262,7 +259,7 @@ protected: class LLPanelRequestTools : public LLPanel { public: - LLPanelRequestTools(const std::string& name); + LLPanelRequestTools(); /*virtual*/ ~LLPanelRequestTools(); BOOL postBuild(); @@ -274,7 +271,7 @@ public: const LLHost& host); protected: - static void onClickRequest(void *data); + void onClickRequest(); void sendRequest(const LLHost& host); }; diff --git a/indra/newview/llfloatergroupinvite.cpp b/indra/newview/llfloatergroupinvite.cpp index 08a6269a04..3598479305 100644 --- a/indra/newview/llfloatergroupinvite.cpp +++ b/indra/newview/llfloatergroupinvite.cpp @@ -34,9 +34,8 @@ #include "llfloatergroupinvite.h" #include "llpanelgroupinvite.h" - -const char FLOATER_TITLE[] = "Group Invitation"; -const LLRect FGI_RECT(0, 380, 210, 0); +#include "lltrans.h" +#include "lldraghandle.h" class LLFloaterGroupInvite::impl { @@ -73,25 +72,26 @@ void LLFloaterGroupInvite::impl::closeFloater(void* data) { LLFloaterGroupInvite* floaterp = (LLFloaterGroupInvite*) data; - if ( floaterp ) floaterp->close(); + if ( floaterp ) floaterp->closeFloater(); } //----------------------------------------------------------------------------- // Implementation //----------------------------------------------------------------------------- -LLFloaterGroupInvite::LLFloaterGroupInvite(const std::string& name, - const LLRect &rect, - const std::string& title, - const LLUUID& group_id) -: LLFloater(name, rect, title) +LLFloaterGroupInvite::LLFloaterGroupInvite(const LLUUID& group_id) +: LLFloater(group_id) { - LLRect contents(getRect()); - contents.mTop -= LLFLOATER_HEADER_SIZE; + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + LLRect contents; mImpl = new impl(group_id); - mImpl->mInvitePanelp = new LLPanelGroupInvite("Group Invite Panel", - group_id); + mImpl->mInvitePanelp = new LLPanelGroupInvite(group_id); + + contents = mImpl->mInvitePanelp->getRect(); + contents.mTop -= floater_header_size; + + setTitle (mImpl->mInvitePanelp->getString("GroupInvitation")); mImpl->mInvitePanelp->setCloseCallback(impl::closeFloater, this); @@ -114,6 +114,9 @@ LLFloaterGroupInvite::~LLFloaterGroupInvite() // static void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, std::vector *agent_ids) { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + LLRect contents; + // Make sure group_id isn't null if (group_id.isNull()) { @@ -127,10 +130,12 @@ void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, std::vectormImpl->mInvitePanelp->getRect(); + contents.mTop += floater_header_size; + fgi->setRect(contents); + fgi->getDragHandle()->setRect(contents); + fgi->getDragHandle()->setTitle(fgi->mImpl->mInvitePanelp->getString("GroupInvitation")); impl::sInstances[group_id] = fgi; @@ -143,6 +148,6 @@ void LLFloaterGroupInvite::showForGroup(const LLUUID& group_id, std::vectorcenter(); - fgi->open(); /*Flawfinder: ignore*/ + fgi->openFloater(); fgi->mImpl->mInvitePanelp->update(); } diff --git a/indra/newview/llfloatergroupinvite.h b/indra/newview/llfloatergroupinvite.h index d1485ead91..b3f5d75ac1 100644 --- a/indra/newview/llfloatergroupinvite.h +++ b/indra/newview/llfloatergroupinvite.h @@ -46,10 +46,7 @@ public: static void showForGroup(const LLUUID &group_id, std::vector *agent_ids = NULL); protected: - LLFloaterGroupInvite(const std::string& name, - const LLRect &rect, - const std::string& title, - const LLUUID& group_id = LLUUID::null); + LLFloaterGroupInvite(const LLUUID& group_id = LLUUID::null); class impl; impl* mImpl; diff --git a/indra/newview/llfloatergroups.cpp b/indra/newview/llfloatergroups.cpp index 9e0b0d7230..7a88612f1a 100644 --- a/indra/newview/llfloatergroups.cpp +++ b/indra/newview/llfloatergroups.cpp @@ -41,27 +41,18 @@ #include "llfloatergroups.h" -#include "message.h" #include "roles_constants.h" #include "llagent.h" #include "llbutton.h" -#include "llfloatergroupinfo.h" -#include "llfloaterdirectory.h" -#include "llfocusmgr.h" -#include "llalertdialog.h" -#include "llselectmgr.h" +#include "llgroupactions.h" #include "llscrolllistctrl.h" #include "lltextbox.h" #include "lluictrlfactory.h" -#include "llviewerwindow.h" -#include "llimview.h" +#include "lltrans.h" using namespace LLOldEvents; -// static -std::map LLFloaterGroupPicker::sInstances; - // helper functions void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 powers_mask = GP_ALL_POWERS); @@ -69,44 +60,16 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow /// Class LLFloaterGroupPicker ///---------------------------------------------------------------------------- -// static -LLFloaterGroupPicker* LLFloaterGroupPicker::findInstance(const LLSD& seed) +LLFloaterGroupPicker::LLFloaterGroupPicker(const LLSD& seed) +: LLFloater(seed), + mPowersMask(GP_ALL_POWERS), + mID(seed.asUUID()) { - instance_map_t::iterator found_it = sInstances.find(seed.asUUID()); - if (found_it != sInstances.end()) - { - return found_it->second; - } - return NULL; -} - -// static -LLFloaterGroupPicker* LLFloaterGroupPicker::createInstance(const LLSD &seed) -{ - LLFloaterGroupPicker* pickerp = new LLFloaterGroupPicker(seed); - LLUICtrlFactory::getInstance()->buildFloater(pickerp, "floater_choose_group.xml"); - return pickerp; -} - -LLFloaterGroupPicker::LLFloaterGroupPicker(const LLSD& seed) : - mSelectCallback(NULL), - mCallbackUserdata(NULL), - mPowersMask(GP_ALL_POWERS) -{ - mID = seed.asUUID(); - sInstances.insert(std::make_pair(mID, this)); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_choose_group.xml"); } LLFloaterGroupPicker::~LLFloaterGroupPicker() { - sInstances.erase(mID); -} - -void LLFloaterGroupPicker::setSelectCallback(void (*callback)(LLUUID, void*), - void* userdata) -{ - mSelectCallback = callback; - mCallbackUserdata = userdata; } void LLFloaterGroupPicker::setPowersMask(U64 powers_mask) @@ -118,7 +81,18 @@ void LLFloaterGroupPicker::setPowersMask(U64 powers_mask) BOOL LLFloaterGroupPicker::postBuild() { - init_group_list(getChild("group list"), gAgent.getGroupID(), mPowersMask); + LLScrollListCtrl* list_ctrl = getChild("group list"); + init_group_list(list_ctrl, gAgent.getGroupID(), mPowersMask); + + // Remove group "none" from list. Group "none" is added in init_group_list(). + // Some UI elements use group "none", we need to manually delete it here. + // Group "none" ID is LLUUID:null. + LLCtrlListInterface* group_list = list_ctrl->getListInterface(); + if(group_list) + { + group_list->selectByValue(LLUUID::null); + group_list->operateOnSelection(LLCtrlListInterface::OP_DELETE); + } childSetAction("OK", onBtnOK, this); @@ -126,8 +100,7 @@ BOOL LLFloaterGroupPicker::postBuild() setDefaultBtn("OK"); - childSetDoubleClickCallback("group list", onBtnOK); - childSetUserData("group list", this); + getChild("group list")->setDoubleClickCallback(onBtnOK, this); childEnable("OK"); @@ -143,7 +116,7 @@ void LLFloaterGroupPicker::onBtnOK(void* userdata) void LLFloaterGroupPicker::onBtnCancel(void* userdata) { LLFloaterGroupPicker* self = (LLFloaterGroupPicker*)userdata; - if(self) self->close(); + if(self) self->closeFloater(); } @@ -155,12 +128,9 @@ void LLFloaterGroupPicker::ok() { group_id = group_list->getCurrentID(); } - if(mSelectCallback) - { - mSelectCallback(group_id, mCallbackUserdata); - } + mGroupSelectSignal(group_id); - close(); + closeFloater(); } ///---------------------------------------------------------------------------- @@ -229,8 +199,7 @@ BOOL LLPanelGroups::postBuild() setDefaultBtn("IM"); - childSetDoubleClickCallback("group list", onBtnIM); - childSetUserData("group list", this); + getChild("group list")->setDoubleClickCallback(onBtnIM, this); reset(); @@ -315,113 +284,54 @@ void LLPanelGroups::onBtnSearch(void* userdata) void LLPanelGroups::create() { - llinfos << "LLPanelGroups::create" << llendl; - LLFloaterGroupInfo::showCreateGroup(NULL); + LLGroupActions::createGroup(); } void LLPanelGroups::activate() { - llinfos << "LLPanelGroups::activate" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list) { group_id = group_list->getCurrentID(); } - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ActivateGroup); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_GroupID, group_id); - gAgent.sendReliableMessage(); + LLGroupActions::activate(group_id); } void LLPanelGroups::info() { - llinfos << "LLPanelGroups::info" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { - LLFloaterGroupInfo::showFromUUID(group_id); + LLGroupActions::show(group_id); } } void LLPanelGroups::startIM() { - //llinfos << "LLPanelFriends::onClickIM()" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { - LLGroupData group_data; - if (gAgent.getGroupData(group_id, group_data)) - { - gIMMgr->setFloaterOpen(TRUE); - gIMMgr->addSession( - group_data.mName, - IM_SESSION_GROUP_START, - group_id); - make_ui_sound("UISndStartIM"); - } - else - { - // this should never happen, as starting a group IM session - // relies on you belonging to the group and hence having the group data - make_ui_sound("UISndInvalidOp"); - } + LLGroupActions::startChat(group_id); } } void LLPanelGroups::leave() { - llinfos << "LLPanelGroups::leave" << llendl; LLCtrlListInterface *group_list = childGetListInterface("group list"); LLUUID group_id; if (group_list && (group_id = group_list->getCurrentID()).notNull()) { - S32 count = gAgent.mGroups.count(); - S32 i; - for(i = 0; i < count; ++i) - { - if(gAgent.mGroups.get(i).mID == group_id) - break; - } - if(i < count) - { - LLSD args; - args["GROUP"] = gAgent.mGroups.get(i).mName; - LLSD payload; - payload["group_id"] = group_id; - LLNotifications::instance().add("GroupLeaveConfirmMember", args, payload, callbackLeaveGroup); - } + LLGroupActions::leave(group_id); } } void LLPanelGroups::search() { - LLFloaterDirectory::showGroups(); -} - -// static -bool LLPanelGroups::callbackLeaveGroup(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLUUID group_id = notification["payload"]["group_id"].asUUID(); - if(option == 0) - { - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_LeaveGroupRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, group_id); - gAgent.sendReliableMessage(); - } - return false; + LLGroupActions::search(); } void LLPanelGroups::onGroupList(LLUICtrl* ctrl, void* userdata) @@ -456,7 +366,7 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow element["columns"][0]["column"] = "name"; element["columns"][0]["value"] = group_datap->mName; element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["font-style"] = style; + element["columns"][0]["font"]["style"] = style; group_list->addElement(element, ADD_SORTED); } @@ -472,9 +382,9 @@ void init_group_list(LLScrollListCtrl* ctrl, const LLUUID& highlight_id, U64 pow LLSD element; element["id"] = LLUUID::null; element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = "none"; // *TODO: Translate + element["columns"][0]["value"] = LLTrans::getString("GroupsNone"); element["columns"][0]["font"] = "SANSSERIF"; - element["columns"][0]["font-style"] = style; + element["columns"][0]["font"]["style"] = style; group_list->addElement(element, ADD_TOP); } diff --git a/indra/newview/llfloatergroups.h b/indra/newview/llfloatergroups.h index 3eb3e5af52..489238356d 100644 --- a/indra/newview/llfloatergroups.h +++ b/indra/newview/llfloatergroups.h @@ -47,6 +47,8 @@ #include "lluuid.h" #include "llfloater.h" #include +#include +#include class LLUICtrl; class LLTextBox; @@ -54,13 +56,15 @@ class LLScrollListCtrl; class LLButton; class LLFloaterGroupPicker; -class LLFloaterGroupPicker : public LLFloater, public LLUIFactory > +class LLFloaterGroupPicker : public LLFloater { - friend class LLUIFactory; public: + LLFloaterGroupPicker(const LLSD& seed); ~LLFloaterGroupPicker(); - void setSelectCallback( void (*callback)(LLUUID, void*), - void* userdata); + + // Note: Don't return connection; use boost::bind + boost::signals2::trackable to disconnect slots + typedef boost::signals2::signal signal_t; + void setSelectGroupCallback(const signal_t::slot_type& cb) { mGroupSelectSignal.connect(cb); } void setPowersMask(U64 powers_mask); BOOL postBuild(); @@ -69,7 +73,6 @@ public: static LLFloaterGroupPicker* createInstance(const LLSD& seed); protected: - LLFloaterGroupPicker(const LLSD& seed); void ok(); static void onBtnOK(void* userdata); static void onBtnCancel(void* userdata); @@ -77,8 +80,7 @@ protected: protected: LLUUID mID; U64 mPowersMask; - void (*mSelectCallback)(LLUUID id, void* userdata); - void* mCallbackUserdata; + signal_t mGroupSelectSignal; typedef std::map instance_map_t; static instance_map_t sInstances; diff --git a/indra/newview/llfloaterhandler.cpp b/indra/newview/llfloaterhandler.cpp index f4c7e43a7d..e50a09ed86 100644 --- a/indra/newview/llfloaterhandler.cpp +++ b/indra/newview/llfloaterhandler.cpp @@ -31,7 +31,7 @@ #include "llfloaterhandler.h" #include "llfloater.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" // register with dispatch via global object LLFloaterHandler gFloaterHandler; @@ -54,7 +54,7 @@ LLFloater* get_parent_floater(LLView* view) } -bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLWebBrowserCtrl *web) +bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLMediaCtrl *web) { if (params.size() < 2) return false; LLFloater* floater = NULL; @@ -70,7 +70,7 @@ bool LLFloaterHandler::handle(const LLSD ¶ms, const LLSD &query_map, LLWebBr { if (floater) { - floater->close(); + floater->closeFloater(); return true; } } diff --git a/indra/newview/llfloaterhandler.h b/indra/newview/llfloaterhandler.h index b08f1f35b4..31ea80c12c 100644 --- a/indra/newview/llfloaterhandler.h +++ b/indra/newview/llfloaterhandler.h @@ -39,7 +39,7 @@ class LLFloaterHandler { public: LLFloaterHandler() : LLCommandHandler("floater", true) { } - bool handle(const LLSD& params, const LLSD& query_map, LLWebBrowserCtrl* web); + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web); }; #endif diff --git a/indra/newview/llfloaterhardwaresettings.cpp b/indra/newview/llfloaterhardwaresettings.cpp index 7886e394a3..3c3508b65c 100644 --- a/indra/newview/llfloaterhardwaresettings.cpp +++ b/indra/newview/llfloaterhardwaresettings.cpp @@ -33,27 +33,26 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterhardwaresettings.h" + +// Viewer includes #include "llfloaterpreference.h" #include "llviewerwindow.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llfeaturemanager.h" #include "llstartup.h" - -#include "llradiogroup.h" -#include "lluictrlfactory.h" - -#include "llimagegl.h" #include "pipeline.h" -LLFloaterHardwareSettings* LLFloaterHardwareSettings::sHardwareSettings = NULL; +// Linden library includes +#include "llradiogroup.h" +#include "lluictrlfactory.h" +#include "llwindow.h" +#include "llslider.h" -LLFloaterHardwareSettings::LLFloaterHardwareSettings() : LLFloater(std::string("Hardware Settings Floater")) +LLFloaterHardwareSettings::LLFloaterHardwareSettings(const LLSD& key) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hardware_settings.xml"); - - // load it up - initCallbacks(); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hardware_settings.xml"); } LLFloaterHardwareSettings::~LLFloaterHardwareSettings() @@ -90,10 +89,10 @@ void LLFloaterHardwareSettings::refresh() void LLFloaterHardwareSettings::refreshEnabledState() { - S32 min_tex_mem = LLViewerImageList::getMinVideoRamSetting(); - S32 max_tex_mem = LLViewerImageList::getMaxVideoRamSetting(); - childSetMinValue("GrapicsCardTextureMemory", min_tex_mem); - childSetMaxValue("GrapicsCardTextureMemory", max_tex_mem); + S32 min_tex_mem = LLViewerTextureList::getMinVideoRamSetting(); + S32 max_tex_mem = LLViewerTextureList::getMaxVideoRamSetting(); + getChild("GrapicsCardTextureMemory")->setMinValue(min_tex_mem); + getChild("GrapicsCardTextureMemory")->setMinValue(max_tex_mem); if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") || !gGLManager.mHasVertexBufferObject) @@ -108,48 +107,6 @@ void LLFloaterHardwareSettings::refreshEnabledState() } -// static instance of it -LLFloaterHardwareSettings* LLFloaterHardwareSettings::instance() -{ - if (!sHardwareSettings) - { - sHardwareSettings = new LLFloaterHardwareSettings(); - sHardwareSettings->close(); - } - return sHardwareSettings; -} -void LLFloaterHardwareSettings::show() -{ - LLFloaterHardwareSettings* hardSettings = instance(); - hardSettings->refresh(); - hardSettings->center(); - - // comment in if you want the menu to rebuild each time - //LLUICtrlFactory::getInstance()->buildFloater(hardSettings, "floater_hardware_settings.xml"); - //hardSettings->initCallbacks(); - - hardSettings->open(); -} - -bool LLFloaterHardwareSettings::isOpen() -{ - if (sHardwareSettings != NULL) - { - return true; - } - return false; -} - -// virtual -void LLFloaterHardwareSettings::onClose(bool app_quitting) -{ - if (sHardwareSettings) - { - sHardwareSettings->setVisible(FALSE); - } -} - - //============================================================================ BOOL LLFloaterHardwareSettings::postBuild() @@ -157,7 +114,10 @@ BOOL LLFloaterHardwareSettings::postBuild() childSetAction("OK", onBtnOK, this); refresh(); + center(); + // load it up + initCallbacks(); return TRUE; } @@ -203,7 +163,7 @@ void LLFloaterHardwareSettings::cancel() gSavedSettings.setF32("RenderFogRatio", mFogRatio); gSavedSettings.setBOOL("ProbeHardwareOnStartup", mProbeHardwareOnStartup ); - close(); + closeFloater(); } // static @@ -211,6 +171,7 @@ void LLFloaterHardwareSettings::onBtnOK( void* userdata ) { LLFloaterHardwareSettings *fp =(LLFloaterHardwareSettings *)userdata; fp->apply(); - fp->close(false); + fp->closeFloater(false); } + diff --git a/indra/newview/llfloaterhardwaresettings.h b/indra/newview/llfloaterhardwaresettings.h index 04a33f69dc..3f19d89cbb 100644 --- a/indra/newview/llfloaterhardwaresettings.h +++ b/indra/newview/llfloaterhardwaresettings.h @@ -35,26 +35,21 @@ #include "llfloater.h" -class LLSliderCtrl; - /// Menuing system for all of windlight's functionality class LLFloaterHardwareSettings : public LLFloater { - friend class LLPreferenceCore; + friend class LLFloaterPreference; public: - LLFloaterHardwareSettings(); - virtual ~LLFloaterHardwareSettings(); + LLFloaterHardwareSettings(const LLSD& key); + /*virtual*/ ~LLFloaterHardwareSettings(); - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild(); /// initialize all the callbacks for the menu void initCallbacks(void); - /// one and one instance only - static LLFloaterHardwareSettings* instance(); - /// callback for the menus help button static void onClickHelp(void* data); @@ -69,9 +64,6 @@ public: /// return if the menu exists or not static bool isOpen(); - /// stuff to do on exit - virtual void onClose(bool app_quitting); - /// sync up menu with parameters void refresh(); @@ -85,8 +77,6 @@ public: void refreshEnabledState(); protected: - LLSliderCtrl* mCtrlVideoCardMem; - BOOL mUseVBO; BOOL mUseAniso; U32 mFSAASamples; @@ -96,8 +86,6 @@ protected: BOOL mProbeHardwareOnStartup; private: - // one instance on the inside - static LLFloaterHardwareSettings* sHardwareSettings; }; #endif diff --git a/indra/newview/llfloaterhud.cpp b/indra/newview/llfloaterhud.cpp index 9810bf1009..047dc2fa92 100644 --- a/indra/newview/llfloaterhud.cpp +++ b/indra/newview/llfloaterhud.cpp @@ -36,14 +36,12 @@ // Viewer libs #include "llviewercontrol.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "llalertdialog.h" // Linden libs #include "lluictrlfactory.h" -// statics -LLFloaterHUD* LLFloaterHUD::sInstance = 0; ///---------------------------------------------------------------------------- /// Class LLFloaterHUD @@ -51,12 +49,18 @@ LLFloaterHUD* LLFloaterHUD::sInstance = 0; #define super LLFloater /* superclass */ // Default constructor -LLFloaterHUD::LLFloaterHUD() -: LLFloater(std::string("floater_hud")), +LLFloaterHUD::LLFloaterHUD(const LLSD& key) +: LLFloater(key), mWebBrowser(0) { - // Create floater from its XML definition - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hud.xml"); + // do not build the floater if there the url is empty + if (gSavedSettings.getString("TutorialURL") == "") + { + LLNotifications::instance().add("TutorialNotFound"); + return; + } + + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_hud.xml"); // Don't grab the focus as it will impede performing in-world actions // while using the HUD @@ -68,79 +72,32 @@ LLFloaterHUD::LLFloaterHUD() // Opaque background since we never get the focus setBackgroundOpaque(TRUE); +} - // Position floater based on saved location - LLRect saved_position_rect = gSavedSettings.getRect("FloaterHUDRect2"); - reshape(saved_position_rect.getWidth(), saved_position_rect.getHeight(), FALSE); - setRect(saved_position_rect); - - mWebBrowser = getChild("floater_hud_browser" ); +BOOL LLFloaterHUD::postBuild() +{ + mWebBrowser = getChild("floater_hud_browser" ); if (mWebBrowser) { // Open links in internal browser mWebBrowser->setOpenInExternalBrowser(false); - + // This is a "chrome" floater, so we don't want anything to // take focus (as the user needs to be able to walk with // arrow keys during tutorial). mWebBrowser->setTakeFocusOnClick(false); - + std::string language = LLUI::getLanguage(); std::string base_url = gSavedSettings.getString("TutorialURL"); - + std::string url = base_url + language + "/"; mWebBrowser->navigateTo(url); } - - // Remember the one instance - sInstance = this; -} - -// Get the instance -LLFloaterHUD* LLFloaterHUD::getInstance() -{ - if (!sInstance) - { - new LLFloaterHUD(); - } - return sInstance; + + return TRUE; } // Destructor LLFloaterHUD::~LLFloaterHUD() { - // Save floater position - gSavedSettings.setRect("FloaterHUDRect2", getRect() ); - - // Clear out the one instance if it's ours - if (sInstance == this) - { - sInstance = NULL; - } -} - -// Show the HUD -void LLFloaterHUD::showHUD() -{ - // do not build the floater if there the url is empty - if (gSavedSettings.getString("TutorialURL") == "") - { - LLNotifications::instance().add("TutorialNotFound"); - return; - } - - // Create the instance if necessary - LLFloaterHUD* hud = getInstance(); - hud->open(); - hud->setFrontmost(FALSE); -} - -// Save our visibility state on close in case the user accidentally -// quit the application while the tutorial was visible. -// virtual -void LLFloaterHUD::onClose(bool app_quitting) -{ - bool stay_visible = app_quitting; - gSavedSettings.setBOOL("ShowTutorial", stay_visible); - destroy(); } diff --git a/indra/newview/llfloaterhud.h b/indra/newview/llfloaterhud.h index 2d58685b58..23ff82362a 100644 --- a/indra/newview/llfloaterhud.h +++ b/indra/newview/llfloaterhud.h @@ -35,26 +35,22 @@ #include "llfloater.h" -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLFloaterHUD : public LLFloater { + friend class LLFloaterReg; public: - static LLFloaterHUD* getInstance(); ///< get instance creating if necessary - - static void showHUD(); ///< show the HUD - - // Save our visibility state during close - /*virtual*/ void onClose(bool app_quitting); + BOOL postBuild(); + private: // Handles its own construction and destruction, so private. - LLFloaterHUD(); + LLFloaterHUD(const LLSD& key); /*virtual*/ ~LLFloaterHUD(); private: - LLWebBrowserCtrl* mWebBrowser; ///< the actual web browser control - static LLFloaterHUD* sInstance; + LLMediaCtrl* mWebBrowser; ///< the actual web browser control }; #endif // LL_LLFLOATERHUD_H diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp index 5ff4f735dd..07dbf98a1e 100644 --- a/indra/newview/llfloaterimagepreview.cpp +++ b/indra/newview/llfloaterimagepreview.cpp @@ -56,12 +56,9 @@ #include "llvoavatar.h" #include "pipeline.h" #include "lluictrlfactory.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llstring.h" -//static -S32 LLFloaterImagePreview::sUploadAmount = 10; - const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; @@ -93,9 +90,7 @@ BOOL LLFloaterImagePreview::postBuild() { return FALSE; } - - childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d",sUploadAmount)); - + LLCtrlSelectionInterface* iface = childGetSelectionInterface("clothing_type_combo"); if (iface) { @@ -130,7 +125,9 @@ BOOL LLFloaterImagePreview::postBuild() childDisable("clothing_type_combo"); childDisable("ok_btn"); } - + + getChild("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this)); + return TRUE; } @@ -142,9 +139,6 @@ LLFloaterImagePreview::~LLFloaterImagePreview() clearAllPreviewTextures(); mRawImagep = NULL; - delete mAvatarPreview; - delete mSculptedPreview; - mImagep = NULL ; } @@ -252,7 +246,7 @@ void LLFloaterImagePreview::draw() } else { - mImagep = new LLImageGL(mRawImagep, FALSE) ; + mImagep = LLViewerTextureManager::getLocalTexture(mRawImagep.get(), FALSE) ; gGL.getTexUnit(0)->unbind(mImagep->getTarget()) ; gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mImagep->getTexName()); @@ -294,11 +288,11 @@ void LLFloaterImagePreview::draw() if (selected == 9) { - gGL.getTexUnit(0)->bind(mSculptedPreview->getTexture()); + gGL.getTexUnit(0)->bind(mSculptedPreview); } else { - gGL.getTexUnit(0)->bind(mAvatarPreview->getTexture()); + gGL.getTexUnit(0)->bind(mAvatarPreview); } gGL.begin( LLRender::QUADS ); @@ -606,7 +600,7 @@ void LLFloaterImagePreview::onMouseCaptureLostImagePreview(LLMouseHandler* handl //----------------------------------------------------------------------------- // LLImagePreviewAvatar //----------------------------------------------------------------------------- -LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) +LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) { mNeedsUpdate = TRUE; mTargetJoint = NULL; @@ -617,6 +611,7 @@ LLImagePreviewAvatar::LLImagePreviewAvatar(S32 width, S32 height) : LLDynamicTex mCameraZoom = 1.f; mDummyAvatar = (LLVOAvatar*)gObjectList.createObjectViewer(LL_PCODE_LEGACY_AVATAR, gAgent.getRegion()); + mDummyAvatar->initInstance(); mDummyAvatar->createDrawable(&gPipeline); mDummyAvatar->mIsDummy = TRUE; mDummyAvatar->mSpecialRenderMode = 2; @@ -696,7 +691,7 @@ BOOL LLImagePreviewAvatar::render() glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); - glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f); + glOrtho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); @@ -705,7 +700,7 @@ BOOL LLImagePreviewAvatar::render() LLGLSUIDefault def; gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - gl_rect_2d_simple( mWidth, mHeight ); + gl_rect_2d_simple( mFullWidth, mFullHeight ); glMatrixMode(GL_PROJECTION); gGL.popMatrix(); @@ -727,9 +722,9 @@ BOOL LLImagePreviewAvatar::render() stop_glerror(); - LLViewerCamera::getInstance()->setAspect((F32)mWidth / mHeight); + LLViewerCamera::getInstance()->setAspect((F32)mFullWidth / mFullHeight); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE); + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); LLVertexBuffer::unbind(); avatarp->updateLOD(); @@ -787,7 +782,7 @@ void LLImagePreviewAvatar::pan(F32 right, F32 up) // LLImagePreviewSculpted //----------------------------------------------------------------------------- -LLImagePreviewSculpted::LLImagePreviewSculpted(S32 width, S32 height) : LLDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) +LLImagePreviewSculpted::LLImagePreviewSculpted(S32 width, S32 height) : LLViewerDynamicTexture(width, height, 3, ORDER_MIDDLE, FALSE) { mNeedsUpdate = TRUE; mCameraDistance = 0.f; @@ -870,7 +865,7 @@ BOOL LLImagePreviewSculpted::render() glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); - glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f); + glOrtho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); @@ -878,7 +873,7 @@ BOOL LLImagePreviewSculpted::render() gGL.color4f(0.15f, 0.2f, 0.3f, 1.f); - gl_rect_2d_simple( mWidth, mHeight ); + gl_rect_2d_simple( mFullWidth, mFullHeight ); glMatrixMode(GL_PROJECTION); gGL.popMatrix(); @@ -901,9 +896,9 @@ BOOL LLImagePreviewSculpted::render() stop_glerror(); - LLViewerCamera::getInstance()->setAspect((F32) mWidth / mHeight); + LLViewerCamera::getInstance()->setAspect((F32) mFullWidth / mFullHeight); LLViewerCamera::getInstance()->setView(LLViewerCamera::getInstance()->getDefaultFOV() / mCameraZoom); - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE); + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); const LLVolumeFace &vf = mVolume->getVolumeFace(0); U32 num_indices = vf.mIndices.size(); diff --git a/indra/newview/llfloaterimagepreview.h b/indra/newview/llfloaterimagepreview.h index 6a4de3d3cc..f007697e88 100644 --- a/indra/newview/llfloaterimagepreview.h +++ b/indra/newview/llfloaterimagepreview.h @@ -44,12 +44,14 @@ class LLVOAvatar; class LLTextBox; class LLVertexBuffer; -class LLImagePreviewSculpted : public LLDynamicTexture +class LLImagePreviewSculpted : public LLViewerDynamicTexture { - public: - LLImagePreviewSculpted(S32 width, S32 height); +protected: virtual ~LLImagePreviewSculpted(); + public: + LLImagePreviewSculpted(S32 width, S32 height); + void setPreviewTarget(LLImageRaw *imagep, F32 distance); void setTexture(U32 name) { mTextureName = name; } @@ -73,12 +75,14 @@ class LLImagePreviewSculpted : public LLDynamicTexture }; -class LLImagePreviewAvatar : public LLDynamicTexture +class LLImagePreviewAvatar : public LLViewerDynamicTexture { -public: - LLImagePreviewAvatar(S32 width, S32 height); +protected: virtual ~LLImagePreviewAvatar(); +public: + LLImagePreviewAvatar(S32 width, S32 height); + void setPreviewTarget(const std::string& joint_name, const std::string& mesh_name, LLImageRaw* imagep, F32 distance, BOOL male); void setTexture(U32 name) { mTextureName = name; } void clearPreviewTexture(const std::string& mesh_name); @@ -117,7 +121,6 @@ public: BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); static void onMouseCaptureLostImagePreview(LLMouseHandler*); - static void setUploadAmount(S32 amount) { sUploadAmount = amount; } void clearAllPreviewTextures(); @@ -127,15 +130,14 @@ protected: bool loadImage(const std::string& filename); LLPointer mRawImagep; - LLImagePreviewAvatar* mAvatarPreview; - LLImagePreviewSculpted* mSculptedPreview; + LLPointer mAvatarPreview; + LLPointer mSculptedPreview; S32 mLastMouseX; S32 mLastMouseY; LLRect mPreviewRect; LLRectf mPreviewImageRect; - LLPointer mImagep ; + LLPointer mImagep ; - static S32 sUploadAmount; }; #endif // LL_LLFLOATERIMAGEPREVIEW_H diff --git a/indra/newview/llfloaterinspect.cpp b/indra/newview/llfloaterinspect.cpp index de8a094fa9..e26937e93f 100644 --- a/indra/newview/llfloaterinspect.cpp +++ b/indra/newview/llfloaterinspect.cpp @@ -31,11 +31,15 @@ */ #include "llviewerprecompiledheaders.h" -#include "llfloateravatarinfo.h" + #include "llfloaterinspect.h" + +#include "llfloaterreg.h" #include "llfloatertools.h" +#include "llavataractions.h" #include "llcachename.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" #include "llselectmgr.h" #include "lltoolcomp.h" #include "lltoolmgr.h" @@ -43,19 +47,33 @@ #include "llviewerobject.h" #include "lluictrlfactory.h" -LLFloaterInspect* LLFloaterInspect::sInstance = NULL; +//LLFloaterInspect* LLFloaterInspect::sInstance = NULL; -LLFloaterInspect::LLFloaterInspect(void) : - LLFloater(std::string("Inspect Object")), +LLFloaterInspect::LLFloaterInspect(const LLSD& key) + : LLFloater(key), mDirty(FALSE) { - sInstance = this; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inspect.xml"); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inspect.xml"); + mCommitCallbackRegistrar.add("Inspect.OwnerProfile", boost::bind(&LLFloaterInspect::onClickOwnerProfile, this)); + mCommitCallbackRegistrar.add("Inspect.CreatorProfile", boost::bind(&LLFloaterInspect::onClickCreatorProfile, this)); + mCommitCallbackRegistrar.add("Inspect.SelectObject", boost::bind(&LLFloaterInspect::onSelectObject, this)); +} + +BOOL LLFloaterInspect::postBuild() +{ + mObjectList = getChild("object_list"); +// childSetAction("button owner",onClickOwnerProfile, this); +// childSetAction("button creator",onClickCreatorProfile, this); +// childSetCommitCallback("object_list", onSelectObject, NULL); + + refresh(); + + return TRUE; } LLFloaterInspect::~LLFloaterInspect(void) { - if(!gFloaterTools->getVisible()) + if(!LLFloaterReg::instanceVisible("build")) { if(LLToolMgr::getInstance()->getBaseTool() == LLToolCompInspect::getInstance()) { @@ -66,16 +84,16 @@ LLFloaterInspect::~LLFloaterInspect(void) } else { - gFloaterTools->setFocus(TRUE); + LLFloaterReg::showInstance("build", LLSD(), TRUE); } - sInstance = NULL; + //sInstance = NULL; } - +/* BOOL LLFloaterInspect::isVisible() { return (!!sInstance); -} - +}*/ +/* void LLFloaterInspect::show(void* ignored) { // setForceSelection ensures that the pie menu does not deselect things when it @@ -88,22 +106,29 @@ void LLFloaterInspect::show(void* ignored) sInstance = new LLFloaterInspect; } - sInstance->open(); + sInstance->openFloater(); LLToolMgr::getInstance()->setTransientTool(LLToolCompInspect::getInstance()); LLSelectMgr::getInstance()->setForceSelection(forcesel); // restore previouis value sInstance->mObjectSelection = LLSelectMgr::getInstance()->getSelection(); sInstance->refresh(); } - -void LLFloaterInspect::onClickCreatorProfile(void* ctrl) +*/ +void LLFloaterInspect::onOpen(const LLSD& key) { - if(sInstance->mObjectList->getAllSelected().size() == 0) + BOOL forcesel = LLSelectMgr::getInstance()->setForceSelection(TRUE); + LLToolMgr::getInstance()->setTransientTool(LLToolCompInspect::getInstance()); + LLSelectMgr::getInstance()->setForceSelection(forcesel); // restore previouis value + mObjectSelection = LLSelectMgr::getInstance()->getSelection(); + refresh(); +} +void LLFloaterInspect::onClickCreatorProfile() +{ + if(mObjectList->getAllSelected().size() == 0) { return; } - LLScrollListItem* first_selected = - sInstance->mObjectList->getFirstSelected(); + LLScrollListItem* first_selected =mObjectList->getFirstSelected(); if (first_selected) { @@ -116,19 +141,18 @@ void LLFloaterInspect::onClickCreatorProfile(void* ctrl) return (obj_id == node->getObject()->getID()); } } func(first_selected->getUUID()); - LLSelectNode* node = sInstance->mObjectSelection->getFirstNode(&func); + LLSelectNode* node = mObjectSelection->getFirstNode(&func); if(node) { - LLFloaterAvatarInfo::showFromDirectory(node->mPermissions->getCreator()); + LLAvatarActions::showProfile(node->mPermissions->getCreator()); } } } -void LLFloaterInspect::onClickOwnerProfile(void* ctrl) +void LLFloaterInspect::onClickOwnerProfile() { - if(sInstance->mObjectList->getAllSelected().size() == 0) return; - LLScrollListItem* first_selected = - sInstance->mObjectList->getFirstSelected(); + if(mObjectList->getAllSelected().size() == 0) return; + LLScrollListItem* first_selected =mObjectList->getFirstSelected(); if (first_selected) { @@ -142,46 +166,34 @@ void LLFloaterInspect::onClickOwnerProfile(void* ctrl) return (obj_id == node->getObject()->getID()); } } func(selected_id); - LLSelectNode* node = sInstance->mObjectSelection->getFirstNode(&func); + LLSelectNode* node = mObjectSelection->getFirstNode(&func); if(node) { const LLUUID& owner_id = node->mPermissions->getOwner(); - LLFloaterAvatarInfo::showFromDirectory(owner_id); + LLAvatarActions::showProfile(owner_id); } } } -BOOL LLFloaterInspect::postBuild() -{ - mObjectList = getChild("object_list"); - childSetAction("button owner",onClickOwnerProfile, this); - childSetAction("button creator",onClickCreatorProfile, this); - childSetCommitCallback("object_list", onSelectObject); - return TRUE; -} - -void LLFloaterInspect::onSelectObject(LLUICtrl* ctrl, void* user_data) +void LLFloaterInspect::onSelectObject() { if(LLFloaterInspect::getSelectedUUID() != LLUUID::null) { - sInstance->childSetEnabled("button owner", true); - sInstance->childSetEnabled("button creator", true); + childSetEnabled("button owner", true); + childSetEnabled("button creator", true); } } LLUUID LLFloaterInspect::getSelectedUUID() { - if(sInstance) + if(mObjectList->getAllSelected().size() > 0) { - if(sInstance->mObjectList->getAllSelected().size() > 0) + LLScrollListItem* first_selected =mObjectList->getFirstSelected(); + if (first_selected) { - LLScrollListItem* first_selected = - sInstance->mObjectList->getFirstSelected(); - if (first_selected) - { - return first_selected->getUUID(); - } + return first_selected->getUUID(); } + } return LLUUID::null; } @@ -212,7 +224,6 @@ void LLFloaterInspect::refresh() { LLSelectNode* obj = *iter; LLSD row; - char time[MAX_STRING]; std::string owner_name, creator_name; if (obj->mCreationDate == 0) @@ -221,8 +232,11 @@ void LLFloaterInspect::refresh() } time_t timestamp = (time_t) (obj->mCreationDate/1000000); - LLStringUtil::copy(time, ctime(×tamp), MAX_STRING); - time[24] = '\0'; + std::string timeStr = getString("timeStamp"); + LLSD substitution; + substitution["datetime"] = (S32) timestamp; + LLStringUtil::format (timeStr, substitution); + gCacheName->getFullName(obj->mPermissions->getOwner(), owner_name); gCacheName->getFullName(obj->mPermissions->getCreator(), creator_name); row["id"] = obj->getObject()->getID(); @@ -246,7 +260,7 @@ void LLFloaterInspect::refresh() row["columns"][2]["value"] = creator_name; row["columns"][3]["column"] = "creation_date"; row["columns"][3]["type"] = "text"; - row["columns"][3]["value"] = time; + row["columns"][3]["value"] = timeStr; mObjectList->addElement(row, ADD_TOP); } if(selected_index > -1 && mObjectList->getItemIndex(selected_uuid) == selected_index) @@ -257,7 +271,7 @@ void LLFloaterInspect::refresh() { mObjectList->selectNthItem(0); } - onSelectObject(this, NULL); + onSelectObject(); mObjectList->setScrollPos(pos); } @@ -269,10 +283,7 @@ void LLFloaterInspect::onFocusReceived() void LLFloaterInspect::dirty() { - if(sInstance) - { - sInstance->setDirty(); - } + setDirty(); } void LLFloaterInspect::draw() diff --git a/indra/newview/llfloaterinspect.h b/indra/newview/llfloaterinspect.h index 57bba6864f..ce9485ee74 100644 --- a/indra/newview/llfloaterinspect.h +++ b/indra/newview/llfloaterinspect.h @@ -44,29 +44,33 @@ class LLUICtrl; class LLFloaterInspect : public LLFloater { + friend class LLFloaterReg; public: - virtual ~LLFloaterInspect(void); - static void show(void* ignored = NULL); + +// static void show(void* ignored = NULL); + void onOpen(const LLSD& key); virtual BOOL postBuild(); - static void dirty(); - static LLUUID getSelectedUUID(); + void dirty(); + LLUUID getSelectedUUID(); virtual void draw(); virtual void refresh(); - static BOOL isVisible(); +// static BOOL isVisible(); virtual void onFocusReceived(); - static void onClickCreatorProfile(void* ctrl); - static void onClickOwnerProfile(void* ctrl); - static void onSelectObject(LLUICtrl* ctrl, void* user_data); + void onClickCreatorProfile(); + void onClickOwnerProfile(); + void onSelectObject(); LLScrollListCtrl* mObjectList; protected: // protected members - LLFloaterInspect(); void setDirty() { mDirty = TRUE; } bool mDirty; private: + + LLFloaterInspect(const LLSD& key); + virtual ~LLFloaterInspect(void); // static data - static LLFloaterInspect* sInstance; +// static LLFloaterInspect* sInstance; LLSafeHandle mObjectSelection; }; diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp new file mode 100644 index 0000000000..45a42f994d --- /dev/null +++ b/indra/newview/llfloaterinventory.cpp @@ -0,0 +1,1885 @@ +/** + * @file llfloaterinventory.cpp + * @brief Implementation of the inventory view and associated stuff. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include // for std::pair<> + +#include "llfloaterinventory.h" + +// library includes +#include "llagent.h" +#include "llagentwearables.h" +#include "llcallingcard.h" +#include "llfloaterreg.h" +#include "llsdserialize.h" +#include "llfiltereditor.h" +#include "llspinctrl.h" +#include "llui.h" +#include "message.h" + +// newview includes +#include "llappviewer.h" +#include "llfirstuse.h" +#include "llfloaterchat.h" +#include "llfloatercustomize.h" +#include "llfocusmgr.h" +#include "llfolderview.h" +#include "llgesturemgr.h" +#include "lliconctrl.h" +#include "llimview.h" +#include "llinventorybridge.h" +#include "llinventoryclipboard.h" +#include "llinventorymodel.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewnotecard.h" +#include "llpreviewscript.h" +#include "llpreviewsound.h" +#include "llpreviewtexture.h" +#include "llresmgr.h" +#include "llscrollbar.h" +#include "llscrollcontainer.h" +#include "llselectmgr.h" +#include "lltabcontainer.h" +#include "lltooldraganddrop.h" +#include "lluictrlfactory.h" +#include "llviewerinventory.h" +#include "llviewermessage.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llvoavatarself.h" +#include "llwearablelist.h" + +static LLDefaultChildRegistry::Register r("inventory_panel"); + +//BOOL LLFloaterInventory::sOpenNextNewItem = FALSE; +BOOL LLFloaterInventory::sWearNewClothing = FALSE; +LLUUID LLFloaterInventory::sWearNewClothingTransactionID; + +///---------------------------------------------------------------------------- +/// LLFloaterInventoryFinder +///---------------------------------------------------------------------------- + +LLFloaterInventoryFinder::LLFloaterInventoryFinder(LLFloaterInventory* inventory_view) +: LLFloater(LLSD()), + mFloaterInventory(inventory_view), + mFilter(inventory_view->mActivePanel->getFilter()) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory_view_finder.xml", NULL); + updateElementsFromFilter(); +} + + +void LLFloaterInventoryFinder::onCheckSinceLogoff(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff= self->childGetValue("check_since_logoff"); + + if (!since_logoff && + !( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) ) + { + self->mSpinSinceHours->set(1.0f); + } +} +BOOL LLFloaterInventoryFinder::postBuild() +{ + const LLRect& viewrect = mFloaterInventory->getRect(); + setRect(LLRect(viewrect.mLeft - getRect().getWidth(), viewrect.mTop, viewrect.mLeft, viewrect.mTop - getRect().getHeight())); + + childSetAction("All", selectAllTypes, this); + childSetAction("None", selectNoTypes, this); + + mSpinSinceHours = getChild("spin_hours_ago"); + childSetCommitCallback("spin_hours_ago", onTimeAgo, this); + + mSpinSinceDays = getChild("spin_days_ago"); + childSetCommitCallback("spin_days_ago", onTimeAgo, this); + + // mCheckSinceLogoff = getChild("check_since_logoff"); + childSetCommitCallback("check_since_logoff", onCheckSinceLogoff, this); + + childSetAction("Close", onCloseBtn, this); + + updateElementsFromFilter(); + return TRUE; +} +void LLFloaterInventoryFinder::onTimeAgo(LLUICtrl *ctrl, void *user_data) +{ + LLFloaterInventoryFinder *self = (LLFloaterInventoryFinder *)user_data; + if (!self) return; + + bool since_logoff=true; + if ( self->mSpinSinceDays->get() || self->mSpinSinceHours->get() ) + { + since_logoff = false; + } + self->childSetValue("check_since_logoff", since_logoff); +} + +void LLFloaterInventoryFinder::changeFilter(LLInventoryFilter* filter) +{ + mFilter = filter; + updateElementsFromFilter(); +} + +void LLFloaterInventoryFinder::updateElementsFromFilter() +{ + if (!mFilter) + return; + + // Get data needed for filter display + U32 filter_types = mFilter->getFilterTypes(); + std::string filter_string = mFilter->getFilterSubString(); + LLInventoryFilter::EFolderShow show_folders = mFilter->getShowFolderState(); + U32 hours = mFilter->getHoursAgo(); + + // update the ui elements + LLFloater::setTitle(mFilter->getName()); + childSetValue("check_animation", (S32) (filter_types & 0x1 << LLInventoryType::IT_ANIMATION)); + + childSetValue("check_calling_card", (S32) (filter_types & 0x1 << LLInventoryType::IT_CALLINGCARD)); + childSetValue("check_clothing", (S32) (filter_types & 0x1 << LLInventoryType::IT_WEARABLE)); + childSetValue("check_gesture", (S32) (filter_types & 0x1 << LLInventoryType::IT_GESTURE)); + childSetValue("check_landmark", (S32) (filter_types & 0x1 << LLInventoryType::IT_LANDMARK)); + childSetValue("check_notecard", (S32) (filter_types & 0x1 << LLInventoryType::IT_NOTECARD)); + childSetValue("check_object", (S32) (filter_types & 0x1 << LLInventoryType::IT_OBJECT)); + childSetValue("check_script", (S32) (filter_types & 0x1 << LLInventoryType::IT_LSL)); + childSetValue("check_sound", (S32) (filter_types & 0x1 << LLInventoryType::IT_SOUND)); + childSetValue("check_texture", (S32) (filter_types & 0x1 << LLInventoryType::IT_TEXTURE)); + childSetValue("check_snapshot", (S32) (filter_types & 0x1 << LLInventoryType::IT_SNAPSHOT)); + childSetValue("check_show_empty", show_folders == LLInventoryFilter::SHOW_ALL_FOLDERS); + childSetValue("check_since_logoff", mFilter->isSinceLogoff()); + mSpinSinceHours->set((F32)(hours % 24)); + mSpinSinceDays->set((F32)(hours / 24)); +} + +void LLFloaterInventoryFinder::draw() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_DRAW); + U32 filter = 0xffffffff; + BOOL filtered_by_all_types = TRUE; + + if (!childGetValue("check_animation")) + { + filter &= ~(0x1 << LLInventoryType::IT_ANIMATION); + filtered_by_all_types = FALSE; + } + + + if (!childGetValue("check_calling_card")) + { + filter &= ~(0x1 << LLInventoryType::IT_CALLINGCARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_clothing")) + { + filter &= ~(0x1 << LLInventoryType::IT_WEARABLE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_gesture")) + { + filter &= ~(0x1 << LLInventoryType::IT_GESTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_landmark")) + + + { + filter &= ~(0x1 << LLInventoryType::IT_LANDMARK); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_notecard")) + { + filter &= ~(0x1 << LLInventoryType::IT_NOTECARD); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_object")) + { + filter &= ~(0x1 << LLInventoryType::IT_OBJECT); + filter &= ~(0x1 << LLInventoryType::IT_ATTACHMENT); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_script")) + { + filter &= ~(0x1 << LLInventoryType::IT_LSL); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_sound")) + { + filter &= ~(0x1 << LLInventoryType::IT_SOUND); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_texture")) + { + filter &= ~(0x1 << LLInventoryType::IT_TEXTURE); + filtered_by_all_types = FALSE; + } + + if (!childGetValue("check_snapshot")) + { + filter &= ~(0x1 << LLInventoryType::IT_SNAPSHOT); + filtered_by_all_types = FALSE; + } + + if (!filtered_by_all_types) + { + // don't include folders in filter, unless I've selected everything + filter &= ~(0x1 << LLInventoryType::IT_CATEGORY); + } + + // update the panel, panel will update the filter + mFloaterInventory->mActivePanel->setShowFolderState(getCheckShowEmpty() ? + LLInventoryFilter::SHOW_ALL_FOLDERS : LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mFloaterInventory->mActivePanel->setFilterTypes(filter); + if (getCheckSinceLogoff()) + { + mSpinSinceDays->set(0); + mSpinSinceHours->set(0); + } + U32 days = (U32)mSpinSinceDays->get(); + U32 hours = (U32)mSpinSinceHours->get(); + if (hours > 24) + { + days += hours / 24; + hours = (U32)hours % 24; + mSpinSinceDays->set((F32)days); + mSpinSinceHours->set((F32)hours); + } + hours += days * 24; + mFloaterInventory->mActivePanel->setHoursAgo(hours); + mFloaterInventory->mActivePanel->setSinceLogoff(getCheckSinceLogoff()); + mFloaterInventory->setFilterTextFromFilter(); + + LLFloater::draw(); +} + +BOOL LLFloaterInventoryFinder::getCheckShowEmpty() +{ + return childGetValue("check_show_empty"); +} + +BOOL LLFloaterInventoryFinder::getCheckSinceLogoff() +{ + return childGetValue("check_since_logoff"); +} + +void LLFloaterInventoryFinder::onCloseBtn(void* user_data) +{ + LLFloaterInventoryFinder* finderp = (LLFloaterInventoryFinder*)user_data; + finderp->closeFloater(); +} + +// static +void LLFloaterInventoryFinder::selectAllTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + self->childSetValue("check_animation", TRUE); + self->childSetValue("check_calling_card", TRUE); + self->childSetValue("check_clothing", TRUE); + self->childSetValue("check_gesture", TRUE); + self->childSetValue("check_landmark", TRUE); + self->childSetValue("check_notecard", TRUE); + self->childSetValue("check_object", TRUE); + self->childSetValue("check_script", TRUE); + self->childSetValue("check_sound", TRUE); + self->childSetValue("check_texture", TRUE); + self->childSetValue("check_snapshot", TRUE); + +/* + self->mCheckCallingCard->set(TRUE); + self->mCheckClothing->set(TRUE); + self->mCheckGesture->set(TRUE); + self->mCheckLandmark->set(TRUE); + self->mCheckNotecard->set(TRUE); + self->mCheckObject->set(TRUE); + self->mCheckScript->set(TRUE); + self->mCheckSound->set(TRUE); + self->mCheckTexture->set(TRUE); + self->mCheckSnapshot->set(TRUE);*/ +} + +//static +void LLFloaterInventoryFinder::selectNoTypes(void* user_data) +{ + LLFloaterInventoryFinder* self = (LLFloaterInventoryFinder*)user_data; + if(!self) return; + + /* + self->childSetValue("check_animation", FALSE); + self->mCheckCallingCard->set(FALSE); + self->mCheckClothing->set(FALSE); + self->mCheckGesture->set(FALSE); + self->mCheckLandmark->set(FALSE); + self->mCheckNotecard->set(FALSE); + self->mCheckObject->set(FALSE); + self->mCheckScript->set(FALSE); + self->mCheckSound->set(FALSE); + self->mCheckTexture->set(FALSE); + self->mCheckSnapshot->set(FALSE);*/ + + + self->childSetValue("check_animation", FALSE); + self->childSetValue("check_calling_card", FALSE); + self->childSetValue("check_clothing", FALSE); + self->childSetValue("check_gesture", FALSE); + self->childSetValue("check_landmark", FALSE); + self->childSetValue("check_notecard", FALSE); + self->childSetValue("check_object", FALSE); + self->childSetValue("check_script", FALSE); + self->childSetValue("check_sound", FALSE); + self->childSetValue("check_texture", FALSE); + self->childSetValue("check_snapshot", FALSE); +} + + +///---------------------------------------------------------------------------- +/// LLFloaterInventory +///---------------------------------------------------------------------------- +void LLSaveFolderState::setApply(BOOL apply) +{ + mApply = apply; + // before generating new list of open folders, clear the old one + if(!apply) + { + clearOpenFolders(); + } +} + +void LLSaveFolderState::doFolder(LLFolderViewFolder* folder) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_DO_FOLDER); + if(mApply) + { + // we're applying the open state + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + LLUUID id(bridge->getUUID()); + if(mOpenFolders.find(id) != mOpenFolders.end()) + { + folder->setOpen(TRUE); + } + else + { + // keep selected filter in its current state, this is less jarring to user + if (!folder->isSelected()) + { + folder->setOpen(FALSE); + } + } + } + else + { + // we're recording state at this point + if(folder->isOpen()) + { + LLInvFVBridge* bridge = (LLInvFVBridge*)folder->getListener(); + if(!bridge) return; + mOpenFolders.insert(bridge->getUUID()); + } + } +} + +LLFloaterInventory::LLFloaterInventory(const LLSD& key) + : LLFloater(key) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_INIT); + // Menu Callbacks (non contex menus) + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLFloaterInventory::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.CloseAllFolders", boost::bind(&LLFloaterInventory::closeAllFolders, this)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLFloaterInventory::doCreate, this, _2)); +// mCommitCallbackRegistrar.add("Inventory.NewWindow", boost::bind(&LLFloaterInventory::newWindow, this)); + mCommitCallbackRegistrar.add("Inventory.ShowFilters", boost::bind(&LLFloaterInventory::toggleFindOptions, this)); + mCommitCallbackRegistrar.add("Inventory.ResetFilters", boost::bind(&LLFloaterInventory::resetFilters, this)); + mCommitCallbackRegistrar.add("Inventory.SetSortBy", boost::bind(&LLFloaterInventory::setSortBy, this, _2)); + + // Controls + // *TODO: Just use persistant settings for each of these + U32 sort_order = gSavedSettings.getU32("InventorySortOrder"); + BOOL sort_by_name = ! ( sort_order & LLInventoryFilter::SO_DATE ); + BOOL sort_folders_by_name = ( sort_order & LLInventoryFilter::SO_FOLDERS_BY_NAME ); + BOOL sort_system_folders_to_top = ( sort_order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ); + + gSavedSettings.declareBOOL("Inventory.SortByName", sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SortByDate", !sort_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.FoldersAlwaysByName", sort_folders_by_name, "Declared in code", FALSE); + gSavedSettings.declareBOOL("Inventory.SystemFoldersToTop", sort_system_folders_to_top, "Declared in code", FALSE); + + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); + + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_inventory.xml"); +} + +BOOL LLFloaterInventory::postBuild() +{ + gInventory.addObserver(this); + + mFilterTabs = getChild("inventory filter tabs"); + mFilterTabs->setCommitCallback(boost::bind(&LLFloaterInventory::onFilterSelected, this)); + + //panel->getFilter()->markDefault(); + + // Set up the default inv. panel/filter settings. + mActivePanel = getChild("All Items"); + if (mActivePanel) + { + // "All Items" is the previous only view, so it gets the InventorySortOrder + mActivePanel->setSortOrder(gSavedSettings.getU32("InventorySortOrder")); + mActivePanel->getFilter()->markDefault(); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + mActivePanel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, mActivePanel, _1, _2)); + } + LLInventoryPanel* recent_items_panel = getChild("Recent Items"); + if (recent_items_panel) + { + recent_items_panel->setSinceLogoff(TRUE); + recent_items_panel->setSortOrder(LLInventoryFilter::SO_DATE); + recent_items_panel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + recent_items_panel->getFilter()->markDefault(); + recent_items_panel->setSelectCallback(boost::bind(&LLInventoryPanel::onSelectionChange, recent_items_panel, _1, _2)); + } + + // Now load the stored settings from disk, if available. + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llinfos << "LLFloaterInventory::init: reading from " << filterSaveName << llendl; + llifstream file(filterSaveName.str()); + LLSD savedFilterState; + if (file.is_open()) + { + LLSDSerialize::fromXML(savedFilterState, file); + file.close(); + + // Load the persistent "Recent Items" settings. + // Note that the "All Items" settings do not persist. + if(recent_items_panel) + { + if(savedFilterState.has(recent_items_panel->getFilter()->getName())) + { + LLSD recent_items = savedFilterState.get( + recent_items_panel->getFilter()->getName()); + recent_items_panel->getFilter()->fromLLSD(recent_items); + } + } + + } + + + mFilterEditor = getChild("inventory search editor"); + if (mFilterEditor) + { + mFilterEditor->setCommitCallback(boost::bind(&LLFloaterInventory::onFilterEdit, this, _2)); + } + + // *TODO:Get the cost info from the server + const std::string upload_cost("10"); + childSetLabelArg("Upload Image", "[COST]", upload_cost); + childSetLabelArg("Upload Sound", "[COST]", upload_cost); + childSetLabelArg("Upload Animation", "[COST]", upload_cost); + childSetLabelArg("Bulk Upload", "[COST]", upload_cost); + + return TRUE; +} + +// Destroys the object +LLFloaterInventory::~LLFloaterInventory( void ) +{ + // Save the filters state. + LLSD filterRoot; + LLInventoryPanel* all_items_panel = getChild("All Items"); + if (all_items_panel) + { + LLInventoryFilter* filter = all_items_panel->getFilter(); + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + + LLInventoryPanel* recent_items_panel = getChild("Recent Items"); + if (recent_items_panel) + { + LLInventoryFilter* filter = recent_items_panel->getFilter(); + LLSD filterState; + filter->toLLSD(filterState); + filterRoot[filter->getName()] = filterState; + } + + std::ostringstream filterSaveName; + filterSaveName << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "filters.xml"); + llofstream filtersFile(filterSaveName.str()); + if(!LLSDSerialize::toPrettyXML(filterRoot, filtersFile)) + { + llwarns << "Could not write to filters save file " << filterSaveName << llendl; + } + else + filtersFile.close(); + + gInventory.removeObserver(this); + delete mSavedFolderState; +} + +void LLFloaterInventory::draw() +{ + if (LLInventoryModel::isEverythingFetched()) + { + LLLocale locale(LLLocale::USER_LOCALE); + std::ostringstream title; + //title << "Inventory"; + title<getIntegerString(item_count_string, gInventory.getItemCount()); + title << " (" << item_count_string << getString("Items")<<")"; + //TODO:: Translate mFilterText + title << mFilterText; + setTitle(title.str()); + } + LLFloater::draw(); +} + +void LLOpenFilteredFolders::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLOpenFilteredFolders::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + // if this folder didn't pass the filter, and none of its descendants did + else if (!folder->getFiltered() && !folder->hasFilteredDescendants()) + { + folder->setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_NO); + } +} + +void LLSelectFirstFilteredItem::doItem(LLFolderViewItem *item) +{ + if (item->getFiltered() && !mItemSelected) + { + item->getRoot()->setSelection(item, FALSE, FALSE); + if (item->getParentFolder()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + item->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLSelectFirstFilteredItem::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getFiltered() && !mItemSelected) + { + folder->getRoot()->setSelection(folder, FALSE, FALSE); + if (folder->getParentFolder()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + folder->getRoot()->scrollToShowSelection(); + mItemSelected = TRUE; + } +} + +void LLOpenFoldersWithSelection::doItem(LLFolderViewItem *item) +{ + if (item->getParentFolder() && item->isSelected()) + { + item->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder) +{ + if (folder->getParentFolder() && folder->isSelected()) + { + folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } +} + +void LLFloaterInventory::startSearch() +{ + // this forces focus to line editor portion of search editor + if (mFilterEditor) + { + mFilterEditor->focusFirstItem(TRUE); + } +} + +void LLFloaterInventory::onOpen(const LLSD& key) +{ + LLFirstUse::useInventory(); +} + +BOOL LLFloaterInventory::handleKeyHere(KEY key, MASK mask) +{ + LLFolderView* root_folder = mActivePanel ? mActivePanel->getRootFolder() : NULL; + if (root_folder) + { + // first check for user accepting current search results + if (mFilterEditor + && mFilterEditor->hasFocus() + && (key == KEY_RETURN + || key == KEY_DOWN) + && mask == MASK_NONE) + { + // move focus to inventory proper + mActivePanel->setFocus(TRUE); + root_folder->scrollToShowSelection(); + return TRUE; + } + + if (mActivePanel->hasFocus() && key == KEY_UP) + { + startSearch(); + } + } + + return LLFloater::handleKeyHere(key, mask); + +} + +void LLFloaterInventory::changed(U32 mask) +{ + std::ostringstream title; + //title << "Inventory"; + title<getIntegerString(item_count_string, gInventory.getItemCount()); + title << " ( "<< getString("Fetched") << item_count_string << getString("Items")<<")"; + } + //TODO:: Translate mFilterText + title << mFilterText; + setTitle(title.str()); + +} + +//---------------------------------------------------------------------------- +// menu callbacks + +void LLFloaterInventory::doToSelected(const LLSD& userdata) +{ + getPanel()->getRootFolder()->doToSelected(&gInventory, userdata); +} + +void LLFloaterInventory::closeAllFolders() +{ + getPanel()->getRootFolder()->closeAllFolders(); +} + +void LLFloaterInventory::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(getPanel()->getRootFolder(), NULL, userdata); +} + +void LLFloaterInventory::resetFilters() +{ + LLFloaterInventoryFinder *finder = getFinder(); + getActivePanel()->getFilter()->resetDefault(); + if (finder) + { + finder->updateElementsFromFilter(); + } + + setFilterTextFromFilter(); +} + +void LLFloaterInventory::setSortBy(const LLSD& userdata) +{ + std::string sort_field = userdata.asString(); + if (sort_field == "name") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order & ~LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", TRUE ); + gSavedSettings.setBOOL("Inventory.SortByDate", FALSE ); + } + else if (sort_field == "date") + { + U32 order = getActivePanel()->getSortOrder(); + getActivePanel()->setSortOrder( order | LLInventoryFilter::SO_DATE ); + + gSavedSettings.setBOOL("Inventory.SortByName", FALSE ); + gSavedSettings.setBOOL("Inventory.SortByDate", TRUE ); + } + else if (sort_field == "foldersalwaysbyname") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_FOLDERS_BY_NAME ) + { + order &= ~LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_FOLDERS_BY_NAME; + + gSavedSettings.setBOOL("Inventory.FoldersAlwaysByName", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } + else if (sort_field == "systemfolderstotop") + { + U32 order = getActivePanel()->getSortOrder(); + if ( order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP ) + { + order &= ~LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", FALSE ); + } + else + { + order |= LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP; + + gSavedSettings.setBOOL("Inventory.SystemFoldersToTop", TRUE ); + } + getActivePanel()->setSortOrder( order ); + } +} + +//---------------------------------------------------------------------------- + +// static +LLFloaterInventory* LLFloaterInventory::showAgentInventory() +{ + LLFloaterInventory* iv = NULL; + if (!gAgent.cameraMouselook()) + { + iv = LLFloaterReg::showTypedInstance("inventory", LLSD()); + } + return iv; +} + +// static +LLFloaterInventory* LLFloaterInventory::getActiveInventory() +{ + LLFloaterInventory* res = NULL; + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + S32 z_min = S32_MAX; + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterInventory* iv = dynamic_cast(*iter); + if (iv) + { + S32 z_order = gFloaterView->getZOrder(iv); + if (z_order < z_min) + { + res = iv; + z_min = z_order; + } + } + } + return res; +} + +// static +void LLFloaterInventory::cleanup() +{ + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end();) + { + LLFloaterInventory* iv = dynamic_cast(*iter++); + if (iv) + { + iv->destroy(); + } + } +} + +void LLFloaterInventory::toggleFindOptions() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_VIEW_TOGGLE); + LLFloater *floater = getFinder(); + if (!floater) + { + LLFloaterInventoryFinder * finder = new LLFloaterInventoryFinder(this); + mFinderHandle = finder->getHandle(); + finder->openFloater(); + addDependentFloater(mFinderHandle); + + // start background fetch of folders + gInventory.startBackgroundFetch(); + } + else + { + floater->closeFloater(); + } +} + +// static +BOOL LLFloaterInventory::filtersVisible(void* user_data) +{ + LLFloaterInventory* self = (LLFloaterInventory*)user_data; + if(!self) return FALSE; + + return self->getFinder() != NULL; +} + +void LLFloaterInventory::onClearSearch() +{ + LLFloater *finder = getFinder(); + if (mActivePanel) + { + mActivePanel->setFilterSubString(LLStringUtil::null); + mActivePanel->setFilterTypes(0xffffffff); + } + + if (finder) + { + LLFloaterInventoryFinder::selectAllTypes(finder); + } + + // re-open folders that were initially open + if (mActivePanel) + { + mSavedFolderState->setApply(TRUE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + mActivePanel->getRootFolder()->applyFunctorRecursively(opener); + mActivePanel->getRootFolder()->scrollToShowSelection(); + } +} + +void LLFloaterInventory::onFilterEdit(const std::string& search_string ) +{ + if (search_string == "") + { + onClearSearch(); + } + if (!mActivePanel) + { + return; + } + + gInventory.startBackgroundFetch(); + + std::string uppercase_search_string = search_string; + LLStringUtil::toUpper(uppercase_search_string); + if (mActivePanel->getFilterSubString().empty() && uppercase_search_string.empty()) + { + // current filter and new filter empty, do nothing + return; + } + + // save current folder open state if no filter currently applied + if (!mActivePanel->getRootFolder()->isFilterModified()) + { + mSavedFolderState->setApply(FALSE); + mActivePanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + } + + // set new filter string + mActivePanel->setFilterSubString(uppercase_search_string); +} + + + //static + BOOL LLFloaterInventory::incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward) + { + LLFloaterInventory* active_view = NULL; + + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("inventory"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); iter != inst_list.end(); ++iter) + { + LLFloaterInventory* iv = dynamic_cast(*iter); + if (iv) + { + if (gFocusMgr.childHasKeyboardFocus(iv)) + { + active_view = iv; + break; + } + } + } + + if (!active_view) + { + return FALSE; + } + + std::string search_string(find_text); + + if (search_string.empty()) + { + return FALSE; + } + + if (active_view->mActivePanel && + active_view->mActivePanel->getRootFolder()->search(first_item, search_string, backward)) + { + return TRUE; + } + + return FALSE; + } + +void LLFloaterInventory::onFilterSelected() +{ + // Find my index + mActivePanel = (LLInventoryPanel*)childGetVisibleTab("inventory filter tabs"); + + if (!mActivePanel) + { + return; + } + LLInventoryFilter* filter = mActivePanel->getFilter(); + LLFloaterInventoryFinder *finder = getFinder(); + if (finder) + { + finder->changeFilter(filter); + } + if (filter->isActive()) + { + // If our filter is active we may be the first thing requiring a fetch so we better start it here. + gInventory.startBackgroundFetch(); + } + setFilterTextFromFilter(); +} + +BOOL LLFloaterInventory::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + // Check to see if we are auto scrolling from the last frame + LLInventoryPanel* panel = (LLInventoryPanel*)this->getActivePanel(); + BOOL needsToScroll = panel->getScrollableContainer()->autoScroll(x, y); + if(mFilterTabs) + { + if(needsToScroll) + { + mFilterTabs->startDragAndDropDelayTimer(); + } + } + + BOOL handled = LLFloater::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + return handled; +} +const std::string& get_item_icon_name(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ) +{ + EInventoryIcon idx = OBJECT_ICON_NAME; + if ( item_is_multi ) + { + idx = OBJECT_MULTI_ICON_NAME; + } + + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + if(LLInventoryType::IT_SNAPSHOT == inventory_type) + { + idx = SNAPSHOT_ICON_NAME; + } + else + { + idx = TEXTURE_ICON_NAME; + } + break; + + case LLAssetType::AT_SOUND: + idx = SOUND_ICON_NAME; + break; + case LLAssetType::AT_CALLINGCARD: + if(attachment_point!= 0) + { + idx = CALLINGCARD_ONLINE_ICON_NAME; + } + else + { + idx = CALLINGCARD_OFFLINE_ICON_NAME; + } + break; + case LLAssetType::AT_LANDMARK: + if(attachment_point!= 0) + { + idx = LANDMARK_VISITED_ICON_NAME; + } + else + { + idx = LANDMARK_ICON_NAME; + } + break; + case LLAssetType::AT_SCRIPT: + case LLAssetType::AT_LSL_TEXT: + case LLAssetType::AT_LSL_BYTECODE: + idx = SCRIPT_ICON_NAME; + break; + case LLAssetType::AT_CLOTHING: + idx = CLOTHING_ICON_NAME; + case LLAssetType::AT_BODYPART : + if(LLAssetType::AT_BODYPART == asset_type) + { + idx = BODYPART_ICON_NAME; + } + switch(LLInventoryItem::II_FLAGS_WEARABLES_MASK & attachment_point) + { + case WT_SHAPE: + idx = BODYPART_SHAPE_ICON_NAME; + break; + case WT_SKIN: + idx = BODYPART_SKIN_ICON_NAME; + break; + case WT_HAIR: + idx = BODYPART_HAIR_ICON_NAME; + break; + case WT_EYES: + idx = BODYPART_EYES_ICON_NAME; + break; + case WT_SHIRT: + idx = CLOTHING_SHIRT_ICON_NAME; + break; + case WT_PANTS: + idx = CLOTHING_PANTS_ICON_NAME; + break; + case WT_SHOES: + idx = CLOTHING_SHOES_ICON_NAME; + break; + case WT_SOCKS: + idx = CLOTHING_SOCKS_ICON_NAME; + break; + case WT_JACKET: + idx = CLOTHING_JACKET_ICON_NAME; + break; + case WT_GLOVES: + idx = CLOTHING_GLOVES_ICON_NAME; + break; + case WT_UNDERSHIRT: + idx = CLOTHING_UNDERSHIRT_ICON_NAME; + break; + case WT_UNDERPANTS: + idx = CLOTHING_UNDERPANTS_ICON_NAME; + break; + case WT_SKIRT: + idx = CLOTHING_SKIRT_ICON_NAME; + break; + case WT_ALPHA: + idx = CLOTHING_ALPHA_ICON_NAME; + break; + case WT_TATTOO: + idx = CLOTHING_TATTOO_ICON_NAME; + break; + default: + // no-op, go with choice above + break; + } + break; + case LLAssetType::AT_NOTECARD: + idx = NOTECARD_ICON_NAME; + break; + case LLAssetType::AT_ANIMATION: + idx = ANIMATION_ICON_NAME; + break; + case LLAssetType::AT_GESTURE: + idx = GESTURE_ICON_NAME; + break; + case LLAssetType::AT_FAVORITE: + //TODO - need bette idx + idx = LANDMARK_ICON_NAME; + break; + case LLAssetType::AT_LINK: + idx = LINKITEM_ICON_NAME; + break; + case LLAssetType::AT_LINK_FOLDER: + idx = LINKFOLDER_ICON_NAME; + break; + default: + break; + } + + return ICON_NAME[idx]; +} + +LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi) +{ + const std::string& icon_name = get_item_icon_name(asset_type, inventory_type, attachment_point, item_is_multi ); + return LLUI::getUIImage(icon_name); +} + +const std::string LLInventoryPanel::DEFAULT_SORT_ORDER = std::string("InventorySortOrder"); +const std::string LLInventoryPanel::RECENTITEMS_SORT_ORDER = std::string("RecentItemsSortOrder"); +const std::string LLInventoryPanel::INHERIT_SORT_ORDER = std::string(""); + +LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) +: LLPanel(p), + mInventoryObserver(NULL), + mFolders(NULL), + mScroller(NULL), + mSortOrderSetting(p.sort_order_setting), + mInventory(p.inventory), + mAllowMultiSelect(p.allow_multi_select) +{ + // contex menu callbacks + mCommitCallbackRegistrar.add("Inventory.DoToSelected", boost::bind(&LLInventoryPanel::doToSelected, this, _2)); + mCommitCallbackRegistrar.add("Inventory.EmptyTrash", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyTrash", LLAssetType::AT_TRASH)); + mCommitCallbackRegistrar.add("Inventory.EmptyLostAndFound", boost::bind(&LLInventoryModel::emptyFolderType, &gInventory, "ConfirmEmptyLostAndFound", LLAssetType::AT_LOST_AND_FOUND)); + mCommitCallbackRegistrar.add("Inventory.DoCreate", boost::bind(&LLInventoryPanel::doCreate, this, _2)); + mCommitCallbackRegistrar.add("Inventory.AttachObject", boost::bind(&LLInventoryPanel::attachObject, this, _2)); + mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this)); + + setBackgroundColor(LLUIColorTable::instance().getColor("InventoryBackgroundColor")); + setBackgroundVisible(TRUE); + setBackgroundOpaque(TRUE); +} + +BOOL LLInventoryPanel::postBuild() +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_POST_BUILD); + + mCommitCallbackRegistrar.pushScope(); // registered as a widget; need to push callback scope ourselves + + // create root folder + { + LLRect folder_rect(0, + 0, + getRect().getWidth(), + 0); + LLFolderView::Params p; + p.name = getName(); + p.rect = folder_rect; + p.parent_panel = this; + mFolders = LLUICtrlFactory::create(p); + mFolders->setAllowMultiSelect(mAllowMultiSelect); + } + + mCommitCallbackRegistrar.popScope(); + + mFolders->setCallbackRegistrar(&mCommitCallbackRegistrar); + + // scroller + { + LLRect scroller_view_rect = getRect(); + scroller_view_rect.translate(-scroller_view_rect.mLeft, -scroller_view_rect.mBottom); + LLScrollContainer::Params p; + p.name("Inventory Scroller"); + p.rect(scroller_view_rect); + p.follows.flags(FOLLOWS_ALL); + p.reserve_scroll_corner(true); + p.tab_stop(true); + mScroller = LLUICtrlFactory::create(p); + } + addChild(mScroller); + mScroller->addChild(mFolders); + + mFolders->setScrollContainer(mScroller); + + // set up the callbacks from the inventory we're viewing, and then + // build everything. + mInventoryObserver = new LLInventoryPanelObserver(this); + mInventory->addObserver(mInventoryObserver); + rebuildViewsFor(LLUUID::null, LLInventoryObserver::ADD); + + // bit of a hack to make sure the inventory is open. + mFolders->openFolder(std::string("My Inventory")); + + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + setSortOrder(gSavedSettings.getU32(mSortOrderSetting)); + } + else + { + setSortOrder(gSavedSettings.getU32(DEFAULT_SORT_ORDER)); + } + mFolders->setSortOrder(mFolders->getFilter()->getSortOrder()); + + return TRUE; +} + +LLInventoryPanel::~LLInventoryPanel() +{ + // should this be a global setting? + if (mFolders) + { + U32 sort_order = mFolders->getSortOrder(); + if (mSortOrderSetting != INHERIT_SORT_ORDER) + { + gSavedSettings.setU32(mSortOrderSetting, sort_order); + } + } + + // LLView destructor will take care of the sub-views. + mInventory->removeObserver(mInventoryObserver); + delete mInventoryObserver; + mScroller = NULL; +} + + LLMemType mt(LLMemType::MTYPE_INVENTORY_FROM_XML); +void LLInventoryPanel::draw() +{ + // select the desired item (in case it wasn't loaded when the selection was requested) + mFolders->updateSelection(); + LLPanel::draw(); +} + +void LLInventoryPanel::setFilterTypes(U64 filter_types, BOOL filter_for_categories) +{ + mFolders->getFilter()->setFilterTypes(filter_types, filter_for_categories); +} + +void LLInventoryPanel::setFilterPermMask(PermissionMask filter_perm_mask) +{ + mFolders->getFilter()->setFilterPermissions(filter_perm_mask); +} + +void LLInventoryPanel::setFilterSubString(const std::string& string) +{ + mFolders->getFilter()->setFilterSubString(string); +} + +void LLInventoryPanel::setSortOrder(U32 order) +{ + mFolders->getFilter()->setSortOrder(order); + if (mFolders->getFilter()->isModified()) + { + mFolders->setSortOrder(order); + // try to keep selection onscreen, even if it wasn't to start with + mFolders->scrollToShowSelection(); + } +} + +void LLInventoryPanel::setSinceLogoff(BOOL sl) +{ + mFolders->getFilter()->setDateRangeLastLogoff(sl); +} + +void LLInventoryPanel::setHoursAgo(U32 hours) +{ + mFolders->getFilter()->setHoursAgo(hours); +} + +void LLInventoryPanel::setShowFolderState(LLInventoryFilter::EFolderShow show) +{ + mFolders->getFilter()->setShowFolderState(show); +} + +LLInventoryFilter::EFolderShow LLInventoryPanel::getShowFolderState() +{ + return mFolders->getFilter()->getShowFolderState(); +} + +static LLFastTimer::DeclareTimer FTM_REFRESH("Inventory Refresh"); + +void LLInventoryPanel::modelChanged(U32 mask) +{ + LLFastTimer t2(FTM_REFRESH); + + bool handled = false; + if(mask & LLInventoryObserver::LABEL) + { + handled = true; + // label change - empty out the display name for each object + // in this change set. + const std::set& changed_items = gInventory.getChangedIDs(); + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + LLFolderViewItem* view = NULL; + LLInvFVBridge* bridge = NULL; + for (;id_it != id_end; ++id_it) + { + view = mFolders->getItemByID(*id_it); + if(view) + { + // request refresh on this item (also flags for filtering) + bridge = (LLInvFVBridge*)view->getListener(); + if(bridge) + { // Clear the display name first, so it gets properly re-built during refresh() + bridge->clearDisplayName(); + } + view->refresh(); + } + } + } + if((mask & (LLInventoryObserver::STRUCTURE + | LLInventoryObserver::ADD + | LLInventoryObserver::REMOVE)) != 0) + { + handled = true; + // Record which folders are open by uuid. + LLInventoryModel* model = getModel(); + if (model) + { + const std::set& changed_items = gInventory.getChangedIDs(); + + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + // sync view with model + LLInventoryObject* model_item = model->getObject(*id_it); + LLFolderViewItem* view_item = mFolders->getItemByID(*id_it); + + if (model_item) + { + if (!view_item) + { + // this object was just created, need to build a view for it + if ((mask & LLInventoryObserver::ADD) != LLInventoryObserver::ADD) + { + llwarns << *id_it << " is in model but not in view, but ADD flag not set" << llendl; + } + buildNewViews(*id_it); + + // select any newly created object + // that has the auto rename at top of folder + // root set + if(mFolders->getRoot()->needsAutoRename()) + { + setSelection(*id_it, FALSE); + } + } + else + { + // this object was probably moved, check its parent + if ((mask & LLInventoryObserver::STRUCTURE) != LLInventoryObserver::STRUCTURE) + { + llwarns << *id_it << " is in model and in view, but STRUCTURE flag not set" << llendl; + } + + LLFolderViewFolder* new_parent = (LLFolderViewFolder*)mFolders->getItemByID(model_item->getParentUUID()); + if (view_item->getParentFolder() != new_parent) + { + view_item->getParentFolder()->extractItem(view_item); + view_item->addToFolder(new_parent, mFolders); + } + } + } + else + { + if (view_item) + { + if ((mask & LLInventoryObserver::REMOVE) != LLInventoryObserver::REMOVE) + { + llwarns << *id_it << " is not in model but in view, but REMOVE flag not set" << llendl; + } + // item in view but not model, need to delete view + view_item->destroyView(); + } + else + { + llwarns << *id_it << "Item does not exist in either view or model, but notification triggered" << llendl; + } + } + } + } + } + + if (!handled) + { + // it's a small change that only requires a refresh. + // *TODO: figure out a more efficient way to do the refresh + // since it is expensive on large inventories + mFolders->refresh(); + } +} + +void LLInventoryPanel::rebuildViewsFor(const LLUUID& id, U32 mask) +{ + LLFolderViewItem* old_view = NULL; + + // get old LLFolderViewItem + old_view = mFolders->getItemByID(id); + if (old_view && id.notNull()) + { + old_view->destroyView(); + } + + buildNewViews(id); +} + +void LLInventoryPanel::buildNewViews(const LLUUID& id) +{ + LLMemType mt(LLMemType::MTYPE_INVENTORY_BUILD_NEW_VIEWS); + LLFolderViewItem* itemp = NULL; + LLInventoryObject* objectp = gInventory.getObject(id); + + if (objectp) + { + if (objectp->getType() <= LLAssetType::AT_NONE || + objectp->getType() >= LLAssetType::AT_COUNT) + { + llwarns << "LLInventoryPanel::buildNewViews called with objectp->mType == " + << ((S32) objectp->getType()) + << " (shouldn't happen)" << llendl; + } + else if (objectp->getType() == LLAssetType::AT_CATEGORY && + objectp->getActualType() != LLAssetType::AT_LINK_FOLDER) + { + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(objectp->getType(), + objectp->getType(), + LLInventoryType::IT_CATEGORY, + this, + objectp->getUUID()); + + if (new_listener) + { + LLFolderViewFolder::Params p; + p.name = new_listener->getDisplayName(); + p.icon = new_listener->getIcon(); + p.root = mFolders; + p.listener = new_listener; + LLFolderViewFolder* folderp = LLUICtrlFactory::create(p); + + folderp->setItemSortOrder(mFolders->getSortOrder()); + itemp = folderp; + } + } + else + { + // Build new view for item + LLInventoryItem* item = (LLInventoryItem*)objectp; + LLInvFVBridge* new_listener = LLInvFVBridge::createBridge(item->getType(), + item->getActualType(), + item->getInventoryType(), + this, + item->getUUID(), + item->getFlags()); + + if (new_listener) + { + LLFolderViewItem::Params params; + params.name(new_listener->getDisplayName()); + params.icon(new_listener->getIcon()); + params.creation_date(new_listener->getCreationDate()); + params.root(mFolders); + params.listener(new_listener); + params.rect(LLRect (0, 0, 0, 0)); + itemp = LLUICtrlFactory::create (params); + } + } + + LLFolderViewFolder* parent_folder = (LLFolderViewFolder*)mFolders->getItemByID(objectp->getParentUUID()); + + if (itemp) + { + if (parent_folder) + { + itemp->addToFolder(parent_folder, mFolders); + } + else + { + llwarns << "Couldn't find parent folder for child " << itemp->getLabel() << llendl; + delete itemp; + } + } + } + if ((id.isNull() || + (objectp && objectp->getType() == LLAssetType::AT_CATEGORY))) + { + LLViewerInventoryCategory::cat_array_t* categories; + LLViewerInventoryItem::item_array_t* items; + + mInventory->lockDirectDescendentArrays(id, categories, items); + if(categories) + { + S32 count = categories->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryCategory* cat = categories->get(i); + buildNewViews(cat->getUUID()); + } + } + if(items) + { + S32 count = items->count(); + for(S32 i = 0; i < count; ++i) + { + LLInventoryItem* item = items->get(i); + buildNewViews(item->getUUID()); + } + } + mInventory->unlockDirectDescendentArrays(id); + } +} + +struct LLConfirmPurgeData +{ + LLUUID mID; + LLInventoryModel* mModel; +}; + +class LLIsNotWorn : public LLInventoryCollectFunctor +{ +public: + LLIsNotWorn() {} + virtual ~LLIsNotWorn() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item) + { + return !gAgentWearables.isWearingItem(item->getUUID()); + } +}; + +class LLOpenFolderByID : public LLFolderViewFunctor +{ +public: + LLOpenFolderByID(const LLUUID& id) : mID(id) {} + virtual ~LLOpenFolderByID() {} + virtual void doFolder(LLFolderViewFolder* folder) + { + if (folder->getListener() && folder->getListener()->getUUID() == mID) folder->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP); + } + virtual void doItem(LLFolderViewItem* item) {} +protected: + const LLUUID& mID; +}; + + +void LLInventoryPanel::openSelected() +{ + LLFolderViewItem* folder_item = mFolders->getCurSelectedItem(); + if(!folder_item) return; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); + if(!bridge) return; + bridge->openItem(); +} + +BOOL LLInventoryPanel::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x, y, mask); + if(handled) + { + ECursorType cursor = getWindow()->getCursor(); + if (LLInventoryModel::backgroundFetchActive() && cursor == UI_CURSOR_ARROW) + { + // replace arrow cursor with arrow and hourglass cursor + getWindow()->setCursor(UI_CURSOR_WORKING); + } + } + else + { + getWindow()->setCursor(UI_CURSOR_ARROW); + } + return TRUE; +} + +BOOL LLInventoryPanel::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + + BOOL handled = LLPanel::handleDragAndDrop(x, y, mask, drop, cargo_type, cargo_data, accept, tooltip_msg); + + if (handled) + { + mFolders->setDragAndDropThisFrame(); + } + + return handled; +} + +void LLInventoryPanel::onFocusLost() +{ + // inventory no longer handles cut/copy/paste/delete + if (LLEditMenuHandler::gEditMenuHandler == mFolders) + { + LLEditMenuHandler::gEditMenuHandler = NULL; + } + + LLPanel::onFocusLost(); +} + +void LLInventoryPanel::onFocusReceived() +{ + // inventory now handles cut/copy/paste/delete + LLEditMenuHandler::gEditMenuHandler = mFolders; + + LLPanel::onFocusReceived(); +} + + +void LLInventoryPanel::openAllFolders() +{ + mFolders->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_DOWN); + mFolders->arrangeAll(); +} + +void LLInventoryPanel::openDefaultFolderForType(LLAssetType::EType type) +{ + LLUUID category_id = mInventory->findCategoryUUIDForType(type); + LLOpenFolderByID opener(category_id); + mFolders->applyFunctorRecursively(opener); +} + +void LLInventoryPanel::setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + mFolders->setSelectionByID(obj_id, take_keyboard_focus); +} + +void LLInventoryPanel::clearSelection() +{ + mFolders->clearSelection(); +} + +void LLInventoryPanel::onSelectionChange(const std::deque& items, BOOL user_action) +{ + LLFolderView* fv = getRootFolder(); + if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename + { + fv->setNeedsAutoRename(FALSE); + if (items.size()) // new asset is visible and selected + { + fv->startRenamingSelectedItem(); + } + } + // Seraph - Put determineFolderType in here for ensemble typing? +} + +//---------------------------------------------------------------------------- + +void LLInventoryPanel::doToSelected(const LLSD& userdata) +{ + mFolders->doToSelected(&gInventory, userdata); +} + +void LLInventoryPanel::doCreate(const LLSD& userdata) +{ + menu_create_inventory_item(mFolders, LLFolderBridge::sSelf, userdata); +} + +bool LLInventoryPanel::beginIMSession() +{ + std::set selected_items; + mFolders->getSelectionList(selected_items); + + std::string name; + static int session_num = 1; + + LLDynamicArray members; + EInstantMessage type = IM_SESSION_CONFERENCE_START; + + std::set::const_iterator iter; + for (iter = selected_items.begin(); iter != selected_items.end(); iter++) + { + + LLUUID item = *iter; + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + + if(folder_item) + { + LLFolderViewEventListener* fve_listener = folder_item->getListener(); + if (fve_listener && (fve_listener->getInventoryType() == LLInventoryType::IT_CATEGORY)) + { + + LLFolderBridge* bridge = (LLFolderBridge*)folder_item->getListener(); + if(!bridge) return true; + LLViewerInventoryCategory* cat = bridge->getCategory(); + if(!cat) return true; + name = cat->getName(); + LLUniqueBuddyCollector is_buddy; + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendentsIf(bridge->getUUID(), + cat_array, + item_array, + LLInventoryModel::EXCLUDE_TRASH, + is_buddy); + S32 count = item_array.count(); + if(count > 0) + { + LLFloaterReg::showInstance("communicate"); + // create the session + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id; + for(S32 i = 0; i < count; ++i) + { + id = item_array.get(i)->getCreatorUUID(); + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } + } + else + { + LLFolderViewItem* folder_item = mFolders->getItemByID(item); + if(!folder_item) return true; + LLInvFVBridge* listenerp = (LLInvFVBridge*)folder_item->getListener(); + + if (listenerp->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + LLInventoryItem* inv_item = gInventory.getItem(listenerp->getUUID()); + + if (inv_item) + { + LLAvatarTracker& at = LLAvatarTracker::instance(); + LLUUID id = inv_item->getCreatorUUID(); + + if(at.isBuddyOnline(id)) + { + members.put(id); + } + } + } //if IT_CALLINGCARD + } //if !IT_CATEGORY + } + } //for selected_items + + // the session_id is randomly generated UUID which will be replaced later + // with a server side generated number + + if (name.empty()) + { + name = llformat("Session %d", session_num++); + } + + gIMMgr->addSession(name, type, members[0], members); + + return true; +} + +bool LLInventoryPanel::attachObject(const LLSD& userdata) +{ + std::set selected_items; + mFolders->getSelectionList(selected_items); + LLUUID id = *selected_items.begin(); + + std::string joint_name = userdata.asString(); + LLVOAvatar *avatarp = static_cast(gAgent.getAvatarObject()); + LLViewerJointAttachment* attachmentp = NULL; + for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); + iter != avatarp->mAttachmentPoints.end(); ) + { + LLVOAvatar::attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getName() == joint_name) + { + attachmentp = attachment; + break; + } + } + if (attachmentp == NULL) + { + return true; + } + LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem(id); + + if(item && gInventory.isObjectDescendentOf(id, gInventory.getRootFolderID())) + { + rez_attachment(item, attachmentp); + } + else if(item && item->isComplete()) + { + // must be in library. copy it to our inventory and put it on. + LLPointer cb = new RezAttachmentCallback(attachmentp); + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + gFocusMgr.setKeyboardFocus(NULL); + + return true; +} + + +//---------------------------------------------------------------------------- + +// static DEBUG ONLY: +void LLInventoryPanel::dumpSelectionInformation(void* user_data) +{ + LLInventoryPanel* iv = (LLInventoryPanel*)user_data; + iv->mFolders->dumpSelectionInformation(); +} + +BOOL LLInventoryPanel::getSinceLogoff() +{ + return mFolders->getFilter()->isSinceLogoff(); +} + +void example_param_block_usage() +{ + LLInventoryPanel::Params param_block; + param_block.name(std::string("inventory")); + + param_block.sort_order_setting(LLInventoryPanel::RECENTITEMS_SORT_ORDER); + param_block.allow_multi_select(true); + param_block.filter(LLInventoryPanel::Filter() + .sort_order(1) + .types(0xffff0000)); + param_block.inventory(&gInventory); + param_block.has_border(true); + + LLUICtrlFactory::create(param_block); + + param_block = LLInventoryPanel::Params(); + param_block.name(std::string("inventory")); + + //LLSD param_block_sd; + //param_block_sd["sort_order_setting"] = LLInventoryPanel::RECENTITEMS_SORT_ORDER; + //param_block_sd["allow_multi_select"] = true; + //param_block_sd["filter"]["sort_order"] = 1; + //param_block_sd["filter"]["types"] = (S32)0xffff0000; + //param_block_sd["has_border"] = true; + + //LLInitParam::LLSDParser(param_block_sd).parse(param_block); + + LLUICtrlFactory::create(param_block); +} diff --git a/indra/newview/llfloaterinventory.h b/indra/newview/llfloaterinventory.h new file mode 100644 index 0000000000..fd61e121ea --- /dev/null +++ b/indra/newview/llfloaterinventory.h @@ -0,0 +1,362 @@ +/** + * @file llfloaterinventory.h + * @brief LLFloaterInventory, LLInventoryFolder, and LLInventoryItem + * class definition + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLINVENTORYVIEW_H +#define LL_LLINVENTORYVIEW_H + +#include "llassetstorage.h" +#include "lldarray.h" +#include "llfloater.h" +#include "llinventory.h" +#include "llinventoryfilter.h" +#include "llfolderview.h" +#include "llinventorymodel.h" +#include "lluictrlfactory.h" +#include + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFloaterInventory +// +// This is the agent inventory _floater_. +// It deals with the buttons and views used to navigate as +// well as controls the behavior of the overall object. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFolderViewItem; +class LLInventoryFilter; +class LLInventoryModel; +class LLInvFVBridge; +class LLMenuBarGL; +class LLCheckBoxCtrl; +class LLSpinCtrl; +class LLScrollContainer; +class LLTextBox; +class LLIconCtrl; +class LLSaveFolderState; +class LLFilterEditor; +class LLTabContainer; + +class LLInventoryPanel : public LLPanel +{ +public: + static const std::string DEFAULT_SORT_ORDER; + static const std::string RECENTITEMS_SORT_ORDER; + static const std::string INHERIT_SORT_ORDER; + + struct Filter : public LLInitParam::Block + { + Optional sort_order; + Optional types; + Optional search_string; + + Filter() + : sort_order("sort_order"), + types("types", 0xffffffff), + search_string("search_string") + {} + }; + + struct Params + : public LLInitParam::Block + { + Optional sort_order_setting; + Optional inventory; + Optional allow_multi_select; + Optional filter; + + Params() + : sort_order_setting("sort_order_setting"), + inventory("", &gInventory), + allow_multi_select("allow_multi_select", true), + filter("filter") + {} + }; + +protected: + LLInventoryPanel(const Params&); + friend class LLUICtrlFactory; + +public: + ~LLInventoryPanel(); + + LLInventoryModel* getModel() { return mInventory; } + + BOOL postBuild(); + + // LLView methods + void draw(); + BOOL handleHover(S32 x, S32 y, MASK mask); + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + // LLUICtrl methods + /*virtual*/ void onFocusLost(); + /*virtual*/ void onFocusReceived(); + + // Call this method to set the selection. + void openAllFolders(); + void openDefaultFolderForType(LLAssetType::EType); + void setSelection(const LLUUID& obj_id, BOOL take_keyboard_focus); + void setSelectCallback(const LLFolderView::signal_t::slot_type& cb) { if (mFolders) mFolders->setSelectCallback(cb); } + void clearSelection(); + LLInventoryFilter* getFilter() { return mFolders->getFilter(); } + void setFilterTypes(U64 filter, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type + U32 getFilterTypes() const { return mFolders->getFilterTypes(); } + void setFilterPermMask(PermissionMask filter_perm_mask); + U32 getFilterPermMask() const { return mFolders->getFilterPermissions(); } + void setFilterSubString(const std::string& string); + const std::string getFilterSubString() { return mFolders->getFilterSubString(); } + void setSortOrder(U32 order); + U32 getSortOrder() { return mFolders->getSortOrder(); } + void setSinceLogoff(BOOL sl); + void setHoursAgo(U32 hours); + BOOL getSinceLogoff(); + + void setShowFolderState(LLInventoryFilter::EFolderShow show); + LLInventoryFilter::EFolderShow getShowFolderState(); + void setAllowMultiSelect(BOOL allow) { mFolders->setAllowMultiSelect(allow); } + // This method is called when something has changed about the inventory. + void modelChanged(U32 mask); + LLFolderView* getRootFolder() { return mFolders; } + LLScrollContainer* getScrollableContainer() { return mScroller; } + + void onSelectionChange(const std::deque &items, BOOL user_action); + + // Callbacks + void doToSelected(const LLSD& userdata); + void doCreate(const LLSD& userdata); + bool beginIMSession(); + bool attachObject(const LLSD& userdata); + + // DEBUG ONLY: + static void dumpSelectionInformation(void* user_data); + + void openSelected(); + void unSelectAll() { mFolders->setSelection(NULL, FALSE, FALSE); } + +protected: + // Given the id and the parent, build all of the folder views. + void rebuildViewsFor(const LLUUID& id, U32 mask); + void buildNewViews(const LLUUID& id); + +protected: + LLInventoryModel* mInventory; + LLInventoryObserver* mInventoryObserver; + LLFolderView* mFolders; + LLScrollContainer* mScroller; + BOOL mAllowMultiSelect; + std::string mSortOrderSetting; +}; + +class LLFloaterInventory; + +class LLFloaterInventoryFinder : public LLFloater +{ +public: + LLFloaterInventoryFinder( LLFloaterInventory* inventory_view); + virtual void draw(); + /*virtual*/ BOOL postBuild(); + void changeFilter(LLInventoryFilter* filter); + void updateElementsFromFilter(); + BOOL getCheckShowEmpty(); + BOOL getCheckSinceLogoff(); + + static void onTimeAgo(LLUICtrl*, void *); + static void onCheckSinceLogoff(LLUICtrl*, void *); + static void onCloseBtn(void* user_data); + static void selectAllTypes(void* user_data); + static void selectNoTypes(void* user_data); + +protected: + LLFloaterInventory* mFloaterInventory; + LLSpinCtrl* mSpinSinceDays; + LLSpinCtrl* mSpinSinceHours; + LLInventoryFilter* mFilter; +}; + +class LLFloaterInventory : public LLFloater, LLInventoryObserver +{ +friend class LLFloaterInventoryFinder; + +public: + LLFloaterInventory(const LLSD& key); + ~LLFloaterInventory(); + + /*virtual*/ void changed(U32 mask); + + BOOL postBuild(); + + // + // Misc functions + // + void setFilterTextFromFilter() { mFilterText = mActivePanel->getFilter()->getFilterText(); } + void startSearch(); + + // This method makes sure that an inventory view exists, is + // visible, and has focus. The view chosen is returned. + static LLFloaterInventory* showAgentInventory(); + + // Return the active inventory view if there is one. Active is + // defined as the inventory that is the closest to the front, and + // is visible. + static LLFloaterInventory* getActiveInventory(); + + // This method calls showAgentInventory() if no views are visible, + // or hides/destroyes them all if any are visible. + static void toggleVisibility(); + static void toggleVisibility(void*) { toggleVisibility(); } + + // Final cleanup, destroy all open inventory views. + static void cleanup(); + + // LLView & LLFloater functionality + virtual void onOpen(const LLSD& key); + virtual void draw(); + virtual BOOL handleKeyHere(KEY key, MASK mask); + + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + + LLInventoryPanel* getPanel() { return mActivePanel; } + LLInventoryPanel* getActivePanel() { return mActivePanel; } + + static BOOL filtersVisible(void* user_data); + void onClearSearch(); + static void onFoldersByName(void *user_data); + static BOOL checkFoldersByName(void *user_data); + void onFilterEdit(const std::string& search_string ); + static BOOL incrementalFind(LLFolderViewItem* first_item, const char *find_text, BOOL backward); + void onFilterSelected(); + + const std::string getFilterSubString() { return mActivePanel->getFilterSubString(); } + void setFilterSubString(const std::string& string) { mActivePanel->setFilterSubString(string); } + + // menu callbacks + void doToSelected(const LLSD& userdata); + void closeAllFolders(); + void doCreate(const LLSD& userdata); + void resetFilters(); + void setSortBy(const LLSD& userdata); + + // HACK: Until we can route this info through the instant message hierarchy + static BOOL sWearNewClothing; + static LLUUID sWearNewClothingTransactionID; // wear all clothing in this transaction + + void toggleFindOptions(); + + LLFloaterInventoryFinder* getFinder() { return (LLFloaterInventoryFinder*)mFinderHandle.get(); } + +protected: + LLFilterEditor* mFilterEditor; + LLTabContainer* mFilterTabs; + LLHandle mFinderHandle; + LLInventoryPanel* mActivePanel; + LLSaveFolderState* mSavedFolderState; + + std::string mFilterText; +}; + +class LLSelectFirstFilteredItem : public LLFolderViewFunctor +{ +public: + LLSelectFirstFilteredItem() : mItemSelected(FALSE) {} + virtual ~LLSelectFirstFilteredItem() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); + BOOL wasItemSelected() { return mItemSelected; } +protected: + BOOL mItemSelected; +}; + +class LLOpenFilteredFolders : public LLFolderViewFunctor +{ +public: + LLOpenFilteredFolders() {} + virtual ~LLOpenFilteredFolders() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +class LLSaveFolderState : public LLFolderViewFunctor +{ +public: + LLSaveFolderState() : mApply(FALSE) {} + virtual ~LLSaveFolderState() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item) {} + void setApply(BOOL apply); + void clearOpenFolders() { mOpenFolders.clear(); } +protected: + std::set mOpenFolders; + BOOL mApply; +}; + +class LLOpenFoldersWithSelection : public LLFolderViewFunctor +{ +public: + LLOpenFoldersWithSelection() {} + virtual ~LLOpenFoldersWithSelection() {} + virtual void doFolder(LLFolderViewFolder* folder); + virtual void doItem(LLFolderViewItem* item); +}; + +///---------------------------------------------------------------------------- +/// Function declarations, constants, enums, and typedefs +///---------------------------------------------------------------------------- + +// useful functions with the inventory view + +class LLInventoryCategory; +class LLInventoryItem; + +const std::string& get_item_icon_name(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +LLUIImagePtr get_item_icon(LLAssetType::EType asset_type, + LLInventoryType::EType inventory_type, + U32 attachment_point, + BOOL item_is_multi ); + +#endif // LL_LLINVENTORYVIEW_H + + + diff --git a/indra/newview/llfloaterjoystick.cpp b/indra/newview/llfloaterjoystick.cpp index e5811671ed..06fe2a84c8 100644 --- a/indra/newview/llfloaterjoystick.cpp +++ b/indra/newview/llfloaterjoystick.cpp @@ -48,10 +48,10 @@ #include "llcheckboxctrl.h" LLFloaterJoystick::LLFloaterJoystick(const LLSD& data) - : LLFloater("floater_joystick") + : LLFloater(data) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_joystick.xml"); - center(); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_joystick.xml"); + } void LLFloaterJoystick::draw() @@ -68,14 +68,15 @@ void LLFloaterJoystick::draw() { F32 value = joystick->getJoystickAxis(i); mAxisStats[i]->addValue(value * gFrameIntervalSeconds); - - if (mAxisStatsBar[i]->mMinBar > value) + if (mAxisStatsBar[i]) { - mAxisStatsBar[i]->mMinBar = value; - } - if (mAxisStatsBar[i]->mMaxBar < value) - { - mAxisStatsBar[i]->mMaxBar = value; + F32 minbar, maxbar; + mAxisStatsBar[i]->getRange(minbar, maxbar); + if (llabs(value) > maxbar) + { + F32 range = llabs(value); + mAxisStatsBar[i]->setRange(-range, range, range * 0.25f, range * 0.5f); + } } } @@ -84,37 +85,20 @@ void LLFloaterJoystick::draw() BOOL LLFloaterJoystick::postBuild() { - F32 range = gSavedSettings.getBOOL("Cursor3D") ? 1024.f : 2.f; - LLUIString axis = getString("Axis"); - LLUIString joystick = getString("JoystickMonitor"); - - // use this child to get relative positioning info; we'll place the - // joystick monitor on its right, vertically aligned to it. - LLView* child = getChild("FlycamAxisScale1"); - LLRect rect; - - if (child) - { - LLRect r = child->getRect(); - LLRect f = getRect(); - rect = LLRect(350, r.mTop, r.mRight + 200, 0); - } - - mAxisStatsView = new LLStatView("axis values", joystick, "", rect); - mAxisStatsView->setDisplayChildren(TRUE); + center(); + F32 range = gSavedSettings.getBOOL("Cursor3D") ? 128.f : 2.f; for (U32 i = 0; i < 6; i++) { - axis.setArg("[NUM]", llformat("%d", i)); mAxisStats[i] = new LLStat(4); - mAxisStatsBar[i] = mAxisStatsView->addStat(axis, mAxisStats[i]); - mAxisStatsBar[i]->mMinBar = -range; - mAxisStatsBar[i]->mMaxBar = range; - mAxisStatsBar[i]->mLabelSpacing = range * 0.5f; - mAxisStatsBar[i]->mTickSpacing = range * 0.25f; + std::string axisname = llformat("axis%d", i); + mAxisStatsBar[i] = getChild(axisname); + if (mAxisStatsBar[i]) + { + mAxisStatsBar[i]->setStat(mAxisStats[i]); + mAxisStatsBar[i]->setRange(-range, range, range * 0.25f, range * 0.5f); + } } - - addChild(mAxisStatsView); mCheckJoystickEnabled = getChild("enable_joystick"); childSetCommitCallback("enable_joystick",onCommitJoystickEnabled,this); @@ -310,7 +294,7 @@ void LLFloaterJoystick::onClickCancel(void *joy_panel) if (self) { self->cancel(); - self->close(); + self->closeFloater(); } } } @@ -323,7 +307,7 @@ void LLFloaterJoystick::onClickOK(void *joy_panel) if (self) { - self->close(); + self->closeFloater(); } } } diff --git a/indra/newview/llfloaterjoystick.h b/indra/newview/llfloaterjoystick.h index 3ce647e5bb..f3559c28e9 100644 --- a/indra/newview/llfloaterjoystick.h +++ b/indra/newview/llfloaterjoystick.h @@ -38,11 +38,11 @@ class LLCheckBoxCtrl; -class LLFloaterJoystick : public LLFloater, public LLFloaterSingleton +class LLFloaterJoystick : public LLFloater { + friend class LLFloaterReg; + public: - LLFloaterJoystick(const LLSD& data); - virtual ~LLFloaterJoystick(); virtual BOOL postBuild(); virtual void refresh(); @@ -52,6 +52,10 @@ public: static void setSNDefaults(); private: + + LLFloaterJoystick(const LLSD& data); + virtual ~LLFloaterJoystick(); + static void onCommitJoystickEnabled(LLUICtrl*, void*); static void onClickRestoreSNDefaults(void*); static void onClickCancel(void*); @@ -84,9 +88,8 @@ private: LLCheckBoxCtrl *mCheckFlycamEnabled; // stats view - LLStatView* mAxisStatsView; - LLStat* mAxisStats[6]; - LLStatBar* mAxisStatsBar[6]; + LLStat* mAxisStats[6]; + LLStatBar* mAxisStatsBar[6]; }; #endif diff --git a/indra/newview/llfloaterlagmeter.cpp b/indra/newview/llfloaterlagmeter.cpp index 8fe455fde4..3753dcaaa8 100644 --- a/indra/newview/llfloaterlagmeter.cpp +++ b/indra/newview/llfloaterlagmeter.cpp @@ -36,7 +36,7 @@ #include "lluictrlfactory.h" #include "llviewerstats.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llviewercontrol.h" #include "llappviewer.h" @@ -51,14 +51,24 @@ const std::string LAG_WARNING_IMAGE_NAME = "lag_status_warning.tga"; const std::string LAG_GOOD_IMAGE_NAME = "lag_status_good.tga"; LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key) - : LLFloater(std::string("floater_lagmeter")) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_lagmeter.xml"); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_lagmeter.xml"); + mCommitCallbackRegistrar.add("LagMeter.ClickShrink", boost::bind(&LLFloaterLagMeter::onClickShrink, this)); +} +BOOL LLFloaterLagMeter::postBuild() +{ // Don't let this window take keyboard focus -- it's confusing to // lose arrow-key driving when testing lag. setIsChrome(TRUE); - + + // were we shrunk last time? + if (gSavedSettings.getBOOL("LagMeterShrunk")) + { + onClickShrink(); + } + mClientButton = getChild("client_lagmeter"); mClientText = getChild("client_text"); mClientCause = getChild("client_lag_cause"); @@ -93,7 +103,7 @@ LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key) config_string = getString("server_single_process_max_time_ms", mStringArgs); mServerSingleProcessMaxTime = (float)atof( config_string.c_str() ); - mShrunk = false; +// mShrunk = false; config_string = getString("max_width_px", mStringArgs); mMaxWidth = atoi( config_string.c_str() ); config_string = getString("min_width_px", mStringArgs); @@ -111,23 +121,18 @@ LLFloaterLagMeter::LLFloaterLagMeter(const LLSD& key) mStringArgs["[SERVER_FRAME_RATE_CRITICAL]"] = getString("server_frame_rate_critical_fps"); mStringArgs["[SERVER_FRAME_RATE_WARNING]"] = getString("server_frame_rate_warning_fps"); - childSetAction("minimize", onClickShrink, this); +// childSetAction("minimize", onClickShrink, this); - // were we shrunk last time? - if (gSavedSettings.getBOOL("LagMeterShrunk")) - { - onClickShrink(this); - } + return TRUE; } - LLFloaterLagMeter::~LLFloaterLagMeter() { // save shrunk status for next time - gSavedSettings.setBOOL("LagMeterShrunk", mShrunk); +// gSavedSettings.setBOOL("LagMeterShrunk", mShrunk); // expand so we save the large window rectangle - if (mShrunk) + if (gSavedSettings.getBOOL("LagMeterShrunk")) { - onClickShrink(this); + onClickShrink(); } } @@ -147,25 +152,25 @@ void LLFloaterLagMeter::determineClient() if (!gFocusMgr.getAppHasFocus()) { - mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_window_bg_msg", mStringArgs) ); mClientCause->setText( LLStringUtil::null ); } else if(client_frame_time >= mClientFrameTimeCritical) { - mClientButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_critical_msg", mStringArgs) ); find_cause = true; } else if(client_frame_time >= mClientFrameTimeWarning) { - mClientButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_warning_msg", mStringArgs) ); find_cause = true; } else { - mClientButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mClientButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mClientText->setText( getString("client_frame_time_normal_msg", mStringArgs) ); mClientCause->setText( LLStringUtil::null ); } @@ -180,7 +185,7 @@ void LLFloaterLagMeter::determineClient() { mClientCause->setText( getString("client_texture_loading_cause_msg", mStringArgs) ); } - else if((BYTES_TO_MEGA_BYTES(LLViewerImage::sBoundTextureMemoryInBytes)) > LLViewerImage::sMaxBoundTextureMemInMegaBytes) + else if((BYTES_TO_MEGA_BYTES(LLViewerTexture::sBoundTextureMemoryInBytes)) > LLViewerTexture::sMaxBoundTextureMemInMegaBytes) { mClientCause->setText( getString("client_texture_memory_cause_msg", mStringArgs) ); } @@ -206,13 +211,13 @@ void LLFloaterLagMeter::determineNetwork() if(packet_loss >= mNetworkPacketLossCritical) { - mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mNetworkText->setText( getString("network_packet_loss_critical_msg", mStringArgs) ); find_cause_loss = true; } else if(ping_time >= mNetworkPingCritical) { - mNetworkButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); if (client_frame_time_ms < mNetworkPingCritical) { mNetworkText->setText( getString("network_ping_critical_msg", mStringArgs) ); @@ -221,13 +226,13 @@ void LLFloaterLagMeter::determineNetwork() } else if(packet_loss >= mNetworkPacketLossWarning) { - mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mNetworkText->setText( getString("network_packet_loss_warning_msg", mStringArgs) ); find_cause_loss = true; } else if(ping_time >= mNetworkPingWarning) { - mNetworkButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); if (client_frame_time_ms < mNetworkPingWarning) { mNetworkText->setText( getString("network_ping_warning_msg", mStringArgs) ); @@ -236,7 +241,7 @@ void LLFloaterLagMeter::determineNetwork() } else { - mNetworkButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mNetworkButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mNetworkText->setText( getString("network_performance_normal_msg", mStringArgs) ); } @@ -261,19 +266,19 @@ void LLFloaterLagMeter::determineServer() if(sim_frame_time >= mServerFrameTimeCritical) { - mServerButton->setImageUnselected(LAG_CRITICAL_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_CRITICAL_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_critical_msg", mStringArgs) ); find_cause = true; } else if(sim_frame_time >= mServerFrameTimeWarning) { - mServerButton->setImageUnselected(LAG_WARNING_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_WARNING_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_warning_msg", mStringArgs) ); find_cause = true; } else { - mServerButton->setImageUnselected(LAG_GOOD_IMAGE_NAME); + mServerButton->setImageUnselected(LLUI::getUIImage(LAG_GOOD_IMAGE_NAME)); mServerText->setText( getString("server_frame_time_normal_msg", mStringArgs) ); mServerCause->setText( LLStringUtil::null ); } @@ -307,58 +312,61 @@ void LLFloaterLagMeter::determineServer() } } -//static -void LLFloaterLagMeter::onClickShrink(void * data) -{ - LLFloaterLagMeter * self = (LLFloaterLagMeter*)data; - LLButton * button = self->getChild("minimize"); - S32 delta_width = self->mMaxWidth - self->mMinWidth; - LLRect r = self->getRect(); - if(self->mShrunk) +void LLFloaterLagMeter::onClickShrink() // toggle "LagMeterShrunk" +{ +// LLFloaterLagMeter * self = (LLFloaterLagMeter*)data; + + LLButton * button = getChild("minimize"); + S32 delta_width = mMaxWidth -mMinWidth; + LLRect r = getRect(); + bool shrunk = gSavedSettings.getBOOL("LagMeterShrunk"); + + if(shrunk) { - self->setTitle( self->getString("max_title_msg", self->mStringArgs) ); + setTitle(getString("max_title_msg", mStringArgs) ); // make left edge appear to expand r.translate(-delta_width, 0); - self->setRect(r); - self->reshape(self->mMaxWidth, self->getRect().getHeight()); + setRect(r); + reshape(mMaxWidth, getRect().getHeight()); - self->childSetText("client", self->getString("client_text_msg", self->mStringArgs) + ":"); - self->childSetText("network", self->getString("network_text_msg", self->mStringArgs) + ":"); - self->childSetText("server", self->getString("server_text_msg", self->mStringArgs) + ":"); + childSetText("client", getString("client_text_msg", mStringArgs) + ":"); + childSetText("network", getString("network_text_msg",mStringArgs) + ":"); + childSetText("server", getString("server_text_msg", mStringArgs) + ":"); // usually "<<" - button->setLabel( self->getString("smaller_label", self->mStringArgs) ); + button->setLabel( getString("smaller_label", mStringArgs) ); } else { - self->setTitle( self->getString("min_title_msg", self->mStringArgs) ); + setTitle( getString("min_title_msg", mStringArgs) ); // make left edge appear to collapse r.translate(delta_width, 0); - self->setRect(r); - self->reshape(self->mMinWidth, self->getRect().getHeight()); + setRect(r); + reshape(mMinWidth, getRect().getHeight()); - self->childSetText("client", self->getString("client_text_msg", self->mStringArgs) ); - self->childSetText("network", self->getString("network_text_msg", self->mStringArgs) ); - self->childSetText("server", self->getString("server_text_msg", self->mStringArgs) ); + childSetText("client", getString("client_text_msg", mStringArgs) ); + childSetText("network",getString("network_text_msg",mStringArgs) ); + childSetText("server", getString("server_text_msg", mStringArgs) ); // usually ">>" - button->setLabel( self->getString("bigger_label", self->mStringArgs) ); + button->setLabel( getString("bigger_label", mStringArgs) ); } // Don't put keyboard focus on the button button->setFocus(FALSE); - self->mClientText->setVisible(self->mShrunk); - self->mClientCause->setVisible(self->mShrunk); - self->childSetVisible("client_help", self->mShrunk); +// self->mClientText->setVisible(self->mShrunk); +// self->mClientCause->setVisible(self->mShrunk); +// self->childSetVisible("client_help", self->mShrunk); - self->mNetworkText->setVisible(self->mShrunk); - self->mNetworkCause->setVisible(self->mShrunk); - self->childSetVisible("network_help", self->mShrunk); +// self->mNetworkText->setVisible(self->mShrunk); +// self->mNetworkCause->setVisible(self->mShrunk); +// self->childSetVisible("network_help", self->mShrunk); - self->mServerText->setVisible(self->mShrunk); - self->mServerCause->setVisible(self->mShrunk); - self->childSetVisible("server_help", self->mShrunk); +// self->mServerText->setVisible(self->mShrunk); +// self->mServerCause->setVisible(self->mShrunk); +// self->childSetVisible("server_help", self->mShrunk); - self->mShrunk = !self->mShrunk; +// self->mShrunk = !self->mShrunk; + gSavedSettings.setBOOL("LagMeterShrunk", !gSavedSettings.getBOOL("LagMeterShrunk")); } diff --git a/indra/newview/llfloaterlagmeter.h b/indra/newview/llfloaterlagmeter.h index d9cea18305..592630636a 100644 --- a/indra/newview/llfloaterlagmeter.h +++ b/indra/newview/llfloaterlagmeter.h @@ -35,22 +35,24 @@ #include "llfloater.h" -class LLFloaterLagMeter : public LLFloater, public LLFloaterSingleton +class LLTextBox; + +class LLFloaterLagMeter : public LLFloater { - friend class LLUISingleton >; + friend class LLFloaterReg; public: /*virtual*/ void draw(); - + /*virtual*/ BOOL postBuild(); private: + LLFloaterLagMeter(const LLSD& key); /*virtual*/ ~LLFloaterLagMeter(); - void determineClient(); void determineNetwork(); void determineServer(); - static void onClickShrink(void * data); + void onClickShrink(); bool mShrunk; S32 mMaxWidth, mMinWidth; diff --git a/indra/newview/llfloaterland.cpp b/indra/newview/llfloaterland.cpp index 94a834502f..4cd09faaaf 100644 --- a/indra/newview/llfloaterland.cpp +++ b/indra/newview/llfloaterland.cpp @@ -44,21 +44,23 @@ #include "lluserauth.h" #include "llagent.h" -#include "llfloateravatarpicker.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llradiogroup.h" #include "llcombobox.h" +#include "llfloaterreg.h" +#include "llfloateravatarpicker.h" #include "llfloaterauction.h" -#include "llfloateravatarinfo.h" #include "llfloatergroups.h" -#include "llfloatergroupinfo.h" +#include "llavataractions.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llnotify.h" +#include "llpanellandaudio.h" #include "llpanellandmedia.h" #include "llradiogroup.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "llselectmgr.h" #include "llspinctrl.h" #include "lltabcontainer.h" @@ -66,7 +68,7 @@ #include "lltexturectrl.h" #include "lluiconstants.h" #include "lluictrlfactory.h" -#include "llviewerimagelist.h" // LLUIImageList +#include "llviewertexturelist.h" // LLUIImageList #include "llviewermessage.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" @@ -75,6 +77,9 @@ #include "llviewerwindow.h" #include "llviewercontrol.h" #include "roles_constants.h" +#include "lltrans.h" + +#include "llgroupactions.h" static std::string OWNER_ONLINE = "0"; static std::string OWNER_OFFLINE = "1"; @@ -146,23 +151,50 @@ void send_parcel_select_objects(S32 parcel_local_id, S32 return_type, //static LLPanelLandObjects* LLFloaterLand::getCurrentPanelLandObjects() { - return LLFloaterLand::getInstance()->mPanelObjects; + LLFloaterLand* land_instance = LLFloaterReg::getTypedInstance("about_land"); + if(land_instance) + { + return land_instance->mPanelObjects; + } + else + { + return NULL; + } } //static LLPanelLandCovenant* LLFloaterLand::getCurrentPanelLandCovenant() { - return LLFloaterLand::getInstance()->mPanelCovenant; + LLFloaterLand* land_instance = LLFloaterReg::getTypedInstance("about_land"); + if(land_instance) + { + return land_instance->mPanelCovenant; + } + else + { + return NULL; + } } // static void LLFloaterLand::refreshAll() { - LLFloaterLand::getInstance()->refresh(); + LLFloaterLand* land_instance = LLFloaterReg::getTypedInstance("about_land"); + if(land_instance) + { + land_instance->refresh(); + } } -void LLFloaterLand::onOpen() +void LLFloaterLand::onOpen(const LLSD& key) { + // moved from triggering show instance in llviwermenu.cpp + + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) + { + LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); + } + // Done automatically when the selected parcel's properties arrive // (and hence we have the local id). // LLViewerParcelMgr::getInstance()->sendParcelAccessListRequest(AL_ACCESS | AL_BAN | AL_RENTER); @@ -174,45 +206,40 @@ void LLFloaterLand::onOpen() refresh(); } - -// virtual -void LLFloaterLand::onClose(bool app_quitting) +void LLFloaterLand::onVisibilityChange(const LLSD& visible) { - LLViewerParcelMgr::getInstance()->removeObserver( sObserver ); - delete sObserver; - sObserver = NULL; + if (!visible.asBoolean()) + { + // Might have been showing owned objects + LLSelectMgr::getInstance()->unhighlightAll(); - // Might have been showing owned objects - LLSelectMgr::getInstance()->unhighlightAll(); - - // Save which panel we had open - sLastTab = mTabLand->getCurrentPanelIndex(); - - destroy(); + // Save which panel we had open + sLastTab = mTabLand->getCurrentPanelIndex(); + } } LLFloaterLand::LLFloaterLand(const LLSD& seed) -: LLFloater(std::string("floaterland"), std::string("FloaterLandRect5"), std::string("About Land")) +: LLFloater(seed) { - LLCallbackMap::map_t factory_map; - factory_map["land_general_panel"] = LLCallbackMap(createPanelLandGeneral, this); + mFactoryMap["land_general_panel"] = LLCallbackMap(createPanelLandGeneral, this); + mFactoryMap["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this); + mFactoryMap["land_objects_panel"] = LLCallbackMap(createPanelLandObjects, this); + mFactoryMap["land_options_panel"] = LLCallbackMap(createPanelLandOptions, this); + mFactoryMap["land_audio_panel"] = LLCallbackMap(createPanelLandAudio, this); + mFactoryMap["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); + mFactoryMap["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); - - factory_map["land_covenant_panel"] = LLCallbackMap(createPanelLandCovenant, this); - factory_map["land_objects_panel"] = LLCallbackMap(createPanelLandObjects, this); - factory_map["land_options_panel"] = LLCallbackMap(createPanelLandOptions, this); - factory_map["land_media_panel"] = LLCallbackMap(createPanelLandMedia, this); - factory_map["land_access_panel"] = LLCallbackMap(createPanelLandAccess, this); - - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about_land.xml", &factory_map, false); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_about_land.xml", false); sObserver = new LLParcelSelectionObserver(); LLViewerParcelMgr::getInstance()->addObserver( sObserver ); } BOOL LLFloaterLand::postBuild() -{ +{ + mVisibleSignal.connect(boost::bind(&LLFloaterLand::onVisibilityChange, this, _2)); + LLTabContainer* tab = getChild("landtab"); mTabLand = (LLTabContainer*) tab; @@ -229,6 +256,9 @@ BOOL LLFloaterLand::postBuild() // virtual LLFloaterLand::~LLFloaterLand() { + LLViewerParcelMgr::getInstance()->removeObserver( sObserver ); + delete sObserver; + sObserver = NULL; } // public @@ -237,6 +267,7 @@ void LLFloaterLand::refresh() mPanelGeneral->refresh(); mPanelObjects->refresh(); mPanelOptions->refresh(); + mPanelAudio->refresh(); mPanelMedia->refresh(); mPanelAccess->refresh(); } @@ -275,6 +306,14 @@ void* LLFloaterLand::createPanelLandOptions(void* data) return self->mPanelOptions; } +// static +void* LLFloaterLand::createPanelLandAudio(void* data) +{ + LLFloaterLand* self = (LLFloaterLand*)data; + self->mPanelAudio = new LLPanelLandAudio(self->mParcel); + return self->mPanelAudio; +} + // static void* LLFloaterLand::createPanelLandMedia(void* data) { @@ -297,7 +336,7 @@ void* LLFloaterLand::createPanelLandAccess(void* data) LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_general_panel")), +: LLPanel(), mUncheckedSell(FALSE), mParcel(parcel) { @@ -306,15 +345,13 @@ LLPanelLandGeneral::LLPanelLandGeneral(LLParcelSelectionHandle& parcel) BOOL LLPanelLandGeneral::postBuild() { mEditName = getChild("Name"); - mEditName->setCommitCallback(onCommitAny); + mEditName->setCommitCallback(onCommitAny, this); childSetPrevalidate("Name", LLLineEditor::prevalidatePrintableNotPipe); - childSetUserData("Name", this); mEditDesc = getChild("Description"); mEditDesc->setCommitOnFocusLost(TRUE); - mEditDesc->setCommitCallback(onCommitAny); + mEditDesc->setCommitCallback(onCommitAny, this); childSetPrevalidate("Description", LLLineEditor::prevalidatePrintableNotPipe); - childSetUserData("Description", this); mTextSalePending = getChild("SalePending"); @@ -333,7 +370,7 @@ BOOL LLPanelLandGeneral::postBuild() mBtnSetGroup = getChild("Set..."); - mBtnSetGroup->setClickedCallback(onClickSetGroup, this); + mBtnSetGroup->setCommitCallback(boost::bind(&LLPanelLandGeneral::onClickSetGroup, this)); mCheckDeedToGroup = getChild( "check deed"); @@ -396,7 +433,7 @@ BOOL LLPanelLandGeneral::postBuild() mBtnReclaimLand->setClickedCallback(onClickReclaim, NULL); mBtnStartAuction = getChild("Linden Sale..."); - mBtnStartAuction->setClickedCallback(onClickStartAuction, NULL); + mBtnStartAuction->setClickedCallback(onClickStartAuction, this); return TRUE; } @@ -754,22 +791,20 @@ void LLPanelLandGeneral::draw() LLPanel::draw(); } -// static -void LLPanelLandGeneral::onClickSetGroup(void* userdata) +void LLPanelLandGeneral::onClickSetGroup() { - LLPanelLandGeneral* panelp = (LLPanelLandGeneral*)userdata; - LLFloaterGroupPicker* fg; + LLFloater* parent_floater = gFloaterView->getParentFloater(this); - LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); - - fg = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); - fg->setSelectCallback( cbGroupID, userdata ); - - if (parent_floater) + LLFloaterGroupPicker* fg = LLFloaterReg::showTypedInstance("group_picker", LLSD(gAgent.getID())); + if (fg) { - LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, fg); - fg->setOrigin(new_rect.mLeft, new_rect.mBottom); - parent_floater->addDependentFloater(fg); + fg->setSelectGroupCallback( boost::bind(&LLPanelLandGeneral::setGroup, this, _1 )); + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, fg); + fg->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(fg); + } } } @@ -783,22 +818,15 @@ void LLPanelLandGeneral::onClickProfile(void* data) if (parcel->getIsGroupOwned()) { const LLUUID& group_id = parcel->getGroupID(); - LLFloaterGroupInfo::showFromUUID(group_id); + LLGroupActions::show(group_id); } else { const LLUUID& avatar_id = parcel->getOwnerID(); - LLFloaterAvatarInfo::showFromObject(avatar_id); + LLAvatarActions::showProfile(avatar_id); } } -// static -void LLPanelLandGeneral::cbGroupID(LLUUID group_id, void* userdata) -{ - LLPanelLandGeneral* self = (LLPanelLandGeneral*)userdata; - self->setGroup(group_id); -} - // public void LLPanelLandGeneral::setGroup(const LLUUID& group_id) { @@ -900,7 +928,8 @@ void LLPanelLandGeneral::onClickStartAuction(void* data) } else { - LLFloaterAuction::show(); + //LLFloaterAuction::showInstance(); + LLFloaterReg::showInstance("auction"); } } } @@ -974,7 +1003,8 @@ void LLPanelLandGeneral::onClickStopSellLand(void* data) // LLPanelLandObjects //--------------------------------------------------------------------------- LLPanelLandObjects::LLPanelLandObjects(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_objects_panel")), mParcel(parcel) + : LLPanel(), + mParcel(parcel) { } @@ -1014,10 +1044,8 @@ BOOL LLPanelLandObjects::postBuild() mCleanOtherObjectsTime = getChild("clean other time"); mCleanOtherObjectsTime->setFocusLostCallback(onLostFocus, this); - mCleanOtherObjectsTime->setCommitCallback(onCommitClean); - + mCleanOtherObjectsTime->setCommitCallback(onCommitClean, this); childSetPrevalidate("clean other time", LLLineEditor::prevalidateNonNegativeS32); - childSetUserData("clean other time", this); mBtnRefresh = getChild("Refresh List"); mBtnRefresh->setClickedCallback(onClickRefresh, this); @@ -1032,7 +1060,7 @@ BOOL LLPanelLandObjects::postBuild() mOwnerList = getChild("owner list"); mOwnerList->sortByColumnIndex(3, FALSE); childSetCommitCallback("owner list", onCommitList, this); - mOwnerList->setDoubleClickCallback(onDoubleClickOwner); + mOwnerList->setDoubleClickCallback(onDoubleClickOwner, this); return TRUE; } @@ -1064,11 +1092,11 @@ void LLPanelLandObjects::onDoubleClickOwner(void *userdata) BOOL is_group = cell->getValue().asString() == OWNER_GROUP; if (is_group) { - LLFloaterGroupInfo::showFromUUID(owner_id); + LLGroupActions::show(owner_id); } else { - LLFloaterAvatarInfo::showFromDirectory(owner_id); + LLAvatarActions::showProfile(owner_id); } } } @@ -1406,7 +1434,7 @@ void LLPanelLandObjects::onClickRefresh(void* userdata) // ready the list for results self->mOwnerList->deleteAllItems(); - self->mOwnerList->addCommentText(std::string("Searching...")); // *TODO: Translate + self->mOwnerList->setCommentText(LLTrans::getString("Searching")); self->mOwnerList->setEnabled(FALSE); self->mFirstReply = TRUE; @@ -1468,39 +1496,34 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo continue; } - LLScrollListItem *row = new LLScrollListItem( TRUE, NULL, owner_id); + LLNameListCtrl::NameItem item_params; + item_params.value = owner_id; + item_params.target = is_group_owned ? LLNameListCtrl::GROUP : LLNameListCtrl::INDIVIDUAL; + if (is_group_owned) { - row->addColumn(self->mIconGroup); - row->addColumn(OWNER_GROUP, FONT); + item_params.columns.add().type("icon").value(self->mIconGroup->getName()).column("type"); + item_params.columns.add().value(OWNER_GROUP).font(FONT).column("online_status"); } else if (is_online) { - row->addColumn(self->mIconAvatarOnline); - row->addColumn(OWNER_ONLINE, FONT); + item_params.columns.add().type("icon").value(self->mIconAvatarOnline->getName()).column("type"); + item_params.columns.add().value(OWNER_ONLINE).font(FONT).column("online_status"); } else // offline { - row->addColumn(self->mIconAvatarOffline); - row->addColumn(OWNER_OFFLINE, FONT); + item_params.columns.add().type("icon").value(self->mIconAvatarOffline->getName()).column("type"); + item_params.columns.add().value(OWNER_OFFLINE).font(FONT).column("online_status"); } + // Placeholder for name. - row->addColumn(LLStringUtil::null, FONT); + item_params.columns.add().font(FONT).column("name"); object_count_str = llformat("%d", object_count); - row->addColumn(object_count_str, FONT); - - row->addColumn(formatted_time((time_t)most_recent_time), FONT); + item_params.columns.add().value(object_count_str).font(FONT).column("count"); + item_params.columns.add().value(formatted_time((time_t)most_recent_time)).font(FONT).column("mostrecent"); - - if (is_group_owned) - { - self->mOwnerList->addGroupNameItem(row, ADD_BOTTOM); - } - else - { - self->mOwnerList->addNameItem(row, ADD_BOTTOM); - } + self->mOwnerList->addRow(item_params); lldebugs << "object owner " << owner_id << " (" << (is_group_owned ? "group" : "agent") << ") owns " << object_count << " objects." << llendl; @@ -1508,7 +1531,7 @@ void LLPanelLandObjects::processParcelObjectOwnersReply(LLMessageSystem *msg, vo // check for no results if (0 == self->mOwnerList->getItemCount()) { - self->mOwnerList->addCommentText(std::string("None found.")); // *TODO: Translate + self->mOwnerList->setCommentText(LLTrans::getString("NoneFound")); } else { @@ -1699,7 +1722,7 @@ void LLPanelLandObjects::onCommitClean(LLUICtrl *caller, void* user_data) //--------------------------------------------------------------------------- LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_options_panel")), +: LLPanel(), mCheckEditObjects(NULL), mCheckEditGroupObjects(NULL), mCheckAllObjectEntry(NULL), @@ -1709,7 +1732,6 @@ LLPanelLandOptions::LLPanelLandOptions(LLParcelSelectionHandle& parcel) mCheckFly(NULL), mCheckGroupScripts(NULL), mCheckOtherScripts(NULL), - mCheckLandmark(NULL), mCheckShowDirectory(NULL), mCategoryCombo(NULL), mLandingTypeCombo(NULL), @@ -1743,10 +1765,6 @@ BOOL LLPanelLandOptions::postBuild() childSetCommitCallback("edit land check", onCommitAny, this); - mCheckLandmark = getChild( "check landmark"); - childSetCommitCallback("check landmark", onCommitAny, this); - - mCheckGroupScripts = getChild( "check group scripts"); childSetCommitCallback("check group scripts", onCommitAny, this); @@ -1808,8 +1826,7 @@ BOOL LLPanelLandOptions::postBuild() mSnapshotCtrl = getChild("snapshot_ctrl"); if (mSnapshotCtrl) { - mSnapshotCtrl->setCommitCallback( onCommitAny ); - mSnapshotCtrl->setCallbackUserData( this ); + mSnapshotCtrl->setCommitCallback( onCommitAny, this ); mSnapshotCtrl->setAllowNoTexture ( TRUE ); mSnapshotCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); mSnapshotCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); @@ -1873,9 +1890,6 @@ void LLPanelLandOptions::refresh() mCheckFly ->set(FALSE); mCheckFly ->setEnabled(FALSE); - mCheckLandmark ->set(FALSE); - mCheckLandmark ->setEnabled(FALSE); - mCheckGroupScripts ->set(FALSE); mCheckGroupScripts ->setEnabled(FALSE); @@ -1926,9 +1940,6 @@ void LLPanelLandOptions::refresh() mCheckFly ->set( parcel->getAllowFly() ); mCheckFly ->setEnabled( can_change_options ); - mCheckLandmark ->set( parcel->getAllowLandmark() ); - mCheckLandmark ->setEnabled( can_change_options ); - mCheckGroupScripts ->set( parcel->getAllowGroupScripts() || parcel->getAllowOtherScripts()); mCheckGroupScripts ->setEnabled( can_change_options && !parcel->getAllowOtherScripts()); @@ -2143,7 +2154,7 @@ void LLPanelLandOptions::onCommitAny(LLUICtrl *ctrl, void *userdata) BOOL allow_terraform = self->mCheckEditLand->get(); BOOL allow_damage = !self->mCheckSafe->get(); BOOL allow_fly = self->mCheckFly->get(); - BOOL allow_landmark = self->mCheckLandmark->get(); + BOOL allow_landmark = TRUE; // cannot restrict landmark creation BOOL allow_group_scripts = self->mCheckGroupScripts->get() || self->mCheckOtherScripts->get(); BOOL allow_other_scripts = self->mCheckOtherScripts->get(); BOOL allow_publish = FALSE; @@ -2262,7 +2273,8 @@ void LLPanelLandOptions::onClickPublishHelp(void*) //--------------------------------------------------------------------------- LLPanelLandAccess::LLPanelLandAccess(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_access_panel")), mParcel(parcel) + : LLPanel(), + mParcel(parcel) { } @@ -2301,6 +2313,8 @@ LLPanelLandAccess::~LLPanelLandAccess() void LLPanelLandAccess::refresh() { + LLFloater* parent_floater = gFloaterView->getParentFloater(this); + if (mListAccess) mListAccess->deleteAllItems(); if (mListBanned) @@ -2328,7 +2342,6 @@ void LLPanelLandAccess::refresh() childSetToolTipArg("AccessList", "[LISTED]", llformat("%d",count)); childSetToolTipArg("AccessList", "[MAX]", llformat("%d",PARCEL_MAX_ACCESS_LIST)); - // *TODO: Translate for (access_map_const_iterator cit = parcel->mAccessList.begin(); cit != parcel->mAccessList.end(); ++cit) { @@ -2336,25 +2349,28 @@ void LLPanelLandAccess::refresh() std::string suffix; if (entry.mTime != 0) { + LLStringUtil::format_map_t args; S32 now = time(NULL); S32 seconds = entry.mTime - now; if (seconds < 0) seconds = 0; suffix.assign(" ("); if (seconds >= 120) { - std::string buf = llformat("%d minutes", (seconds/60)); + args["[MINUTES]"] = llformat("%d", (seconds/60)); + std::string buf = parent_floater->getString ("Minutes", args); suffix.append(buf); } else if (seconds >= 60) { - suffix.append("1 minute"); + suffix.append("1 " + parent_floater->getString("Minute")); } else { - std::string buf = llformat("%d seconds", seconds); + args["[SECONDS]"] = llformat("%d", seconds); + std::string buf = parent_floater->getString ("Seconds", args); suffix.append(buf); } - suffix.append(" remaining)"); + suffix.append(" " + parent_floater->getString("Remaining") + ")"); } if (mListAccess) mListAccess->addNameItem(entry.mID, ADD_SORTED, TRUE, suffix); @@ -2375,25 +2391,28 @@ void LLPanelLandAccess::refresh() std::string suffix; if (entry.mTime != 0) { + LLStringUtil::format_map_t args; S32 now = time(NULL); S32 seconds = entry.mTime - now; if (seconds < 0) seconds = 0; suffix.assign(" ("); if (seconds >= 120) { - std::string buf = llformat("%d minutes", (seconds/60)); + args["[MINUTES]"] = llformat("%d", (seconds/60)); + std::string buf = parent_floater->getString ("Minutes", args); suffix.append(buf); } else if (seconds >= 60) { - suffix.append("1 minute"); + suffix.append("1 " + parent_floater->getString("Minute")); } else { - std::string buf = llformat("%d seconds", seconds); + args["[SECONDS]"] = llformat("%d", seconds); + std::string buf = parent_floater->getString ("Seconds", args); suffix.append(buf); } - suffix.append(" remaining)"); + suffix.append(" " + parent_floater->getString("Remaining") + ")"); } mListBanned->addNameItem(entry.mID, ADD_SORTED, TRUE, suffix); } @@ -2758,7 +2777,8 @@ void LLPanelLandAccess::onClickRemoveBanned(void* data) // LLPanelLandCovenant //--------------------------------------------------------------------------- LLPanelLandCovenant::LLPanelLandCovenant(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_covenant_panel")), mParcel(parcel) + : LLPanel(), + mParcel(parcel) { } @@ -2838,11 +2858,7 @@ void LLPanelLandCovenant::updateCovenantText(const std::string &string) if (self) { LLViewerTextEditor* editor = self->getChild("covenant_editor"); - if (editor) - { - editor->setHandleEditKeysDirectly(TRUE); - editor->setText(string); - } + editor->setText(string); } } diff --git a/indra/newview/llfloaterland.h b/indra/newview/llfloaterland.h index 4c3de65d71..749c395147 100644 --- a/indra/newview/llfloaterland.h +++ b/indra/newview/llfloaterland.h @@ -38,8 +38,9 @@ #include #include "llfloater.h" -//#include "llviewerimagelist.h" -#include "llmemory.h" // LLPointer<> +#include "llpointer.h" // LLPointer<> +//#include "llviewertexturelist.h" +#include "llsafehandle.h" typedef std::set uuid_list_t; const F32 CACHE_REFRESH_TIME = 2.5f; @@ -58,12 +59,12 @@ class LLTextBox; class LLTextEditor; class LLTextureCtrl; class LLUIImage; -class LLViewerTextEditor; class LLParcelSelection; class LLPanelLandGeneral; class LLPanelLandObjects; class LLPanelLandOptions; +class LLPanelLandAudio; class LLPanelLandMedia; class LLPanelLandAccess; class LLPanelLandBan; @@ -71,26 +72,27 @@ class LLPanelLandRenters; class LLPanelLandCovenant; class LLFloaterLand -: public LLFloater, public LLFloaterSingleton +: public LLFloater { - friend class LLUISingleton >; + friend class LLFloaterReg; public: static void refreshAll(); static LLPanelLandObjects* getCurrentPanelLandObjects(); static LLPanelLandCovenant* getCurrentPanelLandCovenant(); - // Destroys itself on close. - virtual void onClose(bool app_quitting); - virtual void onOpen(); + virtual void onOpen(const LLSD& key); virtual BOOL postBuild(); -protected: - +private: // Does its own instance management, so clients not allowed // to allocate or destroy. LLFloaterLand(const LLSD& seed); virtual ~LLFloaterLand(); + + void onVisibilityChange(const LLSD& visible); + +protected: /*virtual*/ void refresh(); @@ -98,6 +100,7 @@ protected: static void* createPanelLandCovenant(void* data); static void* createPanelLandObjects(void* data); static void* createPanelLandOptions(void* data); + static void* createPanelLandAudio(void* data); static void* createPanelLandMedia(void* data); static void* createPanelLandAccess(void* data); static void* createPanelLandBan(void* data); @@ -111,6 +114,7 @@ protected: LLPanelLandGeneral* mPanelGeneral; LLPanelLandObjects* mPanelObjects; LLPanelLandOptions* mPanelOptions; + LLPanelLandAudio* mPanelAudio; LLPanelLandMedia* mPanelMedia; LLPanelLandAccess* mPanelAccess; LLPanelLandCovenant* mPanelCovenant; @@ -138,8 +142,7 @@ public: void setGroup(const LLUUID& group_id); static void onClickProfile(void*); - static void onClickSetGroup(void*); - static void cbGroupID(LLUUID group_id, void* userdata); + void onClickSetGroup(); static BOOL enableDeedToGroup(void*); static void onClickDeed(void*); static void onClickBuyLand(void* data); @@ -329,7 +332,6 @@ private: LLCheckBoxCtrl* mCheckFly; LLCheckBoxCtrl* mCheckGroupScripts; LLCheckBoxCtrl* mCheckOtherScripts; - LLCheckBoxCtrl* mCheckLandmark; LLCheckBoxCtrl* mCheckShowDirectory; LLComboBox* mCategoryCombo; diff --git a/indra/newview/llfloaterlandholdings.cpp b/indra/newview/llfloaterlandholdings.cpp index bd1186b151..19552ca9c9 100644 --- a/indra/newview/llfloaterlandholdings.cpp +++ b/indra/newview/llfloaterlandholdings.cpp @@ -41,58 +41,32 @@ #include "message.h" #include "llagent.h" -#include "llbutton.h" -#include "llfloatergroupinfo.h" +#include "llfloaterreg.h" #include "llfloaterworldmap.h" #include "llproductinforequest.h" #include "llscrolllistctrl.h" #include "llstatusbar.h" #include "lltextbox.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lltrans.h" #include "lluiconstants.h" #include "llviewermessage.h" #include "lluictrlfactory.h" -// statics -LLFloaterLandHoldings* LLFloaterLandHoldings::sInstance = NULL; - - -// static -void LLFloaterLandHoldings::show(void*) -{ - LLFloaterLandHoldings* floater = new LLFloaterLandHoldings(); - LLUICtrlFactory::getInstance()->buildFloater(floater, "floater_land_holdings.xml"); - floater->center(); - - // query_id null is known to be us - const LLUUID& query_id = LLUUID::null; - - // look only for parcels we own - U32 query_flags = DFQ_AGENT_OWNED; - - send_places_query(query_id, - LLUUID::null, - "", - query_flags, - LLParcel::C_ANY, - ""); - - // TODO: request updated L$ balance? - floater->open(); /* Flawfinder: ignore */ -} - +#include "llgroupactions.h" // protected -LLFloaterLandHoldings::LLFloaterLandHoldings() -: LLFloater(std::string("land holdings floater")), +LLFloaterLandHoldings::LLFloaterLandHoldings(const LLSD& key) +: LLFloater(key), mActualArea(0), mBillableArea(0), mFirstPacketReceived(FALSE), mSortColumn(""), mSortAscending(TRUE) { - // Instance management. - sInstance = this; +// LLUICtrlFactory::getInstance()->buildFloater(floater, "floater_land_holdings.xml"); } BOOL LLFloaterLandHoldings::postBuild() @@ -101,8 +75,7 @@ BOOL LLFloaterLandHoldings::postBuild() childSetAction("Show on Map", onClickMap, this); // Grant list - childSetDoubleClickCallback("grant list", onGrantList); - childSetUserData("grant list", this); + getChild("grant list")->setDoubleClickCallback(onGrantList, this); LLCtrlListInterface *list = childGetListInterface("grant list"); if (!list) return TRUE; @@ -126,7 +99,9 @@ BOOL LLFloaterLandHoldings::postBuild() list->addElement(element, ADD_SORTED); } - + + center(); + return TRUE; } @@ -134,9 +109,23 @@ BOOL LLFloaterLandHoldings::postBuild() // protected LLFloaterLandHoldings::~LLFloaterLandHoldings() { - sInstance = NULL; } +void LLFloaterLandHoldings::onOpen(const LLSD& key) +{ + // query_id null is known to be us + const LLUUID& query_id = LLUUID::null; + + // look only for parcels we own + U32 query_flags = DFQ_AGENT_OWNED; + + send_places_query(query_id, + LLUUID::null, + "", + query_flags, + LLParcel::C_ANY, + ""); +} void LLFloaterLandHoldings::draw() { @@ -166,7 +155,7 @@ void LLFloaterLandHoldings::refresh() // static void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) { - LLFloaterLandHoldings* self = sInstance; + LLFloaterLandHoldings* self = LLFloaterReg::findTypedInstance("land_holdings"); // Is this packet from an old, closed window? if (!self) @@ -222,50 +211,53 @@ void LLFloaterLandHoldings::processPlacesReply(LLMessageSystem* msg, void**) land_type = LLTrans::getString("land_type_unknown"); } - self->mActualArea += actual_area; - self->mBillableArea += billable_area; - - S32 region_x = llround(global_x) % REGION_WIDTH_UNITS; - S32 region_y = llround(global_y) % REGION_WIDTH_UNITS; - - std::string location; - location = llformat("%s (%d, %d)", sim_name.c_str(), region_x, region_y); - - std::string area; - if(billable_area == actual_area) + if(owner_id.notNull()) { - area = llformat("%d", billable_area); - } - else - { - area = llformat("%d / %d", billable_area, actual_area); - } - - std::string hidden; - hidden = llformat("%f %f", global_x, global_y); + self->mActualArea += actual_area; + self->mBillableArea += billable_area; - LLSD element; - element["columns"][0]["column"] = "name"; - element["columns"][0]["value"] = name; - element["columns"][0]["font"] = "SANSSERIF"; - - element["columns"][1]["column"] = "location"; - element["columns"][1]["value"] = location; - element["columns"][1]["font"] = "SANSSERIF"; - - element["columns"][2]["column"] = "area"; - element["columns"][2]["value"] = area; - element["columns"][2]["font"] = "SANSSERIF"; - - element["columns"][3]["column"] = "type"; - element["columns"][3]["value"] = land_type; - element["columns"][3]["font"] = "SANSSERIF"; - - // hidden is always last column - element["columns"][4]["column"] = "hidden"; - element["columns"][4]["value"] = hidden; + S32 region_x = llround(global_x) % REGION_WIDTH_UNITS; + S32 region_y = llround(global_y) % REGION_WIDTH_UNITS; - list->addElement(element); + std::string location; + location = llformat("%s (%d, %d)", sim_name.c_str(), region_x, region_y); + + std::string area; + if(billable_area == actual_area) + { + area = llformat("%d", billable_area); + } + else + { + area = llformat("%d / %d", billable_area, actual_area); + } + + std::string hidden; + hidden = llformat("%f %f", global_x, global_y); + + LLSD element; + element["columns"][0]["column"] = "name"; + element["columns"][0]["value"] = name; + element["columns"][0]["font"] = "SANSSERIF"; + + element["columns"][1]["column"] = "location"; + element["columns"][1]["value"] = location; + element["columns"][1]["font"] = "SANSSERIF"; + + element["columns"][2]["column"] = "area"; + element["columns"][2]["value"] = area; + element["columns"][2]["font"] = "SANSSERIF"; + + element["columns"][3]["column"] = "type"; + element["columns"][3]["value"] = land_type; + element["columns"][3]["font"] = "SANSSERIF"; + + // hidden is always last column + element["columns"][4]["column"] = "hidden"; + element["columns"][4]["value"] = hidden; + + list->addElement(element); + } } self->refreshAggregates(); @@ -290,16 +282,17 @@ void LLFloaterLandHoldings::buttonCore(S32 which) F64 global_z = gAgent.getPositionGlobal().mdV[VZ]; LLVector3d pos_global(global_x, global_y, global_z); + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); switch(which) { case 0: gAgent.teleportViaLocation(pos_global); - gFloaterWorldMap->trackLocation(pos_global); + if(floater_world_map) floater_world_map->trackLocation(pos_global); break; case 1: - gFloaterWorldMap->trackLocation(pos_global); - LLFloaterWorldMap::show(NULL, TRUE); + if(floater_world_map) floater_world_map->trackLocation(pos_global); + LLFloaterReg::showInstance("world_map", "center"); break; default: break; @@ -311,7 +304,7 @@ void LLFloaterLandHoldings::onClickTeleport(void* data) { LLFloaterLandHoldings* self = (LLFloaterLandHoldings*)data; self->buttonCore(0); - self->close(); + self->closeFloater(); } @@ -331,7 +324,7 @@ void LLFloaterLandHoldings::onGrantList(void* data) LLUUID group_id = list->getCurrentID(); if (group_id.notNull()) { - LLFloaterGroupInfo::showFromUUID(group_id); + LLGroupActions::show(group_id); } } diff --git a/indra/newview/llfloaterlandholdings.h b/indra/newview/llfloaterlandholdings.h index def77cf2a8..471ddf7f44 100644 --- a/indra/newview/llfloaterlandholdings.h +++ b/indra/newview/llfloaterlandholdings.h @@ -44,10 +44,11 @@ class LLFloaterLandHoldings : public LLFloater { public: - BOOL postBuild(); - - static void show(void*); - + LLFloaterLandHoldings(const LLSD& key); + virtual ~LLFloaterLandHoldings(); + + virtual BOOL postBuild(); + virtual void onOpen(const LLSD& key); virtual void draw(); void refresh(); @@ -63,14 +64,9 @@ public: static void onGrantList(void* data); protected: - LLFloaterLandHoldings(); - virtual ~LLFloaterLandHoldings(); - void refreshAggregates(); protected: - static LLFloaterLandHoldings* sInstance; - // Sum up as packets arrive the total holdings S32 mActualArea; S32 mBillableArea; diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp index 3b1e4c7ac7..eac1b65f7d 100644 --- a/indra/newview/llfloatermap.cpp +++ b/indra/newview/llfloatermap.cpp @@ -30,96 +30,188 @@ * $/LicenseInfo$ */ +#include #include "llviewerprecompiledheaders.h" +// self include #include "llfloatermap.h" +// Library includes +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llglheaders.h" + +// Viewer includes #include "llagent.h" -#include "llcolorscheme.h" #include "llviewercontrol.h" -#include "lldraghandle.h" #include "llnetmap.h" -#include "llregionhandle.h" -#include "llresizebar.h" -#include "lluictrlfactory.h" +#include "lltracker.h" +#include "llviewercamera.h" +#include "lldraghandle.h" +#include "lltextbox.h" +#include "llviewermenu.h" -LLFloaterMap::LLFloaterMap(const LLSD& key) - : - LLFloater(std::string("minimap")), - mPanelMap(NULL) +// +// Constants +// +const F32 MAP_SCALE_MIN = 64; +const F32 MAP_SCALE_MID = 172; +const F32 MAP_SCALE_MAX = 512; + +// +// Member functions +// + +LLFloaterMap::LLFloaterMap(const LLSD& key) + : LLFloater(key) { - LLCallbackMap::map_t factory_map; - factory_map["mini_mapview"] = LLCallbackMap(createPanelMiniMap, this); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_mini_map.xml", &factory_map, FALSE); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_map.xml", FALSE); } - -// static -void* LLFloaterMap::createPanelMiniMap(void* data) -{ - LLFloaterMap* self = (LLFloaterMap*)data; - self->mPanelMap = new LLNetMap("Mapview"); - return self->mPanelMap; -} - -BOOL LLFloaterMap::postBuild() -{ - // Send the drag handle to the back, but make sure close stays on top - sendChildToBack(getDragHandle()); - sendChildToFront(getChild("llfloater_close_btn")); - setIsChrome(TRUE); - return TRUE; -} - - LLFloaterMap::~LLFloaterMap() { } - -// virtual -void LLFloaterMap::onOpen() +BOOL LLFloaterMap::postBuild() { + mMap = getChild("Net Map"); + mMap->setScale(gSavedSettings.getF32("MiniMapScale")); + mMap->setRotateMap(gSavedSettings.getBOOL( "MiniMapRotate" )); + mMap->setToolTipMsg(getString("ToolTipMsg")); + sendChildToBack(mMap); + + mTextBoxNorth = getChild ("floater_map_north"); + mTextBoxEast = getChild ("floater_map_east"); + mTextBoxWest = getChild ("floater_map_west"); + mTextBoxSouth = getChild ("floater_map_south"); + mTextBoxSouthEast = getChild ("floater_map_southeast"); + mTextBoxNorthEast = getChild ("floater_map_northeast"); + mTextBoxSouthWest = getChild ("floater_map_southwest"); + mTextBoxNorthWest = getChild ("floater_map_northwest"); + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("Minimap.Zoom", boost::bind(&LLFloaterMap::handleZoom, this, _2)); + registrar.add("Minimap.Tracker", boost::bind(&LLFloaterMap::handleStopTracking, this, _2)); + + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (mPopupMenu && !LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + } + + // Get the drag handle all the way in back + sendChildToBack(getDragHandle()); + + setIsChrome(TRUE); + + // keep onscreen gFloaterView->adjustToFitScreen(this, FALSE); - gSavedSettings.setBOOL("ShowMiniMap", TRUE); + return TRUE; } - -// virtual -void LLFloaterMap::onClose(bool app_quitting) +BOOL LLFloaterMap::handleDoubleClick( S32 x, S32 y, MASK mask ) { - LLFloater::setVisible(FALSE); + LLFloaterReg::showInstance("world_map"); + return TRUE; +} - if (!app_quitting) +BOOL LLFloaterMap::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mPopupMenu) { - gSavedSettings.setBOOL("ShowMiniMap", FALSE); + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mPopupMenu, x, y); } + return TRUE; } -BOOL LLFloaterMap::canClose() +void LLFloaterMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) { - return !LLApp::isExiting(); -} + // Rotation is in radians. + // Rotation of 0 means x = 1, y = 0 on the unit circle. + F32 map_half_height = (F32)(getRect().getHeight() / 2); + F32 map_half_width = (F32)(getRect().getWidth() / 2); + F32 text_half_height = (F32)(text_box->getRect().getHeight() / 2); + F32 text_half_width = (F32)(text_box->getRect().getWidth() / 2); + F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width ); + + // Inset by a little to account for position display. + radius -= 8.f; + + text_box->setOrigin( + llround(map_half_width - text_half_width + radius * cos( rotation )), + llround(map_half_height - text_half_height + radius * sin( rotation )) ); +} // virtual void LLFloaterMap::draw() { + F32 rotation = 0; + + if( mMap->getRotateMap() ) + { + // rotate subsequent draws to agent rotation + rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); + } + + setDirectionPos( mTextBoxEast, rotation ); + setDirectionPos( mTextBoxNorth, rotation + F_PI_BY_TWO ); + setDirectionPos( mTextBoxWest, rotation + F_PI ); + setDirectionPos( mTextBoxSouth, rotation + F_PI + F_PI_BY_TWO ); + + setDirectionPos( mTextBoxNorthEast, rotation + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxNorthWest, rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxSouthWest, rotation + F_PI + F_PI_BY_TWO / 2); + setDirectionPos( mTextBoxSouthEast, rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); + // Note: we can't just gAgent.check cameraMouselook() because the transition states are wrong. if( gAgent.cameraMouselook()) { setMouseOpaque(FALSE); getDragHandle()->setMouseOpaque(FALSE); - - drawChild(mPanelMap); } else { setMouseOpaque(TRUE); getDragHandle()->setMouseOpaque(TRUE); + } + + if (LLTracker::isTracking(0)) + { + mPopupMenu->setItemEnabled ("Stop Tracking", true); + } + + LLFloater::draw(); +} - LLFloater::draw(); +void LLFloaterMap::handleZoom(const LLSD& userdata) +{ + std::string level = userdata.asString(); + + F32 scale = 0.0f; + if (level == std::string("close")) + scale = MAP_SCALE_MAX; + else if (level == std::string("medium")) + scale = MAP_SCALE_MID; + else if (level == std::string("far")) + scale = MAP_SCALE_MIN; + if (scale != 0.0f) + { + gSavedSettings.setF32("MiniMapScale", scale ); + mMap->setScale(scale); + } +} + +void LLFloaterMap::handleStopTracking (const LLSD& userdata) +{ + if (mPopupMenu) + { + mPopupMenu->setItemEnabled ("Stop Tracking", false); + LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL)); } } diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h index ec2db27f7a..501777ed07 100644 --- a/indra/newview/llfloatermap.h +++ b/indra/newview/llfloatermap.h @@ -35,28 +35,42 @@ #include "llfloater.h" +class LLMenuGL; class LLNetMap; +class LLTextBox; -class LLFloaterMap : - public LLFloater, - public LLFloaterSingleton +// +// Classes +// +class LLFloaterMap : public LLFloater { - friend class LLUISingleton >; public: + LLFloaterMap(const LLSD& key); virtual ~LLFloaterMap(); - - static void* createPanelMiniMap(void* data); - - BOOL postBuild(); - + + /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + /*virtual*/ BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); /*virtual*/ void draw(); - /*virtual*/ void onOpen(); - /*virtual*/ void onClose(bool app_quitting); - /*virtual*/ BOOL canClose(); - + private: - LLFloaterMap(const LLSD& key = LLSD()); - LLNetMap* mPanelMap; + void handleZoom(const LLSD& userdata); + void handleStopTracking (const LLSD& userdata); + void setDirectionPos( LLTextBox* text_box, F32 rotation ); + + LLMenuGL* mPopupMenu; + + LLTextBox* mTextBoxEast; + LLTextBox* mTextBoxNorth; + LLTextBox* mTextBoxWest; + LLTextBox* mTextBoxSouth; + + LLTextBox* mTextBoxSouthEast; + LLTextBox* mTextBoxNorthEast; + LLTextBox* mTextBoxNorthWest; + LLTextBox* mTextBoxSouthWest; + + LLNetMap* mMap; }; #endif // LL_LLFLOATERMAP_H diff --git a/indra/newview/llfloatermediabrowser.cpp b/indra/newview/llfloatermediabrowser.cpp new file mode 100644 index 0000000000..c580cdef8a --- /dev/null +++ b/indra/newview/llfloatermediabrowser.cpp @@ -0,0 +1,398 @@ +/** + * @file llfloaterhtmlhelp.cpp + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloatermediabrowser.h" +#include "llfloaterhtml.h" + +#include "llfloaterreg.h" +#include "llparcel.h" +#include "llpluginclassmedia.h" +#include "lluictrlfactory.h" +#include "llmediactrl.h" +#include "llviewerwindow.h" +#include "llviewercontrol.h" +#include "llviewerparcelmgr.h" +#include "llweb.h" +#include "llui.h" +#include "roles_constants.h" + +#include "llurlhistory.h" +#include "llmediactrl.h" +#include "llviewermedia.h" +#include "llviewerparcelmedia.h" +#include "llcombobox.h" + + +// TEMP +#include "llsdutil.h" + +LLFloaterMediaBrowser::LLFloaterMediaBrowser(const LLSD& key) + : LLFloater(key) +{ +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_media_browser.xml"); + +} + +void LLFloaterMediaBrowser::draw() +{ + childSetEnabled("go", !mAddressCombo->getValue().asString().empty()); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(parcel) + { + childSetVisible("parcel_owner_controls", LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA)); + childSetEnabled("assign", !mAddressCombo->getValue().asString().empty()); + } + bool show_time_controls = false; + bool media_playing = false; + if(mBrowser) + { + LLPluginClassMedia* media_plugin = mBrowser->getMediaPlugin(); + if(media_plugin) + { + show_time_controls = media_plugin->pluginSupportsMediaTime(); + media_playing = media_plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING; + } + } + childSetVisible("rewind", show_time_controls); + childSetVisible("play", show_time_controls && ! media_playing); + childSetVisible("pause", show_time_controls && media_playing); + childSetVisible("stop", show_time_controls); + childSetVisible("seek", show_time_controls); + + childSetEnabled("play", ! media_playing); + childSetEnabled("stop", media_playing); + + childSetEnabled("back", mBrowser->canNavigateBack()); + childSetEnabled("forward", mBrowser->canNavigateForward()); + + LLFloater::draw(); +} + +BOOL LLFloaterMediaBrowser::postBuild() +{ + mBrowser = getChild("browser"); + mBrowser->addObserver(this); + + mAddressCombo = getChild("address"); + mAddressCombo->setCommitCallback(onEnterAddress, this); + + childSetAction("back", onClickBack, this); + childSetAction("forward", onClickForward, this); + childSetAction("reload", onClickRefresh, this); + childSetAction("rewind", onClickRewind, this); + childSetAction("play", onClickPlay, this); + childSetAction("stop", onClickStop, this); + childSetAction("pause", onClickPlay, this); + childSetAction("seek", onClickSeek, this); + childSetAction("go", onClickGo, this); + childSetAction("close", onClickClose, this); + childSetAction("open_browser", onClickOpenWebBrowser, this); + childSetAction("assign", onClickAssign, this); + + buildURLHistory(); + return TRUE; +} + +void LLFloaterMediaBrowser::buildURLHistory() +{ + LLCtrlListInterface* url_list = childGetListInterface("address"); + if (url_list) + { + url_list->operateOnAll(LLCtrlListInterface::OP_DELETE); + } + + // Get all of the entries in the "browser" collection + LLSD browser_history = LLURLHistory::getURLHistory("browser"); + + LLSD::array_iterator iter_history = + browser_history.beginArray(); + LLSD::array_iterator end_history = + browser_history.endArray(); + for(; iter_history != end_history; ++iter_history) + { + std::string url = (*iter_history).asString(); + if(! url.empty()) + url_list->addSimpleElement(url); + } + + // initialize URL history in the plugin + mBrowser->getMediaPlugin()->initializeUrlHistory(browser_history); +} + +std::string LLFloaterMediaBrowser::getSupportURL() +{ + return getString("support_page_url"); +} +void LLFloaterMediaBrowser::onClose(bool app_quitting) +{ + //setVisible(FALSE); + destroy(); +} + +void LLFloaterMediaBrowser::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + if(event == MEDIA_EVENT_LOCATION_CHANGED) + { + setCurrentURL(self->getLocation()); + } + else if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) + { + // This is the event these flags are sent with. + childSetEnabled("back", self->getHistoryBackAvailable()); + childSetEnabled("forward", self->getHistoryForwardAvailable()); + } +} +void LLFloaterMediaBrowser::setCurrentURL(const std::string& url) +{ + mCurrentURL = url; + + // redirects will navigate momentarily to about:blank, don't add to history + if (mCurrentURL != "about:blank") + { + mAddressCombo->remove(mCurrentURL); + mAddressCombo->add(mCurrentURL, ADD_SORTED); + mAddressCombo->selectByValue(mCurrentURL); + + // Serialize url history + LLURLHistory::removeURL("browser", mCurrentURL); + LLURLHistory::addURL("browser", mCurrentURL); + } + childSetEnabled("back", mBrowser->canNavigateBack()); + childSetEnabled("forward", mBrowser->canNavigateForward()); + childSetEnabled("reload", TRUE); +} + +void LLFloaterMediaBrowser::onOpen(const LLSD& media_url) +{ + LLFloater::onOpen(media_url); + openMedia(media_url.asString()); +} + +//static +void LLFloaterMediaBrowser::onEnterAddress(LLUICtrl* ctrl, void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); +} + +//static +void LLFloaterMediaBrowser::onClickRefresh(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mAddressCombo->remove(0); + self->mBrowser->navigateTo(self->mCurrentURL); +} + +//static +void LLFloaterMediaBrowser::onClickForward(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateForward(); +} + +//static +void LLFloaterMediaBrowser::onClickBack(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateBack(); +} + +//static +void LLFloaterMediaBrowser::onClickGo(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->mBrowser->navigateTo(self->mAddressCombo->getValue().asString()); +} + +//static +void LLFloaterMediaBrowser::onClickClose(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + self->closeFloater(); +} + +//static +void LLFloaterMediaBrowser::onClickOpenWebBrowser(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + std::string url = self->mCurrentURL.empty() ? + self->mBrowser->getHomePageUrl() : + self->mCurrentURL; + LLWeb::loadURLExternal(url); +} + +void LLFloaterMediaBrowser::onClickAssign(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!parcel) + { + return; + } + std::string media_url = self->mAddressCombo->getValue().asString(); + LLStringUtil::trim(media_url); + + if(parcel->getMediaType() != "text/html") + { + parcel->setMediaURL(media_url); + parcel->setMediaCurrentURL(media_url); + parcel->setMediaType(std::string("text/html")); + LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel, true ); + LLViewerParcelMedia::sendMediaNavigateMessage(media_url); + LLViewerParcelMedia::stop(); + // LLViewerParcelMedia::update( parcel ); + } + LLViewerParcelMedia::sendMediaNavigateMessage(media_url); +} +//static +void LLFloaterMediaBrowser::onClickRewind(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->start(-2.0f); +} +//static +void LLFloaterMediaBrowser::onClickPlay(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + LLPluginClassMedia* plugin = self->mBrowser->getMediaPlugin(); + if(plugin) + { + if(plugin->getStatus() == LLPluginClassMediaOwner::MEDIA_PLAYING) + { + plugin->pause(); + } + else + { + plugin->start(); + } + } +} +//static +void LLFloaterMediaBrowser::onClickStop(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->stop(); +} +//static +void LLFloaterMediaBrowser::onClickSeek(void* user_data) +{ + LLFloaterMediaBrowser* self = (LLFloaterMediaBrowser*)user_data; + + if(self->mBrowser->getMediaPlugin()) + self->mBrowser->getMediaPlugin()->start(2.0f); +} +void LLFloaterMediaBrowser::openMedia(const std::string& media_url) +{ + mBrowser->setHomePageUrl(media_url); + mBrowser->navigateTo(media_url); + setCurrentURL(media_url); +} +//////////////////////////////////////////////////////////////////////////////// +// + +LLViewerHtmlHelp gViewerHtmlHelp; + + +//////////////////////////////////////////////////////////////////////////////// +// +LLViewerHtmlHelp::LLViewerHtmlHelp() +{ + + LLUI::setHtmlHelp(this); +} + +LLViewerHtmlHelp::~LLViewerHtmlHelp() +{ + + LLUI::setHtmlHelp(NULL); +} + +void LLViewerHtmlHelp::show() +{ + show(""); +} + +void LLViewerHtmlHelp::show(std::string url) +{ + LLFloaterMediaBrowser* floater_html = dynamic_cast(LLFloaterReg::getInstance("media_browser")); + floater_html->setVisible(FALSE); + + if (url.empty()) + { + url = floater_html->getSupportURL(); + } + + if (gSavedSettings.getBOOL("UseExternalBrowser")) + { + LLSD notificationData; + notificationData["url"] = url; + + LLNotifications::instance().add("ClickOpenF1Help", notificationData, LLSD(), onClickF1HelpLoadURL); + floater_html->closeFloater(); + } + else + { + // don't wait, just do it + floater_html->setVisible(TRUE); + floater_html->openMedia(url); + } +} + +// static +bool LLViewerHtmlHelp::onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response) +{ + LLFloaterMediaBrowser* floater_html = dynamic_cast(LLFloaterReg::getInstance("media_browser")); + floater_html->setVisible(FALSE); + std::string url = floater_html->getSupportURL(); + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) + { + LLWeb::loadURL(url); + } + floater_html->closeFloater(); + return false; +} + diff --git a/indra/newview/llfloatermediabrowser.h b/indra/newview/llfloatermediabrowser.h new file mode 100644 index 0000000000..76e8b517a0 --- /dev/null +++ b/indra/newview/llfloatermediabrowser.h @@ -0,0 +1,99 @@ +/** + * @file llfloatermediabrowser.h + * @brief HTML Help floater - uses embedded web browser control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFLOATERMEDIABROWSER_H +#define LL_LLFLOATERMEDIABROWSER_H + +#include "llhtmlhelp.h" +#include "llfloater.h" +#include "llmediactrl.h" + +class LLViewerHtmlHelp : public LLHtmlHelp +{ +public: + LLViewerHtmlHelp(); + virtual ~LLViewerHtmlHelp(); + + /*virtual*/ void show(); + /*virtual*/ void show(std::string start_url); + void show(std::string start_url, std::string title); + + static bool onClickF1HelpLoadURL(const LLSD& notification, const LLSD& response); + +}; + +class LLComboBox; +class LLMediaCtrl; + +class LLFloaterMediaBrowser : + public LLFloater, + public LLViewerMediaObserver +{ +public: + LLFloaterMediaBrowser(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onClose(bool app_quitting); + /*virtual*/ void draw(); + /*virtual*/ void onOpen(const LLSD& key); + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + void openMedia(const std::string& media_url); + void buildURLHistory(); + std::string getSupportURL(); + void setCurrentURL(const std::string& url); + + static void onEnterAddress(LLUICtrl* ctrl, void* user_data); + static void onClickRefresh(void* user_data); + static void onClickBack(void* user_data); + static void onClickForward(void* user_data); + static void onClickGo(void* user_data); + static void onClickClose(void* user_data); + static void onClickOpenWebBrowser(void* user_data); + static void onClickAssign(void* user_data); + static void onClickRewind(void* user_data); + static void onClickPlay(void* user_data); + static void onClickStop(void* user_data); + static void onClickSeek(void* user_data); + +private: + LLMediaCtrl* mBrowser; + LLComboBox* mAddressCombo; + std::string mCurrentURL; +}; + +extern LLViewerHtmlHelp gViewerHtmlHelp; + +#endif // LL_LLFLOATERMEDIABROWSER_H + diff --git a/indra/newview/llfloatermemleak.cpp b/indra/newview/llfloatermemleak.cpp index df51918e35..529bd68e03 100644 --- a/indra/newview/llfloatermemleak.cpp +++ b/indra/newview/llfloatermemleak.cpp @@ -42,24 +42,56 @@ #include "llmath.h" #include "llviewerwindow.h" -LLFloaterMemLeak* LLFloaterMemLeak::sInstance = NULL; U32 LLFloaterMemLeak::sMemLeakingSpeed = 0 ; //bytes leaked per frame U32 LLFloaterMemLeak::sMaxLeakedMem = 0 ; //maximum allowed leaked memory U32 LLFloaterMemLeak::sTotalLeaked = 0 ; S32 LLFloaterMemLeak::sStatus = LLFloaterMemLeak::STOP ; BOOL LLFloaterMemLeak::sbAllocationFailed = FALSE ; -LLFloaterMemLeak::LLFloaterMemLeak() : LLFloater("Memory Leaking Simulation Floater") +LLFloaterMemLeak::LLFloaterMemLeak(const LLSD& key) + : LLFloater(key) { + setTitle("Memory Leaking Simulation Floater"); + mCommitCallbackRegistrar.add("MemLeak.ChangeLeakingSpeed", boost::bind(&LLFloaterMemLeak::onChangeLeakingSpeed, this)); + mCommitCallbackRegistrar.add("MemLeak.ChangeMaxMemLeaking", boost::bind(&LLFloaterMemLeak::onChangeMaxMemLeaking, this)); + mCommitCallbackRegistrar.add("MemLeak.Start", boost::bind(&LLFloaterMemLeak::onClickStart, this)); + mCommitCallbackRegistrar.add("MemLeak.Stop", boost::bind(&LLFloaterMemLeak::onClickStop, this)); + mCommitCallbackRegistrar.add("MemLeak.Release", boost::bind(&LLFloaterMemLeak::onClickRelease, this)); + mCommitCallbackRegistrar.add("MemLeak.Close", boost::bind(&LLFloaterMemLeak::onClickClose, this)); } +//---------------------------------------------- +BOOL LLFloaterMemLeak::postBuild(void) +{ + F32 a, b ; + a = childGetValue("leak_speed").asReal(); + if(a > (F32)(0xFFFFFFFF)) + { + sMemLeakingSpeed = 0xFFFFFFFF ; + } + else + { + sMemLeakingSpeed = (U32)a ; + } + b = childGetValue("max_leak").asReal(); + if(b > (F32)0xFFF) + { + sMaxLeakedMem = 0xFFFFFFFF ; + } + else + { + sMaxLeakedMem = ((U32)b) << 20 ; + } + + sbAllocationFailed = FALSE ; + return TRUE ; +} LLFloaterMemLeak::~LLFloaterMemLeak() { release() ; sMemLeakingSpeed = 0 ; //bytes leaked per frame sMaxLeakedMem = 0 ; //maximum allowed leaked memory - sInstance = NULL ; } void LLFloaterMemLeak::release() @@ -115,79 +147,56 @@ void LLFloaterMemLeak::idle() } //---------------------- -void LLFloaterMemLeak::onChangeLeakingSpeed(LLUICtrl* ctrl, void* userData) +void LLFloaterMemLeak::onChangeLeakingSpeed() { - LLFloaterMemLeak *mem_leak = (LLFloaterMemLeak *)userData; - if (mem_leak) - { - F32 tmp ; - tmp = mem_leak->childGetValue("leak_speed").asReal(); + F32 tmp ; + tmp =childGetValue("leak_speed").asReal(); - if(tmp > (F32)0xFFFFFFFF) - { - sMemLeakingSpeed = 0xFFFFFFFF ; - } - else - { - sMemLeakingSpeed = (U32)tmp ; - } + if(tmp > (F32)0xFFFFFFFF) + { + sMemLeakingSpeed = 0xFFFFFFFF ; } + else + { + sMemLeakingSpeed = (U32)tmp ; + } + } -void LLFloaterMemLeak::onChangeMaxMemLeaking(LLUICtrl* ctrl, void* userData) +void LLFloaterMemLeak::onChangeMaxMemLeaking() { - LLFloaterMemLeak *mem_leak = (LLFloaterMemLeak *)userData; - if (mem_leak) + + F32 tmp ; + tmp =childGetValue("max_leak").asReal(); + if(tmp > (F32)0xFFF) { - F32 tmp ; - tmp = mem_leak->childGetValue("max_leak").asReal(); - if(tmp > (F32)0xFFF) - { - sMaxLeakedMem = 0xFFFFFFFF ; - } - else - { - sMaxLeakedMem = ((U32)tmp) << 20 ; - } + sMaxLeakedMem = 0xFFFFFFFF ; } + else + { + sMaxLeakedMem = ((U32)tmp) << 20 ; + } + } -void LLFloaterMemLeak::onClickStart(void* userData) +void LLFloaterMemLeak::onClickStart() { sStatus = START ; } -void LLFloaterMemLeak::onClickStop(void* userData) +void LLFloaterMemLeak::onClickStop() { sStatus = STOP ; } -void LLFloaterMemLeak::onClickRelease(void* userData) +void LLFloaterMemLeak::onClickRelease() { sStatus = RELEASE ; } -void LLFloaterMemLeak::onClickClose(void* userData) +void LLFloaterMemLeak::onClickClose() { - if (sInstance) - { - sInstance->setVisible(FALSE); - } -} - -//---------------------------------------------- - -BOOL LLFloaterMemLeak::postBuild(void) -{ - childSetCommitCallback("leak_speed", onChangeLeakingSpeed, this); - childSetCommitCallback("max_leak", onChangeMaxMemLeaking, this); - - childSetAction("start_btn", onClickStart, this); - childSetAction("stop_btn", onClickStop, this); - childSetAction("release_btn", onClickRelease, this); - childSetAction("close_btn", onClickClose, this); - - return TRUE ; + setVisible(FALSE); } void LLFloaterMemLeak::draw() @@ -217,50 +226,3 @@ void LLFloaterMemLeak::draw() LLFloater::draw(); } - -// static instance of it -LLFloaterMemLeak* LLFloaterMemLeak::instance() -{ - if (!sInstance) - { - sInstance = new LLFloaterMemLeak(); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_mem_leaking.xml", NULL, FALSE); - - if(sInstance) - { - F32 a, b ; - a = sInstance->childGetValue("leak_speed").asReal(); - if(a > (F32)(0xFFFFFFFF)) - { - sMemLeakingSpeed = 0xFFFFFFFF ; - } - else - { - sMemLeakingSpeed = (U32)a ; - } - b = sInstance->childGetValue("max_leak").asReal(); - if(b > (F32)0xFFF) - { - sMaxLeakedMem = 0xFFFFFFFF ; - } - else - { - sMaxLeakedMem = ((U32)b) << 20 ; - } - - sbAllocationFailed = FALSE ; - } - } - return sInstance ; -} - -void LLFloaterMemLeak::show(void*) -{ - instance()->open(); -} - -LLFloaterMemLeak* LLFloaterMemLeak::getInstance() -{ - return sInstance ; -} - diff --git a/indra/newview/llfloatermemleak.h b/indra/newview/llfloatermemleak.h index 7d9d5f9c5f..763af943ba 100644 --- a/indra/newview/llfloatermemleak.h +++ b/indra/newview/llfloatermemleak.h @@ -37,34 +37,28 @@ class LLFloaterMemLeak : public LLFloater { + friend class LLFloaterReg; public: - LLFloaterMemLeak(); - virtual ~LLFloaterMemLeak(); - /// initialize all the callbacks for the menu - //void initCallbacks(void); + virtual BOOL postBuild() ; virtual void draw() ; - - /// one and one instance only - static LLFloaterMemLeak* instance(); - static void onChangeLeakingSpeed(LLUICtrl* ctrl, void* userData); - static void onChangeMaxMemLeaking(LLUICtrl* ctrl, void* userData); - static void onClickStart(void* userData); - static void onClickStop(void* userData); - static void onClickRelease(void* userData); - static void onClickClose(void* userData); - - /// show off our menu - static void show(void*); + void onChangeLeakingSpeed(); + void onChangeMaxMemLeaking(); + void onClickStart(); + void onClickStop(); + void onClickRelease(); + void onClickClose(); public: - static LLFloaterMemLeak* getInstance() ; void idle() ; void stop() ; private: + + LLFloaterMemLeak(const LLSD& key); + virtual ~LLFloaterMemLeak(); void release() ; private: @@ -75,9 +69,6 @@ private: START } ; - // one instance on the inside - static LLFloaterMemLeak* sInstance; - static U32 sMemLeakingSpeed ; //bytes leaked per frame static U32 sMaxLeakedMem ; //maximum allowed leaked memory static U32 sTotalLeaked ; diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp index acfcfab445..ed7d2c71ea 100644 --- a/indra/newview/llfloaternamedesc.cpp +++ b/indra/newview/llfloaternamedesc.cpp @@ -41,6 +41,7 @@ #include "llbutton.h" #include "llviewerwindow.h" #include "llfocusmgr.h" +#include "llrootview.h" #include "llradiogroup.h" #include "lldbstrings.h" #include "lldir.h" @@ -68,14 +69,12 @@ const S32 PREF_BUTTON_HEIGHT = 16; //----------------------------------------------------------------------------- // LLFloaterNameDesc() //----------------------------------------------------------------------------- -LLFloaterNameDesc::LLFloaterNameDesc(const std::string& filename ) - : LLFloater(std::string("Name/Description Floater")) +LLFloaterNameDesc::LLFloaterNameDesc(const LLSD& filename ) + : LLFloater(filename), + mIsAudio(FALSE) { - mFilenameAndPath = filename; - mFilename = gDirUtilp->getBaseFileName(filename, false); - // SL-5521 Maintain capitalization of filename when making the inventory item. JC - //LLStringUtil::toLower(mFilename); - mIsAudio = FALSE; + mFilenameAndPath = filename.asString(); + mFilename = gDirUtilp->getBaseFileName(mFilenameAndPath, false); } //----------------------------------------------------------------------------- @@ -91,11 +90,6 @@ BOOL LLFloaterNameDesc::postBuild() LLStringUtil::stripNonprintable(asset_name); LLStringUtil::trim(asset_name); - std::string exten = gDirUtilp->getExtension(asset_name); - if (exten == "wav") - { - mIsAudio = TRUE; - } asset_name = gDirUtilp->getBaseFileName(asset_name, true); // no extsntion setTitle(mFilename); @@ -110,7 +104,7 @@ BOOL LLFloaterNameDesc::postBuild() r.setLeftTopAndSize( PREVIEW_HPAD, y, line_width, PREVIEW_LINE_HEIGHT ); - childSetCommitCallback("name_form", doCommit, this); + getChild("name_form")->setCommitCallback(boost::bind(&LLFloaterNameDesc::doCommit, this)); childSetValue("name_form", LLSD(asset_name)); LLLineEditor *NameEditor = getChild("name_form"); @@ -124,7 +118,7 @@ BOOL LLFloaterNameDesc::postBuild() y -= PREVIEW_LINE_HEIGHT; r.setLeftTopAndSize( PREVIEW_HPAD, y, line_width, PREVIEW_LINE_HEIGHT ); - childSetCommitCallback("description_form", doCommit, this); + getChild("description_form")->setCommitCallback(boost::bind(&LLFloaterNameDesc::doCommit, this)); LLLineEditor *DescEditor = getChild("description_form"); if (DescEditor) { @@ -135,12 +129,12 @@ BOOL LLFloaterNameDesc::postBuild() y -= llfloor(PREVIEW_LINE_HEIGHT * 1.2f); // Cancel button - childSetAction("cancel_btn", onBtnCancel, this); + getChild("cancel_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnCancel, this)); - // OK button - childSetAction("ok_btn", onBtnOK, this); + childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); + setDefaultBtn("ok_btn"); - + return TRUE; } @@ -160,45 +154,59 @@ void LLFloaterNameDesc::onCommit() { } -// static //----------------------------------------------------------------------------- // onCommit() //----------------------------------------------------------------------------- -void LLFloaterNameDesc::doCommit( class LLUICtrl *, void* userdata ) +void LLFloaterNameDesc::doCommit() { - LLFloaterNameDesc* self = (LLFloaterNameDesc*) userdata; - self->onCommit(); + onCommit(); } -// static //----------------------------------------------------------------------------- // onBtnOK() //----------------------------------------------------------------------------- -void LLFloaterNameDesc::onBtnOK( void* userdata ) +void LLFloaterNameDesc::onBtnOK( ) { - LLFloaterNameDesc *fp =(LLFloaterNameDesc *)userdata; - - fp->childDisable("ok_btn"); // don't allow inadvertent extra uploads + childDisable("ok_btn"); // don't allow inadvertent extra uploads LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); // kinda hack - assumes that unsubclassed LLFloaterNameDesc is only used for uploading chargeable assets, which it is right now (it's only used unsubclassed for the sound upload dialog, and THAT should be a subclass). void *nruserdata = NULL; std::string display_name = LLStringUtil::null; - upload_new_resource(fp->mFilenameAndPath, // file - fp->childGetValue("name_form").asString(), - fp->childGetValue("description_form").asString(), + upload_new_resource(mFilenameAndPath, // file + childGetValue("name_form").asString(), + childGetValue("description_form").asString(), 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE, LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(), display_name, callback, expected_upload_cost, nruserdata); - fp->close(false); + closeFloater(false); } -// static //----------------------------------------------------------------------------- // onBtnCancel() //----------------------------------------------------------------------------- -void LLFloaterNameDesc::onBtnCancel( void* userdata ) +void LLFloaterNameDesc::onBtnCancel() { - LLFloaterNameDesc *fp =(LLFloaterNameDesc *)userdata; - fp->close(false); + closeFloater(false); +} + + +//----------------------------------------------------------------------------- +// LLFloaterSoundPreview() +//----------------------------------------------------------------------------- + +LLFloaterSoundPreview::LLFloaterSoundPreview(const LLSD& filename ) + : LLFloaterNameDesc(filename) +{ + mIsAudio = TRUE; +} + +BOOL LLFloaterSoundPreview::postBuild() +{ + if (!LLFloaterNameDesc::postBuild()) + { + return FALSE; + } + getChild("ok_btn")->setCommitCallback(boost::bind(&LLFloaterNameDesc::onBtnOK, this)); + return TRUE; } diff --git a/indra/newview/llfloaternamedesc.h b/indra/newview/llfloaternamedesc.h index 6aa19eba40..2cc7f1101d 100644 --- a/indra/newview/llfloaternamedesc.h +++ b/indra/newview/llfloaternamedesc.h @@ -44,11 +44,14 @@ class LLRadioGroup; class LLFloaterNameDesc : public LLFloater { public: - LLFloaterNameDesc(const std::string& filename); + LLFloaterNameDesc(const LLSD& filename); virtual ~LLFloaterNameDesc(); virtual BOOL postBuild(); - - static void doCommit(class LLUICtrl *, void* userdata); + + void onBtnOK(); + void onBtnCancel(); + void doCommit(); + protected: virtual void onCommit(); @@ -57,9 +60,13 @@ protected: std::string mFilenameAndPath; std::string mFilename; - - static void onBtnOK(void*); - static void onBtnCancel(void*); }; +class LLFloaterSoundPreview : public LLFloaterNameDesc +{ +public: + LLFloaterSoundPreview(const LLSD& filename ); + virtual BOOL postBuild(); +}; + #endif // LL_LLFLOATERNAMEDESC_H diff --git a/indra/newview/llfloaternotificationsconsole.cpp b/indra/newview/llfloaternotificationsconsole.cpp index e6250063f7..f2dff55044 100644 --- a/indra/newview/llfloaternotificationsconsole.cpp +++ b/indra/newview/llfloaternotificationsconsole.cpp @@ -36,9 +36,9 @@ #include "lluictrlfactory.h" #include "llbutton.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" #include "llpanel.h" #include "llcombobox.h" -#include "llviewertexteditor.h" const S32 NOTIFICATION_PANEL_HEADER_HEIGHT = 20; const S32 HEADER_PADDING = 38; @@ -59,11 +59,12 @@ private: }; LLNotificationChannelPanel::LLNotificationChannelPanel(const std::string& channel_name) - : LLPanel(channel_name) + : LLPanel() { mChannelPtr = LLNotifications::instance().getChannel(channel_name); mChannelRejectsPtr = LLNotificationChannelPtr( - LLNotificationChannel::buildChannel(channel_name + "rejects", mChannelPtr->getParentChannelName(), !boost::bind(mChannelPtr->getFilter(), _1))); + LLNotificationChannel::buildChannel(channel_name + "rejects", mChannelPtr->getParentChannelName(), + !boost::bind(mChannelPtr->getFilter(), _1))); LLUICtrlFactory::instance().buildPanel(this, "panel_notifications_channel.xml"); } @@ -77,13 +78,11 @@ BOOL LLNotificationChannelPanel::postBuild() mChannelRejectsPtr->connectChanged(boost::bind(&LLNotificationChannelPanel::update, this, _1, false)); LLScrollListCtrl* scroll = getChild("notifications_list"); - scroll->setDoubleClickCallback(onClickNotification); - scroll->setCallbackUserData(this); - + scroll->setDoubleClickCallback(onClickNotification, this); + scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0)); scroll = getChild("notification_rejects_list"); - scroll->setDoubleClickCallback(onClickNotificationReject); - scroll->setCallbackUserData(this); - + scroll->setDoubleClickCallback(onClickNotificationReject, this); + scroll->setRect(LLRect( getRect().mLeft, getRect().mTop, getRect().mRight, 0)); return TRUE; } @@ -161,17 +160,13 @@ bool LLNotificationChannelPanel::update(const LLSD& payload, bool passed_filter) // LLFloaterNotificationConsole // LLFloaterNotificationConsole::LLFloaterNotificationConsole(const LLSD& key) +: LLFloater(key) { - LLUICtrlFactory::instance().buildFloater(this, "floater_notifications_console.xml"); -} + mCommitCallbackRegistrar.add("ClickAdd", boost::bind(&LLFloaterNotificationConsole::onClickAdd, this)); -void LLFloaterNotificationConsole::onClose(bool app_quitting) -{ - setVisible(FALSE); - //destroy(); + //LLUICtrlFactory::instance().buildFloater(this, "floater_notifications_console.xml"); } - BOOL LLFloaterNotificationConsole::postBuild() { // these are in the order of processing @@ -186,7 +181,7 @@ BOOL LLFloaterNotificationConsole::postBuild() addChannel("Notifications"); addChannel("NotificationTips"); - getChild("add_notification")->setClickedCallback(onClickAdd, this); +// getChild("add_notification")->setClickedCallback(onClickAdd, this); LLComboBox* notifications = getChild("notification_types"); LLNotifications::TemplateNames names = LLNotifications::instance().getTemplateNames(); @@ -216,12 +211,9 @@ void LLFloaterNotificationConsole::addChannel(const std::string& name, bool open void LLFloaterNotificationConsole::removeChannel(const std::string& name) { - LLPanel* panelp = getChild(name, TRUE, FALSE); - if (panelp) - { - getChildRef("notification_channels").removePanel(panelp); - delete panelp; - } + LLPanel* panelp = getChild(name); + getChildRef("notification_channels").removePanel(panelp); + delete panelp; updateResizeLimits(); } @@ -229,15 +221,15 @@ void LLFloaterNotificationConsole::removeChannel(const std::string& name) //static void LLFloaterNotificationConsole::updateResizeLimits() { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + LLLayoutStack& stack = getChildRef("notification_channels"); - setResizeLimits(getMinWidth(), LLFLOATER_HEADER_SIZE + HEADER_PADDING + ((NOTIFICATION_PANEL_HEADER_HEIGHT + 3) * stack.getNumPanels())); + setResizeLimits(getMinWidth(), floater_header_size + HEADER_PADDING + ((NOTIFICATION_PANEL_HEADER_HEIGHT + 3) * stack.getNumPanels())); } -void LLFloaterNotificationConsole::onClickAdd(void* user_data) +void LLFloaterNotificationConsole::onClickAdd() { - LLFloaterNotificationConsole* floater = (LLFloaterNotificationConsole*)user_data; - - std::string message_name = floater->getChild("notification_types")->getValue().asString(); + std::string message_name = getChild("notification_types")->getValue().asString(); if (!message_name.empty()) { LLNotifications::instance().add(message_name, LLSD()); @@ -247,15 +239,17 @@ void LLFloaterNotificationConsole::onClickAdd(void* user_data) //=============== LLFloaterNotification ================ -LLFloaterNotification::LLFloaterNotification(LLNotification* note) : mNote(note) +LLFloaterNotification::LLFloaterNotification(LLNotification* note) +: LLFloater(LLSD()), + mNote(note) { - LLUICtrlFactory::instance().buildFloater(this, "floater_notification.xml"); + LLUICtrlFactory::instance().buildFloater(this, "floater_notification.xml", NULL); } BOOL LLFloaterNotification::postBuild() { setTitle(mNote->getName()); - getChild("payload")->setText(mNote->getMessage()); + getChild("payload")->setValue(mNote->getMessage()); LLComboBox* responses_combo = getChild("response"); LLCtrlListInterface* response_list = responses_combo->getListInterface(); @@ -265,8 +259,7 @@ BOOL LLFloaterNotification::postBuild() return TRUE; } - responses_combo->setCommitCallback(onCommitResponse); - responses_combo->setCallbackUserData(this); + responses_combo->setCommitCallback(onCommitResponse, this); LLSD form_sd = form->asLLSD(); diff --git a/indra/newview/llfloaternotificationsconsole.h b/indra/newview/llfloaternotificationsconsole.h index 1a436b8bfe..7349ff1d8f 100644 --- a/indra/newview/llfloaternotificationsconsole.h +++ b/indra/newview/llfloaternotificationsconsole.h @@ -34,18 +34,18 @@ #define LL_LLFLOATER_NOTIFICATIONS_CONSOLE_H #include "llfloater.h" +#include "lllayoutstack.h" #include "llnotifications.h" class LLFloaterNotificationConsole : - public LLFloater, - public LLFloaterSingleton + public LLFloater { + friend class LLFloaterReg; + public: - LLFloaterNotificationConsole(const LLSD& key); // LLPanel BOOL postBuild(); - void onClose(bool app_quitting); void addChannel(const std::string& type, bool open = false); void updateResizeLimits(LLLayoutStack &stack); @@ -54,7 +54,8 @@ public: void updateResizeLimits(); private: - static void onClickAdd(void* user_data); + LLFloaterNotificationConsole(const LLSD& key); + void onClickAdd(); }; @@ -69,7 +70,6 @@ public: // LLPanel BOOL postBuild(); void respond(); - void onClose(bool app_quitting) { setVisible(FALSE); } private: static void onCommitResponse(LLUICtrl* ctrl, void* data) { ((LLFloaterNotification*)data)->respond(); } diff --git a/indra/newview/llfloateropenobject.cpp b/indra/newview/llfloateropenobject.cpp index f4984df6d9..aa82dc34b7 100644 --- a/indra/newview/llfloateropenobject.cpp +++ b/indra/newview/llfloateropenobject.cpp @@ -43,11 +43,12 @@ #include "llbutton.h" #include "lltextbox.h" -#include "llagent.h" // for agent id #include "llalertdialog.h" -#include "llinventoryview.h" +#include "llinventorybridge.h" +#include "llfloaterinventory.h" #include "llinventorymodel.h" #include "llpanelinventory.h" +#include "llfloaterreg.h" #include "llselectmgr.h" #include "lluiconstants.h" #include "llviewerobject.h" @@ -55,27 +56,44 @@ #include "llviewerwindow.h" -LLFloaterOpenObject* LLFloaterOpenObject::sInstance = NULL; - -LLFloaterOpenObject::LLFloaterOpenObject() -: LLFloater(std::string("object_contents")), +LLFloaterOpenObject::LLFloaterOpenObject(const LLSD& key) +: LLFloater(key), mPanelInventory(NULL), mDirty(TRUE) { - LLCallbackMap::map_t factory_map; - factory_map["object_contents"] = LLCallbackMap(createPanelInventory, this); - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_openobject.xml",&factory_map); - - childSetAction("copy_to_inventory_button", onClickMoveToInventory, this); - childSetAction("copy_and_wear_button", onClickMoveAndWear, this); - childSetTextArg("object_name", "[DESC]", std::string("Object") ); // *Note: probably do not want to translate this +// LLUICtrlFactory::getInstance()->buildFloater(this,"floater_openobject.xml"); + mCommitCallbackRegistrar.add("OpenObject.MoveToInventory", boost::bind(&LLFloaterOpenObject::onClickMoveToInventory, this)); + mCommitCallbackRegistrar.add("OpenObject.MoveAndWear", boost::bind(&LLFloaterOpenObject::onClickMoveAndWear, this)); } LLFloaterOpenObject::~LLFloaterOpenObject() { - sInstance = NULL; +// sInstance = NULL; +} +// virtual +BOOL LLFloaterOpenObject::postBuild() +{ + childSetTextArg("object_name", "[DESC]", std::string("Object") ); // *Note: probably do not want to translate this + mPanelInventory = getChild("object_contents"); + return TRUE; } +void LLFloaterOpenObject::onOpen(const LLSD& key) +{ + LLObjectSelectionHandle object_selection = LLSelectMgr::getInstance()->getSelection(); + if (object_selection->getRootObjectCount() != 1) + { + LLNotifications::instance().add("UnableToViewContentsMoreThanOne"); + closeFloater(); + return; + } + if(!(object_selection->getPrimaryObject())) + { + closeFloater(); + return; + } + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); +} void LLFloaterOpenObject::refresh() { mPanelInventory->refresh(); @@ -96,7 +114,6 @@ void LLFloaterOpenObject::refresh() } childSetTextArg("object_name", "[DESC]", name); - childSetEnabled("copy_to_inventory_button", enabled); childSetEnabled("copy_and_wear_button", enabled); @@ -112,34 +129,11 @@ void LLFloaterOpenObject::draw() LLFloater::draw(); } -// static void LLFloaterOpenObject::dirty() { - if (sInstance) sInstance->mDirty = TRUE; + mDirty = TRUE; } -// static -void LLFloaterOpenObject::show() -{ - LLObjectSelectionHandle object_selection = LLSelectMgr::getInstance()->getSelection(); - if (object_selection->getRootObjectCount() != 1) - { - LLNotifications::instance().add("UnableToViewContentsMoreThanOne"); - return; - } - - // Create a new instance only if needed - if (!sInstance) - { - sInstance = new LLFloaterOpenObject(); - sInstance->center(); - } - - sInstance->open(); /* Flawfinder: ignore */ - sInstance->setFocus(TRUE); - - sInstance->mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); -} void LLFloaterOpenObject::moveToInventory(bool wear) @@ -167,7 +161,7 @@ void LLFloaterOpenObject::moveToInventory(bool wear) } else { - parent_category_id = gAgent.getInventoryRootID(); + parent_category_id = gInventory.getRootFolderID(); } LLUUID category_id = gInventory.createNewCategory(parent_category_id, LLAssetType::AT_NONE, @@ -198,8 +192,8 @@ void LLFloaterOpenObject::callbackMoveInventory(S32 result, void* data) if (result == 0) { - LLInventoryView::showAgentInventory(); - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLFloaterInventory::showAgentInventory(); + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); if (view) { view->getPanel()->setSelection(cat->mCatID, TAKE_FOCUS_NO); @@ -209,27 +203,15 @@ void LLFloaterOpenObject::callbackMoveInventory(S32 result, void* data) delete cat; } - -// static -void LLFloaterOpenObject::onClickMoveToInventory(void* data) +void LLFloaterOpenObject::onClickMoveToInventory() { - LLFloaterOpenObject* self = (LLFloaterOpenObject*)data; - self->moveToInventory(false); - self->close(); + moveToInventory(false); + closeFloater(); } -// static -void LLFloaterOpenObject::onClickMoveAndWear(void* data) +void LLFloaterOpenObject::onClickMoveAndWear() { - LLFloaterOpenObject* self = (LLFloaterOpenObject*)data; - self->moveToInventory(true); - self->close(); + moveToInventory(true); + closeFloater(); } -//static -void* LLFloaterOpenObject::createPanelInventory(void* data) -{ - LLFloaterOpenObject* floater = (LLFloaterOpenObject*)data; - floater->mPanelInventory = new LLPanelInventory(std::string("Object Contents"), LLRect()); - return floater->mPanelInventory; -} diff --git a/indra/newview/llfloateropenobject.h b/indra/newview/llfloateropenobject.h index 27653a5c99..0df3780ac4 100644 --- a/indra/newview/llfloateropenobject.h +++ b/indra/newview/llfloateropenobject.h @@ -46,9 +46,10 @@ class LLPanelInventory; class LLFloaterOpenObject : public LLFloater { + friend class LLFloaterReg; public: - static void show(); - static void dirty(); + + void dirty(); struct LLCatAndWear { @@ -57,21 +58,25 @@ public: }; protected: - LLFloaterOpenObject(); - ~LLFloaterOpenObject(); + /*virtual*/ BOOL postBuild(); void refresh(); void draw(); + virtual void onOpen(const LLSD& key); +// virtual void onClose(); void moveToInventory(bool wear); - static void onClickMoveToInventory(void* data); - static void onClickMoveAndWear(void* data); + void onClickMoveToInventory(); + void onClickMoveAndWear(); static void callbackMoveInventory(S32 result, void* data); - static void* createPanelInventory(void* data); +private: + + LLFloaterOpenObject(const LLSD& key); + ~LLFloaterOpenObject(); + protected: - static LLFloaterOpenObject* sInstance; LLPanelInventory* mPanelInventory; LLSafeHandle mObjectSelection; diff --git a/indra/newview/llfloaterparcel.cpp b/indra/newview/llfloaterparcel.cpp index 4213150553..44270683a0 100644 --- a/indra/newview/llfloaterparcel.cpp +++ b/indra/newview/llfloaterparcel.cpp @@ -35,6 +35,8 @@ #include "llfloaterparcel.h" +#include "llfloaterreg.h" + // viewer project includes #include "llcommandhandler.h" #include "llpanelplace.h" @@ -47,15 +49,13 @@ // Globals //----------------------------------------------------------------------------- -LLMap< const LLUUID, LLFloaterParcelInfo* > gPlaceInfoInstances; - class LLParcelHandler : public LLCommandHandler { public: // requires trusted browser to trigger LLParcelHandler() : LLCommandHandler("parcel", true) { } bool handle(const LLSD& params, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { if (params.size() < 2) { @@ -68,8 +68,11 @@ public: } if (params[1].asString() == "about") { - LLFloaterParcelInfo::show(parcel_id); - return true; + if (parcel_id.notNull()) + { + LLFloaterReg::showInstance("parcel_info", LLSD(parcel_id)); + return true; + } } return false; } @@ -82,7 +85,7 @@ LLParcelHandler gParcelHandler; //---------------------------------------------------------------------------- -void* LLFloaterParcelInfo::createPanelPlace(void* data) +void* LLFloaterParcelInfo::createPanelPlace(void* data) { LLFloaterParcelInfo* self = (LLFloaterParcelInfo*)data; self->mPanelParcelp = new LLPanelPlace(); // allow edit self @@ -93,54 +96,29 @@ void* LLFloaterParcelInfo::createPanelPlace(void* data) //---------------------------------------------------------------------------- -LLFloaterParcelInfo::LLFloaterParcelInfo(const std::string& name, const LLUUID &parcel_id) -: LLFloater(name), - mParcelID( parcel_id ) +LLFloaterParcelInfo::LLFloaterParcelInfo(const LLSD& parcel_id) +: LLFloater(parcel_id), + mParcelID( parcel_id.asUUID() ), + mPanelParcelp(NULL) { mFactoryMap["place_details_panel"] = LLCallbackMap(LLFloaterParcelInfo::createPanelPlace, this); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_url.xml", &getFactoryMap()); - gPlaceInfoInstances.addData(parcel_id, this); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_url.xml"); } // virtual LLFloaterParcelInfo::~LLFloaterParcelInfo() { - // child views automatically deleted - gPlaceInfoInstances.removeData(mParcelID); } -void LLFloaterParcelInfo::displayParcelInfo(const LLUUID& parcel_id) +BOOL LLFloaterParcelInfo::postBuild() { - mPanelParcelp->setParcelID(parcel_id); -} - -// static -LLFloaterParcelInfo* LLFloaterParcelInfo::show(const LLUUID &parcel_id) -{ - if (parcel_id.isNull()) + if (mPanelParcelp) { - return NULL; + mPanelParcelp->setParcelID(mParcelID); } - - LLFloaterParcelInfo *floater; - if (gPlaceInfoInstances.checkData(parcel_id)) - { - // ...bring that window to front - floater = gPlaceInfoInstances.getData(parcel_id); - floater->open(); /*Flawfinder: ignore*/ - floater->setFrontmost(true); - } - else - { - floater = new LLFloaterParcelInfo("parcelinfo", parcel_id ); - floater->center(); - floater->open(); /*Flawfinder: ignore*/ - floater->displayParcelInfo(parcel_id); - floater->setFrontmost(true); - } - - return floater; + center(); + return LLFloater::postBuild(); } diff --git a/indra/newview/llfloaterparcel.h b/indra/newview/llfloaterparcel.h index 4d698d64ae..386acb3fd5 100644 --- a/indra/newview/llfloaterparcel.h +++ b/indra/newview/llfloaterparcel.h @@ -43,13 +43,13 @@ class LLFloaterParcelInfo public: static void* createPanelPlace(void* data); - LLFloaterParcelInfo(const std::string& name, const LLUUID &parcel_id ); + LLFloaterParcelInfo( const LLSD& parcel_id ); /*virtual*/ ~LLFloaterParcelInfo(); - + + /*virtual*/ BOOL postBuild(); + void displayParcelInfo(const LLUUID& parcel_id); - static LLFloaterParcelInfo* show(const LLUUID& parcel_id); - private: LLUUID mParcelID; // for which parcel is this window? LLPanelPlace* mPanelParcelp; diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index 52fba0aa20..17bb8221ad 100644 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -42,50 +42,45 @@ LLFloaterPerms::LLFloaterPerms(const LLSD& seed) +: LLFloater(seed) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_perm_prefs.xml"); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_perm_prefs.xml"); + mCommitCallbackRegistrar.add("Perms.Copy", boost::bind(&LLFloaterPerms::onCommitCopy, this)); + mCommitCallbackRegistrar.add("Perms.OK", boost::bind(&LLFloaterPerms::onClickOK, this)); + mCommitCallbackRegistrar.add("Perms.Cancel", boost::bind(&LLFloaterPerms::onClickCancel, this)); + } BOOL LLFloaterPerms::postBuild() { - childSetEnabled("next_owner_transfer", gSavedSettings.getBOOL("NextOwnerCopy")); - childSetAction("help", onClickHelp, this); - childSetAction("ok", onClickOK, this); - childSetAction("cancel", onClickCancel, this); - childSetCommitCallback("next_owner_copy", &onCommitCopy, this); - + mCloseSignal.connect(boost::bind(&LLFloaterPerms::cancel, this)); + refresh(); return TRUE; } -//static -void LLFloaterPerms::onClickOK(void* data) +void LLFloaterPerms::onClickOK() { - LLFloaterPerms* self = static_cast(data); - self->ok(); - self->close(); + ok(); + closeFloater(); } -//static -void LLFloaterPerms::onClickCancel(void* data) +void LLFloaterPerms::onClickCancel() { - LLFloaterPerms* self = static_cast(data); - self->cancel(); - self->close(); + cancel(); + closeFloater(); } -//static -void LLFloaterPerms::onCommitCopy(LLUICtrl* ctrl, void* data) +void LLFloaterPerms::onCommitCopy() { - LLFloaterPerms* self = static_cast(data); // Implements fair use BOOL copyable = gSavedSettings.getBOOL("NextOwnerCopy"); if(!copyable) { gSavedSettings.setBOOL("NextOwnerTransfer", TRUE); } - LLCheckBoxCtrl* xfer = self->getChild("next_owner_transfer"); + LLCheckBoxCtrl* xfer = getChild("next_owner_transfer"); xfer->setEnabled(copyable); } @@ -112,14 +107,6 @@ void LLFloaterPerms::refresh() mNextOwnerTransfer = gSavedSettings.getBOOL("NextOwnerTransfer"); } -void LLFloaterPerms::onClose(bool app_quitting) -{ - // Cancel any unsaved changes before closing. - // Note: when closed due to the OK button this amounts to a no-op. - cancel(); - LLFloater::onClose(app_quitting); -} - //static U32 LLFloaterPerms::getGroupPerms(std::string prefix) { @@ -151,9 +138,3 @@ U32 LLFloaterPerms::getNextOwnerPerms(std::string prefix) return flags; } - -//static -void LLFloaterPerms::onClickHelp(void* data) -{ - LLNotifications::instance().add("ClickUploadHelpPermissions"); -} diff --git a/indra/newview/llfloaterperms.h b/indra/newview/llfloaterperms.h index 805039efe4..2426f43ca7 100644 --- a/indra/newview/llfloaterperms.h +++ b/indra/newview/llfloaterperms.h @@ -36,18 +36,17 @@ #include "llfloater.h" -class LLFloaterPerms : public LLFloater, public LLFloaterSingleton +class LLFloaterPerms : public LLFloater { - friend class LLUISingleton >; + friend class LLFloaterReg; public: - /*virtual*/ void onClose(bool app_quitting = false); /*virtual*/ BOOL postBuild(); void ok(); void cancel(); - static void onClickOK(void*); - static void onClickCancel(void*); - static void onCommitCopy(LLUICtrl* ctrl, void* data); + void onClickOK(); + void onClickCancel(); + void onCommitCopy(); // Convenience methods to get current permission preference bitfields from saved settings: static U32 getEveryonePerms(std::string prefix=""); // prefix + "EveryoneCopy" static U32 getGroupPerms(std::string prefix=""); // prefix + "ShareWithGroup" @@ -57,9 +56,6 @@ private: LLFloaterPerms(const LLSD& seed); void refresh(); - /// callback for the menus help button - static void onClickHelp(void* data); - BOOL // cached values only for implementing cancel. mShareWithGroup, mEveryoneCopy, diff --git a/indra/newview/llfloaterpostcard.cpp b/indra/newview/llfloaterpostcard.cpp index b0ab0f9625..a27070de39 100644 --- a/indra/newview/llfloaterpostcard.cpp +++ b/indra/newview/llfloaterpostcard.cpp @@ -43,8 +43,9 @@ #include "llagent.h" #include "llui.h" #include "lllineeditor.h" -#include "llviewertexteditor.h" #include "llbutton.h" +#include "lltexteditor.h" +#include "llfloaterreg.h" #include "llviewercontrol.h" #include "llviewernetwork.h" #include "lluictrlfactory.h" @@ -61,8 +62,9 @@ #include "llimagej2c.h" #include "llvfile.h" #include "llvfs.h" - +#include "llviewertexture.h" #include "llassetuploadresponders.h" +#include "llagentui.h" #include //boost.regex lib @@ -70,89 +72,59 @@ /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -//static -LLFloaterPostcard::instance_list_t LLFloaterPostcard::sInstances; - ///---------------------------------------------------------------------------- /// Class LLFloaterPostcard ///---------------------------------------------------------------------------- -LLFloaterPostcard::LLFloaterPostcard(LLImageJPEG* jpeg, LLImageGL *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global) -: LLFloater(std::string("Postcard Floater")), - mJPEGImage(jpeg), - mViewerImage(img), - mImageScale(img_scale), - mPosTakenGlobal(pos_taken_global), +LLFloaterPostcard::LLFloaterPostcard(const LLSD& key) +: LLFloater(key), + mJPEGImage(NULL), + mViewerImage(NULL), mHasFirstMsgFocus(false) { - init(); -} - -void LLFloaterPostcard::init() -{ - // pick up the user's up-to-date email address - if(!gAgent.getID().isNull()) - { - // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } - - sInstances.insert(this); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_postcard.xml"); } // Destroys the object LLFloaterPostcard::~LLFloaterPostcard() { - sInstances.erase(this); mJPEGImage = NULL; // deletes image } BOOL LLFloaterPostcard::postBuild() { + // pick up the user's up-to-date email address + gAgent.sendAgentUserInfoRequest(); + childSetAction("cancel_btn", onClickCancel, this); childSetAction("send_btn", onClickSend, this); childDisable("from_form"); std::string name_string; - gAgent.buildFullname(name_string); + LLAgentUI::buildFullname(name_string); childSetValue("name_form", LLSD(name_string)); - LLTextEditor* MsgField = getChild("msg_form"); - if (MsgField) - { - MsgField->setWordWrap(TRUE); - - // For the first time a user focusess to .the msg box, all text will be selected. - MsgField->setFocusChangedCallback(onMsgFormFocusRecieved, this); - } + // For the first time a user focusess to .the msg box, all text will be selected. + getChild("msg_form")->setFocusChangedCallback(onMsgFormFocusRecieved, this); childSetFocus("to_form", TRUE); return TRUE; } - - // static -LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLImageGL *img, const LLVector2 &image_scale, const LLVector3d& pos_taken_global) +LLFloaterPostcard* LLFloaterPostcard::showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2 &image_scale, const LLVector3d& pos_taken_global) { // Take the images from the caller // It's now our job to clean them up - LLFloaterPostcard *instance = new LLFloaterPostcard(jpeg, img, image_scale, pos_taken_global); - - LLUICtrlFactory::getInstance()->buildFloater(instance, "floater_postcard.xml"); - - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - instance->setOrigin(left, top - instance->getRect().getHeight()); + LLFloaterPostcard* instance = LLFloaterReg::showTypedInstance("postcard", LLSD(img->getID())); + + instance->mJPEGImage = jpeg; + instance->mViewerImage = img; + instance->mImageScale = image_scale; + instance->mPosTakenGlobal = pos_taken_global; - instance->open(); /*Flawfinder: ignore*/ - return instance; } @@ -198,7 +170,7 @@ void LLFloaterPostcard::draw() rect.mBottom, rect.getWidth(), rect.getHeight(), - mViewerImage, + mViewerImage.get(), LLColor4::white); } glMatrixMode(GL_TEXTURE); @@ -215,7 +187,7 @@ void LLFloaterPostcard::onClickCancel(void* data) { LLFloaterPostcard *self = (LLFloaterPostcard *)data; - self->close(false); + self->closeFloater(false); } } @@ -313,16 +285,17 @@ void LLFloaterPostcard::uploadCallback(const LLUUID& asset_id, void *user_data, gAgent.sendReliableMessage(); } - self->close(); + self->closeFloater(); } // static void LLFloaterPostcard::updateUserInfo(const std::string& email) { - for (instance_list_t::iterator iter = sInstances.begin(); - iter != sInstances.end(); ++iter) + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); + iter != inst_list.end(); ++iter) { - LLFloaterPostcard *instance = *iter; + LLFloater* instance = *iter; const std::string& text = instance->childGetValue("from_form").asString(); if (text.empty()) { diff --git a/indra/newview/llfloaterpostcard.h b/indra/newview/llfloaterpostcard.h index 087649f159..49cce53106 100644 --- a/indra/newview/llfloaterpostcard.h +++ b/indra/newview/llfloaterpostcard.h @@ -36,25 +36,25 @@ #include "llfloater.h" #include "llcheckboxctrl.h" -#include "llmemory.h" -#include "llimagegl.h" +#include "llpointer.h" class LLTextEditor; class LLLineEditor; class LLButton; +class LLViewerTexture; +class LLImageJPEG; class LLFloaterPostcard : public LLFloater { public: - LLFloaterPostcard(LLImageJPEG* jpeg, LLImageGL *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global); + LLFloaterPostcard(const LLSD& key); virtual ~LLFloaterPostcard(); - virtual void init(); virtual BOOL postBuild(); virtual void draw(); - static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLImageGL *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global); + static LLFloaterPostcard* showFromSnapshot(LLImageJPEG *jpeg, LLViewerTexture *img, const LLVector2& img_scale, const LLVector3d& pos_taken_global); static void onClickCancel(void* data); static void onClickSend(void* data); @@ -73,15 +73,12 @@ public: protected: LLPointer mJPEGImage; - LLPointer mViewerImage; + LLPointer mViewerImage; LLTransactionID mTransactionID; LLAssetID mAssetID; LLVector2 mImageScale; LLVector3d mPosTakenGlobal; boolean mHasFirstMsgFocus; - - typedef std::set instance_list_t; - static instance_list_t sInstances; }; diff --git a/indra/newview/llfloaterpostprocess.cpp b/indra/newview/llfloaterpostprocess.cpp index de9b598b1e..2ab54d6e46 100644 --- a/indra/newview/llfloaterpostprocess.cpp +++ b/indra/newview/llfloaterpostprocess.cpp @@ -36,6 +36,7 @@ #include "llsliderctrl.h" #include "llcheckboxctrl.h" +#include "llcombobox.h" #include "lluictrlfactory.h" #include "llviewerdisplay.h" #include "llpostprocess.h" @@ -44,13 +45,19 @@ #include "llviewerwindow.h" -LLFloaterPostProcess* LLFloaterPostProcess::sPostProcess = NULL; - - -LLFloaterPostProcess::LLFloaterPostProcess() : LLFloater(std::string("Post-Process Floater")) +LLFloaterPostProcess::LLFloaterPostProcess(const LLSD& key) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_post_process.xml"); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_post_process.xml"); +} +LLFloaterPostProcess::~LLFloaterPostProcess() +{ + + +} +BOOL LLFloaterPostProcess::postBuild() +{ /// Color Filter Callbacks childSetCommitCallback("ColorFilterToggle", &LLFloaterPostProcess::onBoolToggle, (char*)"enable_color_filter"); //childSetCommitCallback("ColorFilterGamma", &LLFloaterPostProcess::onFloatControlMoved, &(gPostProcess->tweaks.gamma())); @@ -77,32 +84,14 @@ LLFloaterPostProcess::LLFloaterPostProcess() : LLFloater(std::string("Post-Proce // Effect loading and saving. LLComboBox* comboBox = getChild("PPEffectsCombo"); - childSetAction("PPLoadEffect", &LLFloaterPostProcess::onLoadEffect, comboBox); - comboBox->setCommitCallback(onChangeEffectName); + getChild("PPLoadEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onLoadEffect, this, comboBox)); + comboBox->setCommitCallback(boost::bind(&LLFloaterPostProcess::onChangeEffectName, this, _1)); LLLineEditor* editBox = getChild("PPEffectNameEditor"); - childSetAction("PPSaveEffect", &LLFloaterPostProcess::onSaveEffect, editBox); + getChild("PPSaveEffect")->setCommitCallback(boost::bind(&LLFloaterPostProcess::onSaveEffect, this, editBox)); syncMenu(); - -} - -LLFloaterPostProcess::~LLFloaterPostProcess() -{ - - -} - -LLFloaterPostProcess* LLFloaterPostProcess::instance() -{ - // if we don't have our singleton instance, create it - if (!sPostProcess) - { - sPostProcess = new LLFloaterPostProcess(); - sPostProcess->open(); - sPostProcess->setFocus(TRUE); - } - return sPostProcess; + return TRUE; } // Bool Toggle @@ -155,44 +144,39 @@ void LLFloaterPostProcess::onColorControlIMoved(LLUICtrl* ctrl, void* userData) gPostProcess->tweaks[floatVariableName][3] = sldrCtrl->getValue(); } -void LLFloaterPostProcess::onLoadEffect(void* userData) +void LLFloaterPostProcess::onLoadEffect(LLComboBox* comboBox) { - LLComboBox* comboBox = static_cast(userData); - LLSD::String effectName(comboBox->getSelectedValue().asString()); gPostProcess->setSelectedEffect(effectName); - sPostProcess->syncMenu(); + syncMenu(); } -void LLFloaterPostProcess::onSaveEffect(void* userData) +void LLFloaterPostProcess::onSaveEffect(LLLineEditor* editBox) { - LLLineEditor* editBox = static_cast(userData); - std::string effectName(editBox->getValue().asString()); if (gPostProcess->mAllEffects.has(effectName)) { LLSD payload; payload["effect_name"] = effectName; - LLNotifications::instance().add("PPSaveEffectAlert", LLSD(), payload, &LLFloaterPostProcess::saveAlertCallback); + LLNotifications::instance().add("PPSaveEffectAlert", LLSD(), payload, boost::bind(&LLFloaterPostProcess::saveAlertCallback, this, _1, _2)); } else { gPostProcess->saveEffect(effectName); - sPostProcess->syncMenu(); + syncMenu(); } } -void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl, void * userData) +void LLFloaterPostProcess::onChangeEffectName(LLUICtrl* ctrl) { // get the combo box and name - LLComboBox * comboBox = static_cast(ctrl); - LLLineEditor* editBox = sPostProcess->getChild("PPEffectNameEditor"); + LLLineEditor* editBox = getChild("PPEffectNameEditor"); // set the parameter's new name - editBox->setValue(comboBox->getSelectedValue()); + editBox->setValue(ctrl->getValue()); } bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLSD& response) @@ -204,30 +188,11 @@ bool LLFloaterPostProcess::saveAlertCallback(const LLSD& notification, const LLS { gPostProcess->saveEffect(notification["payload"]["effect_name"].asString()); - sPostProcess->syncMenu(); + syncMenu(); } return false; } -void LLFloaterPostProcess::show() -{ - // get the instance, make sure the values are synced - // and open the menu - LLFloaterPostProcess* postProcess = instance(); - postProcess->syncMenu(); - postProcess->open(); -} - -// virtual -void LLFloaterPostProcess::onClose(bool app_quitting) -{ - // just set visibility to false, don't get fancy yet - if (sPostProcess) - { - sPostProcess->setVisible(FALSE); - } -} - void LLFloaterPostProcess::syncMenu() { // add the combo boxe contents diff --git a/indra/newview/llfloaterpostprocess.h b/indra/newview/llfloaterpostprocess.h index 08a3618c2b..c789adee00 100644 --- a/indra/newview/llfloaterpostprocess.h +++ b/indra/newview/llfloaterpostprocess.h @@ -36,6 +36,8 @@ #include "llfloater.h" class LLButton; +class LLComboBox; +class LLLineEditor; class LLSliderCtrl; class LLTabContainer; class LLPanelPermissions; @@ -51,11 +53,9 @@ class LLFloaterPostProcess : public LLFloater { public: - LLFloaterPostProcess(); + LLFloaterPostProcess(const LLSD& key); virtual ~LLFloaterPostProcess(); - - /// one and one instance only - static LLFloaterPostProcess* instance(); + /*virtual*/ BOOL postBuild(); /// post process callbacks static void onBoolToggle(LLUICtrl* ctrl, void* userData); @@ -64,18 +64,12 @@ public: static void onColorControlGMoved(LLUICtrl* ctrl, void* userData); static void onColorControlBMoved(LLUICtrl* ctrl, void* userData); static void onColorControlIMoved(LLUICtrl* ctrl, void* userData); - static void onLoadEffect(void* userData); - static void onSaveEffect(void* userData); - static void onChangeEffectName(LLUICtrl* ctrl, void * userData); + void onLoadEffect(LLComboBox* comboBox); + void onSaveEffect(LLLineEditor* editBox); + void onChangeEffectName(LLUICtrl* ctrl); /// prompts a user when overwriting an effect - static bool saveAlertCallback(const LLSD& notification, const LLSD& response); - - /// show off our menu - static void show(); - - /// stuff to do on exit - virtual void onClose(bool app_quitting); + bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// sync up sliders void syncMenu(); @@ -84,8 +78,6 @@ public: void refresh(); */ public: - - static LLFloaterPostProcess* sPostProcess; }; #endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 17a59ccb77..c47c7b073c 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -40,411 +40,526 @@ #include "llfloaterpreference.h" -#include "llbutton.h" -#include "llcheckboxctrl.h" -#include "lldir.h" -#include "llfocusmgr.h" -#include "llscrollbar.h" -#include "llspinctrl.h" #include "message.h" -#include "llcommandhandler.h" -#include "llfloaterabout.h" -#include "llfloaterpreference.h" -#include "llpanelnetwork.h" -#include "llpanelaudioprefs.h" -#include "llpaneldisplay.h" -#include "llpaneldebug.h" -#include "llpanelgeneral.h" -#include "llpanelinput.h" -#include "llpanellogin.h" -#include "llpanelLCD.h" -#include "llpanelmsgs.h" -#include "llpanelweb.h" -#include "llpanelskins.h" -#include "llprefschat.h" -#include "llprefsvoice.h" -#include "llprefsim.h" -#include "llresizehandle.h" -#include "llresmgr.h" -#include "llassetstorage.h" #include "llagent.h" -#include "llviewercontrol.h" -#include "llviewernetwork.h" -#include "lluictrlfactory.h" -#include "llviewerwindow.h" -#include "llkeyboard.h" -#include "llscrollcontainer.h" +#include "llavatarconstants.h" +#include "llcheckboxctrl.h" +#include "llcolorswatch.h" +#include "llcombobox.h" +#include "llcommandhandler.h" +#include "lldirpicker.h" +#include "llfeaturemanager.h" +#include "llfocusmgr.h" +#include "llfirstuse.h" +#include "llfloaterreg.h" +#include "llfloaterabout.h" #include "llfloaterhardwaresettings.h" +#include "llfloatervoicedevicesettings.h" +#include "llkeyboard.h" +#include "llmodaldialog.h" +#include "llnavigationbar.h" +#include "llpanellogin.h" +#include "llradiogroup.h" +#include "llsky.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llsliderctrl.h" +#include "lltabcontainer.h" +#include "lltrans.h" +#include "llviewercontrol.h" +#include "llviewercamera.h" +#include "llviewerwindow.h" +#include "llviewermessage.h" +#include "llviewershadermgr.h" +#include "llvotree.h" +#include "llvosky.h" -const S32 PREF_BORDER = 4; -const S32 PREF_PAD = 5; -const S32 PREF_BUTTON_WIDTH = 70; -const S32 PREF_CATEGORY_WIDTH = 150; +// linden library includes +#include "llerror.h" +#include "llfontgl.h" +#include "llrect.h" +#include "llstring.h" -const S32 PREF_FLOATER_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 96; +// project includes -LLFloaterPreference* LLFloaterPreference::sInstance = NULL; +#include "llbutton.h" +#include "llflexibleobject.h" +#include "lllineeditor.h" +#include "llresmgr.h" +#include "llspinctrl.h" +#include "llstartup.h" +#include "lltextbox.h" +#include "llui.h" +#include "llviewerobjectlist.h" +#include "llvoavatar.h" +#include "llvovolume.h" +#include "llwindow.h" +#include "llworld.h" +#include "pipeline.h" +#include "lluictrlfactory.h" +#include "llboost.h" +#include "llviewermedia.h" +#include "llpluginclassmedia.h" -class LLPreferencesHandler : public LLCommandHandler +//RN temporary includes for resolution switching +#include "llglheaders.h" +const F32 MAX_USER_FAR_CLIP = 512.f; +const F32 MIN_USER_FAR_CLIP = 64.f; + +const S32 ASPECT_RATIO_STR_LEN = 100; + +class LLVoiceSetKeyDialog : public LLModalDialog { public: - // requires trusted browser - LLPreferencesHandler() : LLCommandHandler("preferences", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) - { - LLFloaterPreference::show(NULL); - return true; - } + LLVoiceSetKeyDialog(const LLSD& key); + ~LLVoiceSetKeyDialog(); + + /*virtual*/ BOOL postBuild(); + + void setParent(LLFloaterPreference* parent) { mParent = parent; } + + BOOL handleKeyHere(KEY key, MASK mask); + static void onCancel(void* user_data); + +private: + LLFloaterPreference* mParent; }; -LLPreferencesHandler gPreferencesHandler; - - -// Must be done at run time, not compile time. JC -S32 pref_min_width() +LLVoiceSetKeyDialog::LLVoiceSetKeyDialog(const LLSD& key) + : LLModalDialog(key), + mParent(NULL) { - return - 2 * PREF_BORDER + - 2 * PREF_BUTTON_WIDTH + - PREF_PAD + RESIZE_HANDLE_WIDTH + - PREF_CATEGORY_WIDTH + - PREF_PAD; +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_select_key.xml", NULL); } -S32 pref_min_height() +//virtual +BOOL LLVoiceSetKeyDialog::postBuild() { - return - 2 * PREF_BORDER + - 3*(BTN_HEIGHT + PREF_PAD) + - PREF_FLOATER_MIN_HEIGHT; -} - - -LLPreferenceCore::LLPreferenceCore(LLTabContainer* tab_container, LLButton * default_btn) : - mTabContainer(tab_container), - mGeneralPanel(NULL), - mInputPanel(NULL), - mNetworkPanel(NULL), - mDisplayPanel(NULL), - mAudioPanel(NULL), - mMsgPanel(NULL), - mSkinsPanel(NULL), - mLCDPanel(NULL) -{ - mGeneralPanel = new LLPanelGeneral(); - mTabContainer->addTabPanel(mGeneralPanel, mGeneralPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mGeneralPanel->setDefaultBtn(default_btn); - - mInputPanel = new LLPanelInput(); - mTabContainer->addTabPanel(mInputPanel, mInputPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mInputPanel->setDefaultBtn(default_btn); - - mNetworkPanel = new LLPanelNetwork(); - mTabContainer->addTabPanel(mNetworkPanel, mNetworkPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mNetworkPanel->setDefaultBtn(default_btn); - - mWebPanel = new LLPanelWeb(); - mTabContainer->addTabPanel(mWebPanel, mWebPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mWebPanel->setDefaultBtn(default_btn); - - mDisplayPanel = new LLPanelDisplay(); - mTabContainer->addTabPanel(mDisplayPanel, mDisplayPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mDisplayPanel->setDefaultBtn(default_btn); - - mAudioPanel = new LLPanelAudioPrefs(); - mTabContainer->addTabPanel(mAudioPanel, mAudioPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mAudioPanel->setDefaultBtn(default_btn); - - mPrefsChat = new LLPrefsChat(); - mTabContainer->addTabPanel(mPrefsChat->getPanel(), mPrefsChat->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); - mPrefsChat->getPanel()->setDefaultBtn(default_btn); - - mPrefsVoice = new LLPrefsVoice(); - mTabContainer->addTabPanel(mPrefsVoice, mPrefsVoice->getLabel(), FALSE, onTabChanged, mTabContainer); - mPrefsVoice->setDefaultBtn(default_btn); - - mPrefsIM = new LLPrefsIM(); - mTabContainer->addTabPanel(mPrefsIM->getPanel(), mPrefsIM->getPanel()->getLabel(), FALSE, onTabChanged, mTabContainer); - mPrefsIM->getPanel()->setDefaultBtn(default_btn); - -#if LL_LCD_COMPILE - - // only add this option if we actually have a logitech keyboard / speaker set - if (gLcdScreen->Enabled()) - { - mLCDPanel = new LLPanelLCD(); - mTabContainer->addTabPanel(mLCDPanel, mLCDPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mLCDPanel->setDefaultBtn(default_btn); - } - -#else - mLCDPanel = NULL; -#endif - - mMsgPanel = new LLPanelMsgs(); - mTabContainer->addTabPanel(mMsgPanel, mMsgPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mMsgPanel->setDefaultBtn(default_btn); + childSetAction("Cancel", onCancel, this); + childSetFocus("Cancel"); - mSkinsPanel = new LLPanelSkins(); - mTabContainer->addTabPanel(mSkinsPanel, mSkinsPanel->getLabel(), FALSE, onTabChanged, mTabContainer); - mSkinsPanel->setDefaultBtn(default_btn); - - if (!mTabContainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) - { - mTabContainer->selectFirstTab(); - } + gFocusMgr.setKeystrokesOnly(TRUE); + + return TRUE; } -LLPreferenceCore::~LLPreferenceCore() +LLVoiceSetKeyDialog::~LLVoiceSetKeyDialog() { - if (mGeneralPanel) - { - delete mGeneralPanel; - mGeneralPanel = NULL; - } - if (mInputPanel) - { - delete mInputPanel; - mInputPanel = NULL; - } - if (mNetworkPanel) - { - delete mNetworkPanel; - mNetworkPanel = NULL; - } - if (mDisplayPanel) - { - delete mDisplayPanel; - mDisplayPanel = NULL; - } - - if (mAudioPanel) - { - delete mAudioPanel; - mAudioPanel = NULL; - } - if (mPrefsChat) - { - delete mPrefsChat; - mPrefsChat = NULL; - } - if (mPrefsIM) - { - delete mPrefsIM; - mPrefsIM = NULL; - } - if (mMsgPanel) - { - delete mMsgPanel; - mMsgPanel = NULL; - } - if (mWebPanel) - { - delete mWebPanel; - mWebPanel = NULL; - } - if (mSkinsPanel) - { - delete mSkinsPanel; - mSkinsPanel = NULL; - } - } - -void LLPreferenceCore::apply() +BOOL LLVoiceSetKeyDialog::handleKeyHere(KEY key, MASK mask) { - mGeneralPanel->apply(); - mInputPanel->apply(); - mNetworkPanel->apply(); - mDisplayPanel->apply(); - mAudioPanel->apply(); - mPrefsChat->apply(); - mPrefsVoice->apply(); - mPrefsIM->apply(); - mMsgPanel->apply(); - mSkinsPanel->apply(); - - // hardware menu apply - LLFloaterHardwareSettings::instance()->apply(); - - mWebPanel->apply(); -#if LL_LCD_COMPILE - // only add this option if we actually have a logitech keyboard / speaker set - if (gLcdScreen->Enabled()) + BOOL result = TRUE; + + if(key == 'Q' && mask == MASK_CONTROL) { - mLCDPanel->apply(); + result = FALSE; } -#endif -// mWebPanel->apply(); + else if (mParent) + { + mParent->setKey(key); + } + + closeFloater(); + return result; } - -void LLPreferenceCore::cancel() +//static +void LLVoiceSetKeyDialog::onCancel(void* user_data) { - mGeneralPanel->cancel(); - mInputPanel->cancel(); - mNetworkPanel->cancel(); - mDisplayPanel->cancel(); - mAudioPanel->cancel(); - mPrefsChat->cancel(); - mPrefsVoice->cancel(); - mPrefsIM->cancel(); - mMsgPanel->cancel(); - mSkinsPanel->cancel(); - - // cancel hardware menu - LLFloaterHardwareSettings::instance()->cancel(); - - mWebPanel->cancel(); -#if LL_LCD_COMPILE - // only add this option if we actually have a logitech keyboard / speaker set - if (gLcdScreen->Enabled()) - { - mLCDPanel->cancel(); - } -#endif -// mWebPanel->cancel(); + LLVoiceSetKeyDialog* self = (LLVoiceSetKeyDialog*)user_data; + self->closeFloater(); } + +// global functions + +// helper functions for getting/freeing the web browser media +// if creating/destroying these is too slow, we'll need to create +// a static member and update all our static callbacks + +void handleNameTagOptionChanged(const LLSD& newvalue); +viewer_media_t get_web_media(); +bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response); + +bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater); +bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater); + +bool extractWindowSizeFromString(const std::string& instr, U32 &width, U32 &height); +void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); + +viewer_media_t get_web_media() +{ + viewer_media_t media_source = LLViewerMedia::newMediaImpl("", LLUUID::null, 0, 0, 0, 0, "text/html"); + + return media_source; +} + + +bool callback_clear_browser_cache(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if ( option == 0 ) // YES + { + // clean web + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) + media_source->getMediaPlugin()->clear_cache(); + + // clean nav bar history + LLNavigationBar::getInstance()->clearHistoryCache(); + + // flag client texture cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotifications::instance().add("CacheWillClear"); + } + + return false; +} + +void handleNameTagOptionChanged(const LLSD& newvalue) +{ + S32 name_tag_option = S32(newvalue); + if(name_tag_option==2) + { + gSavedSettings.setBOOL("SmallAvatarNames", TRUE); + } + else + { + gSavedSettings.setBOOL("SmallAvatarNames", FALSE); + } +} + +bool callback_skip_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (0 == option && floater ) + { + if ( floater ) + { + floater->setAllIgnored(); + LLFirstUse::disableFirstUse(); + LLFloaterPreference::buildLists(floater); + } + } + return false; +} + +bool callback_reset_dialogs(const LLSD& notification, const LLSD& response, LLFloaterPreference* floater) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if ( 0 == option && floater ) + { + if ( floater ) + { + floater->resetAllIgnored(); + LLFirstUse::resetFirstUse(); + LLFloaterPreference::buildLists(floater); + } + } + return false; +} + + +// Extract from strings of the form " x ", e.g. "640 x 480". +bool extractWindowSizeFromString(const std::string& instr, U32 &width, U32 &height) +{ + using namespace boost; + cmatch what; + const regex expression("([0-9]+) x ([0-9]+)"); + if (regex_match(instr.c_str(), what, expression)) + { + width = atoi(what[1].first); + height = atoi(what[2].first); + return true; + } + + width = height = 0; + return false; +} + +void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator) +{ + numerator = 0; + denominator = 0; + for (F32 test_denominator = 1.f; test_denominator < 30.f; test_denominator += 1.f) + { + if (fmodf((decimal_val * test_denominator) + 0.01f, 1.f) < 0.02f) + { + numerator = llround(decimal_val * test_denominator); + denominator = llround(test_denominator); + break; + } + } +} // static -void LLPreferenceCore::onTabChanged(void* user_data, bool from_click) -{ - LLTabContainer* self = (LLTabContainer*)user_data; - - gSavedSettings.setS32("LastPrefTab", self->getCurrentPanelIndex()); -} - - -void LLPreferenceCore::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) -{ - mPrefsIM->setPersonalInfo(visibility, im_via_email, email); -} - -void LLPreferenceCore::refreshEnabledGraphics() -{ - LLFloaterHardwareSettings::instance()->refreshEnabledState(); - mDisplayPanel->refreshEnabledState(); -} - +std::string LLFloaterPreference::sSkin = ""; +F32 LLFloaterPreference::sAspectRatio = 0.0; ////////////////////////////////////////////// // LLFloaterPreference -LLFloaterPreference::LLFloaterPreference() +LLFloaterPreference::LLFloaterPreference(const LLSD& key) + : LLFloater(key), + mGotPersonalInfo(false), + mOriginalIMViaEmail(false) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preferences.xml"); + //Build Floater is now Called from LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + static bool registered_dialog = false; + if (!registered_dialog) + { + LLFloaterReg::add("voice_set_key", "floater_select_key.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + registered_dialog = true; + } + + mCommitCallbackRegistrar.add("Pref.Apply", boost::bind(&LLFloaterPreference::onBtnApply, this)); + mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreference::onBtnCancel, this)); + mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreference::onBtnOK, this)); + +// mCommitCallbackRegistrar.add("Pref.ClearCache", boost::bind(&LLFloaterPreference::onClickClearCache, this)); + mCommitCallbackRegistrar.add("Pref.WebClearCache", boost::bind(&LLFloaterPreference::onClickBrowserClearCache, this)); + mCommitCallbackRegistrar.add("Pref.SetCache", boost::bind(&LLFloaterPreference::onClickSetCache, this)); + 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.VoiceSetMiddleMouse", boost::bind(&LLFloaterPreference::onClickSetMiddleMouse, this)); + mCommitCallbackRegistrar.add("Pref.ClickSkipDialogs", boost::bind(&LLFloaterPreference::onClickSkipDialogs, this)); + mCommitCallbackRegistrar.add("Pref.ClickResetDialogs", boost::bind(&LLFloaterPreference::onClickResetDialogs, this)); + mCommitCallbackRegistrar.add("Pref.ClickEnablePopup", boost::bind(&LLFloaterPreference::onClickEnablePopup, this)); + mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); + mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); + mCommitCallbackRegistrar.add("Pref.Logging", boost::bind(&LLFloaterPreference::onCommitLogging, this)); + mCommitCallbackRegistrar.add("Pref.OpenHelp", boost::bind(&LLFloaterPreference::onOpenHelp, this)); + mCommitCallbackRegistrar.add("Pref.UpdateMeterText", boost::bind(&LLFloaterPreference::updateMeterText, this, _1)); + mCommitCallbackRegistrar.add("Pref.HardwareSettings", boost::bind(&LLFloaterPreference::onOpenHardwareSettings, this)); + mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); + mCommitCallbackRegistrar.add("Pref.VertexShaderEnable", boost::bind(&LLFloaterPreference::onVertexShaderEnable, this)); + mCommitCallbackRegistrar.add("Pref.WindowedMod", boost::bind(&LLFloaterPreference::onCommitWindowedMode, this)); + mCommitCallbackRegistrar.add("Pref.UpdateSliderText", boost::bind(&LLFloaterPreference::onUpdateSliderText,this, _1,_2)); + mCommitCallbackRegistrar.add("Pref.AutoDetectAspect", boost::bind(&LLFloaterPreference::onCommitAutoDetectAspect, this)); + mCommitCallbackRegistrar.add("Pref.onSelectAspectRatio", boost::bind(&LLFloaterPreference::onKeystrokeAspectRatio, this)); + mCommitCallbackRegistrar.add("Pref.QualityPerformance", boost::bind(&LLFloaterPreference::onChangeQuality, this, _2)); + + sSkin = gSavedSettings.getString("SkinCurrent"); + + gSavedSettings.getControl("AvatarNameTagMode")->getCommitSignal()->connect(boost::bind(&handleNameTagOptionChanged, _2)); } BOOL LLFloaterPreference::postBuild() { - requires("About..."); - requires("OK"); - requires("Cancel"); - requires("Apply"); - requires("pref core"); - - if (!checkRequirements()) - { - return FALSE; - } - - mAboutBtn = getChild("About..."); - mAboutBtn->setClickedCallback(onClickAbout, this); + mCloseSignal.connect(boost::bind(&LLFloaterPreference::onClose, this)); - mApplyBtn = getChild("Apply"); - mApplyBtn->setClickedCallback(onBtnApply, this); - - mCancelBtn = getChild("Cancel"); - mCancelBtn->setClickedCallback(onBtnCancel, this); - - mOKBtn = getChild("OK"); - mOKBtn->setClickedCallback(onBtnOK, this); - - mPreferenceCore = new LLPreferenceCore( - getChild("pref core"), - getChild("OK") - ); - - sInstance = this; - + LLTabContainer* tabcontainer = getChild("pref core"); + if (!tabcontainer->selectTab(gSavedSettings.getS32("LastPrefTab"))) + tabcontainer->selectFirstTab(); + S32 show_avatar_nametag_options = gSavedSettings.getS32("AvatarNameTagMode"); + handleNameTagOptionChanged(LLSD(show_avatar_nametag_options)); return TRUE; } - LLFloaterPreference::~LLFloaterPreference() { - sInstance = NULL; - delete mPreferenceCore; + // clean up user data + LLComboBox* ctrl_aspect_ratio = getChild( "aspect_ratio"); + LLComboBox* ctrl_window_size = getChild("windowsize combo"); + for (S32 i = 0; i < ctrl_aspect_ratio->getItemCount(); i++) + { + ctrl_aspect_ratio->setCurrentByIndex(i); + } + for (S32 i = 0; i < ctrl_window_size->getItemCount(); i++) + { + ctrl_window_size->setCurrentByIndex(i); + } +} +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::apply() { - this->mPreferenceCore->apply(); -} + LLTabContainer* tabcontainer = getChild("pref core"); + if (sSkin != gSavedSettings.getString("SkinCurrent")) + { + LLNotifications::instance().add("ChangeSkin"); + refreshSkin(this); + } + // Call apply() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + panel->apply(); + } + // hardware menu apply + LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance("prefs_hardware_settings"); + if (hardware_settings) + { + hardware_settings->apply(); + } + + LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterReg::findTypedInstance("pref_voicedevicesettings"); + if(voice_device_settings) + { + voice_device_settings->apply(); + } + + gViewerWindow->requestResolutionUpdate(); // for UIScaleFactor + LLSliderCtrl* fov_slider = getChild("camera_fov"); + fov_slider->setMinValue(LLViewerCamera::getInstance()->getMinView()); + fov_slider->setMaxValue(LLViewerCamera::getInstance()->getMaxView()); + + std::string cache_location = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); + childSetText("cache_location", cache_location); + + viewer_media_t media_source = get_web_media(); + if (media_source && media_source->hasMedia()) + { + media_source->getMediaPlugin()->enable_cookies(childGetValue("cookies_enabled")); + if(hasChild("web_proxy_enabled") &&hasChild("web_proxy_editor") && hasChild("web_proxy_port")) + { + bool proxy_enable = childGetValue("web_proxy_enabled"); + std::string proxy_address = childGetValue("web_proxy_editor"); + int proxy_port = childGetValue("web_proxy_port"); + media_source->getMediaPlugin()->proxy_setup(proxy_enable, proxy_address, proxy_port); + } + } + +// LLWString busy_response = utf8str_to_wstring(getChild("busy_response")->getValue().asString()); +// LLWStringUtil::replaceTabsWithSpaces(busy_response, 4); + + if(mGotPersonalInfo) + { +// gSavedSettings.setString("BusyModeResponse2", std::string(wstring_to_utf8str(busy_response))); + bool new_im_via_email = childGetValue("send_im_to_email").asBoolean(); + bool new_hide_online = childGetValue("online_visibility").asBoolean(); + + if((new_im_via_email != mOriginalIMViaEmail) + ||(new_hide_online != mOriginalHideOnlineStatus)) + { + // This hack is because we are representing several different + // possible strings with a single checkbox. Since most users + // can only select between 2 values, we represent it as a + // checkbox. This breaks down a little bit for liaisons, but + // works out in the end. + if(new_hide_online != mOriginalHideOnlineStatus) + { + if(new_hide_online) mDirectoryVisibility = VISIBILITY_HIDDEN; + else mDirectoryVisibility = VISIBILITY_DEFAULT; + //Update showonline value, otherwise multiple applys won't work + mOriginalHideOnlineStatus = new_hide_online; + } + gAgent.sendAgentUpdateUserInfo(new_im_via_email,mDirectoryVisibility); + } + } + + applyResolution(); + + // Only set window size if we're not in fullscreen mode + if(!gSavedSettings.getBOOL("WindowFullScreen")) + { + applyWindowSize(); + } + +} void LLFloaterPreference::cancel() { - this->mPreferenceCore->cancel(); + LLTabContainer* tabcontainer = getChild("pref core"); + // Call cancel() on all panels that derive from LLPanelPreference + for (child_list_t::const_iterator iter = tabcontainer->getChildList()->begin(); + iter != tabcontainer->getChildList()->end(); ++iter) + { + LLView* view = *iter; + LLPanelPreference* panel = dynamic_cast(view); + if (panel) + panel->cancel(); + } + // hide joystick pref floater + LLFloaterReg::hideInstance("pref_joystick"); + + // cancel hardware menu + LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance("prefs_hardware_settings"); + if (hardware_settings) + { + hardware_settings->cancel(); + } + + // reverts any changes to current skin + gSavedSettings.setString("SkinCurrent", sSkin); + + LLFloaterVoiceDeviceSettings* voice_device_settings = LLFloaterReg::findTypedInstance("pref_voicedevicesettings"); + if (voice_device_settings) + { + voice_device_settings ->cancel(); + } + + LLFloaterReg::hideInstance("pref_voicedevicesettings"); + + gSavedSettings.setF32("FullScreenAspectRatio", sAspectRatio); + } - -// static -void LLFloaterPreference::show(void*) +void LLFloaterPreference::onOpen(const LLSD& key) { - if (!sInstance) - { - new LLFloaterPreference(); - sInstance->center(); - } - - sInstance->open(); /* Flawfinder: ignore */ - - if(!gAgent.getID().isNull()) - { - // we're logged in, so we can get this info. - gMessageSystem->newMessageFast(_PREHASH_UserInfoRequest); - gMessageSystem->nextBlockFast(_PREHASH_AgentData); - gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - } - + gAgent.sendAgentUserInfoRequest(); LLPanelLogin::setAlwaysRefresh(true); + refresh(); } - -// static -void LLFloaterPreference::onClickAbout(void*) +void LLFloaterPreference::onVertexShaderEnable() { - LLFloaterAbout::show(NULL); + refreshEnabledGraphics(); } +void LLFloaterPreference::setHardwareDefaults() +{ + LLFeatureManager::getInstance()->applyRecommendedSettings(); + refreshEnabledGraphics(); +} +void LLFloaterPreference::onClose() +{ + gSavedSettings.setS32("LastPrefTab", getChild("pref core")->getCurrentPanelIndex()); + LLPanelLogin::setAlwaysRefresh(false); + cancel(); // will be a no-op if OK or apply was performed just prior. +} + +void LLFloaterPreference::onOpenHardwareSettings() +{ + LLFloaterReg::showInstance("prefs_hardware_settings"); +} // static -void LLFloaterPreference::onBtnOK( void* userdata ) +void LLFloaterPreference::onBtnOK() { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; // commit any outstanding text entry - if (fp->hasFocus()) + if (hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } } - if (fp->canClose()) + if (canClose()) { - fp->apply(); - fp->close(false); - + apply(); + closeFloater(false); gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE ); - + LLUIColorTable::instance().saveUserSettings(); std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE); // save all settings, even if equals defaults gCrashSettings.saveToFile(crash_settings_filename, FALSE); @@ -458,59 +573,1051 @@ void LLFloaterPreference::onBtnOK( void* userdata ) LLPanelLogin::refreshLocation( false ); } +void LLFloaterPreference::onOpenHelp() +{ + const char* xml_alert = "GraphicsPreferencesHelp"; + LLNotifications::instance().add(this->contextualNotification(xml_alert)); +} // static -void LLFloaterPreference::onBtnApply( void* userdata ) +void LLFloaterPreference::onBtnApply( ) { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; - if (fp->hasFocus()) + if (hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } } - fp->apply(); + apply(); LLPanelLogin::refreshLocation( false ); } - -void LLFloaterPreference::onClose(bool app_quitting) -{ - LLPanelLogin::setAlwaysRefresh(false); - cancel(); // will be a no-op if OK or apply was performed just prior. - LLFloater::onClose(app_quitting); -} - - // static -void LLFloaterPreference::onBtnCancel( void* userdata ) +void LLFloaterPreference::onBtnCancel() { - LLFloaterPreference *fp =(LLFloaterPreference *)userdata; - if (fp->hasFocus()) + if (hasFocus()) { - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); if (cur_focus->acceptsTextInput()) { cur_focus->onCommit(); } + refresh(); } - fp->close(); // side effect will also cancel any unsaved changes. + closeFloater(); // side effect will also cancel any unsaved changes. } - -// static +// static void LLFloaterPreference::updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email) { - if(sInstance && sInstance->mPreferenceCore) + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if(instance) { - sInstance->mPreferenceCore->setPersonalInfo(visibility, im_via_email, email); + instance->setPersonalInfo(visibility, im_via_email, email); } } + void LLFloaterPreference::refreshEnabledGraphics() { - sInstance->mPreferenceCore->refreshEnabledGraphics(); + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance("preferences"); + if(instance) + { + instance->refreshEnabledState(); + } + LLFloaterHardwareSettings* hardware_settings = LLFloaterReg::getTypedInstance("prefs_hardware_settings"); + if (hardware_settings) + { + hardware_settings->refreshEnabledState(); + } } + +void LLFloaterPreference::updateMeterText(LLUICtrl* ctrl) +{ + // get our UI widgets + LLSliderCtrl* slider = (LLSliderCtrl*) ctrl; + + LLTextBox* m1 = getChild("DrawDistanceMeterText1"); + LLTextBox* m2 = getChild("DrawDistanceMeterText2"); + + // toggle the two text boxes based on whether we have 1 or two digits + F32 val = slider->getValueF32(); + bool two_digits = val < 100; + m1->setVisible(two_digits); + m2->setVisible(!two_digits); +} +/* +void LLFloaterPreference::onClickClearCache() +{ + // flag client cache for clearing next time the client runs + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", TRUE); + LLNotifications::instance().add("CacheWillClear"); +} +*/ + +void LLFloaterPreference::onClickBrowserClearCache() +{ + LLNotifications::instance().add("ConfirmClearBrowserCache", LLSD(), LLSD(), callback_clear_browser_cache); +} + +void LLFloaterPreference::onClickSetCache() +{ + std::string cur_name(gSavedSettings.getString("CacheLocation")); +// std::string cur_top_folder(gDirUtilp->getBaseFileName(cur_name)); + + std::string proposed_name(cur_name); + + LLDirPicker& picker = LLDirPicker::instance(); + if (! picker.getDir(&proposed_name ) ) + { + return; //Canceled! + } + + std::string dir_name = picker.getDirName(); + if (!dir_name.empty() && dir_name != cur_name) + { + std::string new_top_folder(gDirUtilp->getBaseFileName(dir_name)); + LLNotifications::instance().add("CacheWillBeMoved"); + gSavedSettings.setString("NewCacheLocation", dir_name); + gSavedSettings.setString("NewCacheLocationTopFolder", new_top_folder); + } + else + { + std::string cache_location = gDirUtilp->getCacheDir(); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); + } +} + +void LLFloaterPreference::onClickResetCache() +{ + if (!gSavedSettings.getString("CacheLocation").empty()) + { + gSavedSettings.setString("NewCacheLocation", ""); + gSavedSettings.setString("NewCacheLocationTopFolder", ""); + LLNotifications::instance().add("CacheWillBeMoved"); + } + std::string cache_location = gDirUtilp->getCacheDir(true); + gSavedSettings.setString("CacheLocation", cache_location); + std::string top_folder(gDirUtilp->getBaseFileName(cache_location)); + gSavedSettings.setString("CacheLocationTopFolder", top_folder); +} + +void LLFloaterPreference::onClickSkin(LLUICtrl* ctrl, const LLSD& userdata) +{ + gSavedSettings.setString("SkinCurrent", userdata.asString()); + ctrl->setValue(userdata.asString()); +} + +void LLFloaterPreference::onSelectSkin() +{ + std::string skin_selection = getChild("skin_selection")->getValue().asString(); + gSavedSettings.setString("SkinCurrent", skin_selection); +} + +void LLFloaterPreference::refreshSkin(void* data) +{ + LLPanel*self = (LLPanel*)data; + sSkin = gSavedSettings.getString("SkinCurrent"); + self->getChild("skin_selection", true)->setValue(sSkin); +} + +// static +void LLFloaterPreference::buildLists(void* data) +{ + LLPanel*self = (LLPanel*)data; + LLScrollListCtrl& disabled_popups = self->getChildRef("disabled_popups"); + LLScrollListCtrl& enabled_popups = self->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 = LLUI::sSettingGroups["ignores"]->getBOOL(templatep->mName); + if (!show_popup) + { + if (ignore == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + LLSD last_response = LLUI::sSettingGroups["config"]->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(); + break; + } + } + } + row["columns"][1]["font"] = "SANSSERIF_SMALL"; + row["columns"][1]["width"] = 360; + } + item = disabled_popups.addElement(row, + ADD_SORTED); + } + else + { + item = enabled_popups.addElement(row, + ADD_SORTED); + } + + if (item) + { + item->setUserdata((void*)&iter->first); + } + } +} + +void LLFloaterPreference::refreshEnabledState() +{ + + LLCheckBoxCtrl* ctrl_reflections = getChild("Reflections"); + LLRadioGroup* radio_reflection_detail = getChild("ReflectionDetailRadio"); + + // Reflections + BOOL reflections = gSavedSettings.getBOOL("VertexShaderEnable") + && gGLManager.mHasCubeMap + && LLCubeMap::sUseCubeMaps; + ctrl_reflections->setEnabled(reflections); + + // Bump & Shiny + bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); + getChild("BumpShiny")->setEnabled(bumpshiny ? TRUE : FALSE); + + for (S32 i = 0; i < radio_reflection_detail->getItemCount(); ++i) + { + radio_reflection_detail->setIndexEnabled(i, ctrl_reflections->get() && reflections); + } + + // Avatar Mode + // Enable Avatar Shaders + LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); + // Avatar Render Mode + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); + + S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel; + ctrl_avatar_vp->setEnabled((max_avatar_shader > 0) ? TRUE : FALSE); + + if (gSavedSettings.getBOOL("VertexShaderEnable") == FALSE || + gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) + { + ctrl_avatar_cloth->setEnabled(false); + } + else + { + ctrl_avatar_cloth->setEnabled(true); + } + + // Vertex Shaders + // Global Shader Enable + LLCheckBoxCtrl* ctrl_shader_enable = getChild("BasicShaders"); + // radio set for terrain detail mode + LLRadioGroup* mRadioTerrainDetail = getChild("TerrainDetailRadio"); // can be linked with control var + + ctrl_shader_enable->setEnabled(LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")); + + BOOL shaders = ctrl_shader_enable->get(); + if (shaders) + { + mRadioTerrainDetail->setValue(1); + mRadioTerrainDetail->setEnabled(FALSE); + } + else + { + mRadioTerrainDetail->setEnabled(TRUE); + } + + // WindLight + LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); + + // *HACK just checks to see if we can use shaders... + // maybe some cards that use shaders, but don't support windlight + ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders); + // now turn off any features that are unavailable + disableUnavailableSettings(); +} + +void LLFloaterPreference::disableUnavailableSettings() +{ + LLCheckBoxCtrl* ctrl_reflections = getChild("Reflections"); + LLCheckBoxCtrl* ctrl_avatar_vp = getChild("AvatarVertexProgram"); + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild("AvatarCloth"); + LLCheckBoxCtrl* ctrl_shader_enable = getChild("BasicShaders"); + LLCheckBoxCtrl* ctrl_wind_light = getChild("WindLightUseAtmosShaders"); + LLCheckBoxCtrl* ctrl_avatar_impostors = getChild("AvatarImpostors"); + + // if vertex shaders off, disable all shader related products + if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable")) + { + ctrl_shader_enable->setEnabled(FALSE); + ctrl_shader_enable->setValue(FALSE); + + ctrl_wind_light->setEnabled(FALSE); + ctrl_wind_light->setValue(FALSE); + + ctrl_reflections->setEnabled(FALSE); + ctrl_reflections->setValue(FALSE); + + ctrl_avatar_vp->setEnabled(FALSE); + ctrl_avatar_vp->setValue(FALSE); + + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + } + + // disabled windlight + if(!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) + { + ctrl_wind_light->setEnabled(FALSE); + ctrl_wind_light->setValue(FALSE); + } + + // disabled reflections + if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderWaterReflections")) + { + ctrl_reflections->setEnabled(FALSE); + ctrl_reflections->setValue(FALSE); + } + + // disabled av + if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) + { + ctrl_avatar_vp->setEnabled(FALSE); + ctrl_avatar_vp->setValue(FALSE); + + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + } + // disabled cloth + if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) + { + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + } + // disabled impostors + if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors")) + { + ctrl_avatar_impostors->setEnabled(FALSE); + ctrl_avatar_impostors->setValue(FALSE); + } +} + +void LLFloaterPreference::onCommitAutoDetectAspect() +{ + BOOL auto_detect = getChild("aspect_auto_detect")->get(); + F32 ratio; + + if (auto_detect) + { + S32 numerator = 0; + S32 denominator = 0; + + // clear any aspect ratio override + gViewerWindow->mWindow->setNativeAspectRatio(0.f); + fractionFromDecimal(gViewerWindow->mWindow->getNativeAspectRatio(), numerator, denominator); + + std::string aspect; + if (numerator != 0) + { + aspect = llformat("%d:%d", numerator, denominator); + } + else + { + aspect = llformat("%.3f", gViewerWindow->mWindow->getNativeAspectRatio()); + } + + getChild( "aspect_ratio")->setLabel(aspect); + + ratio = gViewerWindow->mWindow->getNativeAspectRatio(); + gSavedSettings.setF32("FullScreenAspectRatio", ratio); + } +} + +void LLFloaterPreference::refresh() +{ + LLPanel::refresh(); + + // sliders and their text boxes + // mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow"); + // slider text boxes + updateSliderText(getChild("ObjectMeshDetail", true), getChild("ObjectMeshDetailText", true)); + updateSliderText(getChild("FlexibleMeshDetail", true), getChild("FlexibleMeshDetailText", true)); + updateSliderText(getChild("TreeMeshDetail", true), getChild("TreeMeshDetailText", true)); + updateSliderText(getChild("AvatarMeshDetail", true), getChild("AvatarMeshDetailText", true)); + updateSliderText(getChild("TerrainMeshDetail", true), getChild("TerrainMeshDetailText", true)); + updateSliderText(getChild("RenderPostProcess", true), getChild("PostProcessText", true)); + updateSliderText(getChild("SkyMeshDetail", true), getChild("SkyMeshDetailText", true)); + + refreshEnabledState(); +} + +void LLFloaterPreference::onCommitWindowedMode() +{ + refresh(); +} + +void LLFloaterPreference::onChangeQuality(const LLSD& data) +{ + U32 level = (U32)(data.asReal()); + LLFeatureManager::getInstance()->setGraphicsLevel(level, true); + refreshEnabledGraphics(); + refresh(); +} + +// static +// DEV-24146 - needs to be removed at a later date. jan-2009 +void LLFloaterPreference::cleanupBadSetting() +{ + if (gSavedPerAccountSettings.getString("BusyModeResponse2") == "|TOKEN COPY BusyModeResponse|") + { + llwarns << "cleaning old BusyModeResponse" << llendl; + gSavedPerAccountSettings.setString("BusyModeResponse2", gSavedPerAccountSettings.getText("BusyModeResponse")); + } +} + +void LLFloaterPreference::onClickSetKey() +{ + LLVoiceSetKeyDialog* dialog = LLFloaterReg::showTypedInstance("voice_set_key", LLSD(), TRUE); + if (dialog) + { + dialog->setParent(this); + } +} + +void LLFloaterPreference::setKey(KEY key) +{ + childSetValue("modifier_combo", LLKeyboard::stringFromKey(key)); +} + +void LLFloaterPreference::onClickSetMiddleMouse() +{ + childSetValue("modifier_combo", "MiddleMouse"); +} + +void LLFloaterPreference::onClickSkipDialogs() +{ + LLNotifications::instance().add("SkipShowNextTimeDialogs", LLSD(), LLSD(), boost::bind(&callback_skip_dialogs, _1, _2, this)); +} + +void LLFloaterPreference::onClickResetDialogs() +{ + LLNotifications::instance().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::sSettingGroups["ignores"]->setBOOL(notification_name, TRUE); + } + + buildLists(this); +} + +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())); + //gSavedSettings.setWarning(templatep->mName, TRUE); + std::string notification_name = templatep->mName; + LLUI::sSettingGroups["ignores"]->setBOOL(notification_name, FALSE); + } + + buildLists(this); +} +void LLFloaterPreference::resetAllIgnored() +{ + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + { + LLUI::sSettingGroups["ignores"]->setBOOL(iter->first, TRUE); + } + } +} + +void LLFloaterPreference::setAllIgnored() +{ + for (LLNotifications::TemplateMap::const_iterator iter = LLNotifications::instance().templatesBegin(); + iter != LLNotifications::instance().templatesEnd(); + ++iter) + { + if (iter->second->mForm->getIgnoreType() != LLNotificationForm::IGNORE_NO) + { + LLUI::sSettingGroups["ignores"]->setBOOL(iter->first, FALSE); + } + } +} + +void LLFloaterPreference::onClickLogPath() +{ + std::string proposed_name(gSavedPerAccountSettings.getString("InstantMessageLogPath")); + + LLDirPicker& picker = LLDirPicker::instance(); + if (!picker.getDir(&proposed_name ) ) + { + return; //Canceled! + } + std::string chat_log_dir = picker.getDirName(); + std::string chat_log_top_folder= gDirUtilp->getBaseFileName(chat_log_dir); + gSavedPerAccountSettings.setString("InstantMessageLogPath",chat_log_dir); + gSavedPerAccountSettings.setString("InstantMessageLogFolder",chat_log_top_folder); +} + +void LLFloaterPreference::onCommitLogging() +{ + enableHistory(); +} + +void LLFloaterPreference::enableHistory() +{ + if (childGetValue("log_instant_messages").asBoolean()) + { + childEnable("ChatIMLogs"); + childEnable("log_path_button"); + childEnable("show_timestamps_check_im"); + } + else + { + childDisable("ChatIMLogs"); + childDisable("log_path_button"); + childDisable("show_timestamps_check_im"); + } +} + +void LLFloaterPreference::setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email) +{ + mGotPersonalInfo = true; + mOriginalIMViaEmail = im_via_email; + mDirectoryVisibility = visibility; + + if(visibility == VISIBILITY_DEFAULT) + { + mOriginalHideOnlineStatus = false; + childEnable("online_visibility"); + } + else if(visibility == VISIBILITY_HIDDEN) + { + mOriginalHideOnlineStatus = true; + childEnable("online_visibility"); + } + else + { + mOriginalHideOnlineStatus = true; + } + + childEnable("include_im_in_chat_history"); + childEnable("show_timestamps_check_im"); + childEnable("friends_online_notify_checkbox"); + + childSetValue("online_visibility", mOriginalHideOnlineStatus); + childSetLabelArg("online_visibility", "[DIR_VIS]", mDirectoryVisibility); + childEnable("send_im_to_email"); + childSetValue("send_im_to_email", im_via_email); + childEnable("log_instant_messages"); +// childEnable("log_chat"); +// childEnable("busy_response"); +// childEnable("log_instant_messages_timestamp"); +// childEnable("log_chat_timestamp"); + childEnable("log_chat_IM"); + childEnable("log_date_timestamp"); + +// childSetText("busy_response", gSavedSettings.getString("BusyModeResponse2")); + + enableHistory(); + std::string display_email(email); + childSetText("email_address",display_email); + +} + +void LLFloaterPreference::onUpdateSliderText(LLUICtrl* ctrl, const LLSD& name) +{ + std::string ctrl_name = name.asString(); + + if((ctrl_name =="" )|| !hasChild(ctrl_name, true)) + return; + + LLTextBox* text_box = getChild(name.asString()); + LLSliderCtrl* slider = dynamic_cast(ctrl); + updateSliderText(slider, text_box); +} + +void LLFloaterPreference::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box) +{ + if(text_box == NULL || ctrl== NULL) + return; + + // get range and points when text should change + F32 value = (F32)ctrl->getValue().asReal(); + F32 min = ctrl->getMinValue(); + F32 max = ctrl->getMaxValue(); + F32 range = max - min; + llassert(range > 0); + F32 midPoint = min + range / 3.0f; + F32 highPoint = min + (2.0f * range / 3.0f); + + // choose the right text + if(value < midPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityLow")); + } + else if (value < highPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityMid")); + } + else + { + text_box->setText(LLTrans::getString("GraphicsQualityHigh")); + } +} + +void LLFloaterPreference::onKeystrokeAspectRatio() +{ + getChild("aspect_auto_detect")->set(FALSE); +} + +void LLFloaterPreference::applyWindowSize() +{ + LLComboBox* ctrl_windowSize = getChild("windowsize combo"); + if (ctrl_windowSize->getVisible() && (ctrl_windowSize->getCurrentIndex() != -1)) + { + U32 width = 0; + U32 height = 0; + if (extractWindowSizeFromString(ctrl_windowSize->getValue().asString().c_str(), width,height)) + { + LLViewerWindow::movieSize(width, height); + } + } +} + +void LLFloaterPreference::applyResolution() +{ + LLComboBox* ctrl_aspect_ratio = getChild( "aspect_ratio"); + gGL.flush(); + char aspect_ratio_text[ASPECT_RATIO_STR_LEN]; /*Flawfinder: ignore*/ + if (ctrl_aspect_ratio->getCurrentIndex() == -1) + { + // *Can't pass const char* from c_str() into strtok + strncpy(aspect_ratio_text, ctrl_aspect_ratio->getSimple().c_str(), sizeof(aspect_ratio_text) -1); /*Flawfinder: ignore*/ + aspect_ratio_text[sizeof(aspect_ratio_text) -1] = '\0'; + char *element = strtok(aspect_ratio_text, ":/\\"); + if (!element) + { + sAspectRatio = 0.f; // will be clamped later + } + else + { + LLLocale locale(LLLocale::USER_LOCALE); + sAspectRatio = (F32)atof(element); + } + + // look for denominator + element = strtok(NULL, ":/\\"); + if (element) + { + LLLocale locale(LLLocale::USER_LOCALE); + + F32 denominator = (F32)atof(element); + if (denominator != 0.f) + { + sAspectRatio /= denominator; + } + } + } + else + { + sAspectRatio = (F32)ctrl_aspect_ratio->getValue().asReal(); + } + + // presumably, user entered a non-numeric value if aspect_ratio == 0.f + if (sAspectRatio != 0.f) + { + sAspectRatio = llclamp(sAspectRatio, 0.2f, 5.f); + gSavedSettings.setF32("FullScreenAspectRatio", sAspectRatio); + } + + // Screen resolution + S32 num_resolutions; + LLWindow::LLWindowResolution* supported_resolutions = + gViewerWindow->getWindow()->getSupportedResolutions(num_resolutions); + S32 resIndex = getChild("fullscreen combo")->getCurrentIndex(); + if (resIndex == -1) + { + // use highest resolution if nothing selected + resIndex = num_resolutions - 1; + } + gSavedSettings.setS32("FullScreenWidth", supported_resolutions[resIndex].mWidth); + gSavedSettings.setS32("FullScreenHeight", supported_resolutions[resIndex].mHeight); + + gViewerWindow->requestResolutionUpdate(gSavedSettings.getBOOL("WindowFullScreen")); + + send_agent_update(TRUE); + + // Update enable/disable + refresh(); +} + +void LLFloaterPreference::initWindowSizeControls(LLPanel* panelp) +{ + // Window size + // mWindowSizeLabel = getChild("WindowSizeLabel"); + LLComboBox* ctrl_window_size = panelp->getChild("windowsize combo"); + + // Look to see if current window size matches existing window sizes, if so then + // just set the selection value... + const U32 height = gViewerWindow->getWindowDisplayHeight(); + const U32 width = gViewerWindow->getWindowDisplayWidth(); + for (S32 i=0; i < ctrl_window_size->getItemCount(); i++) + { + U32 height_test = 0; + U32 width_test = 0; + ctrl_window_size->setCurrentByIndex(i); + if (extractWindowSizeFromString(ctrl_window_size->getValue().asString(), width_test, height_test)) + { + if ((height_test == height) && (width_test == width)) + { + return; + } + } + } + // ...otherwise, add a new entry with the current window height/width. + LLUIString resolution_label = panelp->getString("resolution_format"); + resolution_label.setArg("[RES_X]", llformat("%d", width)); + resolution_label.setArg("[RES_Y]", llformat("%d", height)); + ctrl_window_size->add(resolution_label, ADD_TOP); + ctrl_window_size->setCurrentByIndex(0); +} + + + +//---------------------------------------------------------------------------- +static LLRegisterPanelClassWrapper t_places("panel_preference"); +LLPanelPreference::LLPanelPreference() +: LLPanel() +{ + mCommitCallbackRegistrar.add("Pref.setControlFalse", boost::bind(&LLPanelPreference::setControlFalse,this, _2)); +} + +static void applyUIColor(const std::string& color_name, LLUICtrl* ctrl, const LLSD& param) +{ + LLUIColorTable::instance().setColor(color_name, LLColor4(param)); +} + +//virtual +BOOL LLPanelPreference::postBuild() +{ + if (hasChild("maturity_desired_combobox")) + { + /////////////////////////// From LLPanelGeneral ////////////////////////// + // if we have no agent, we can't let them choose anything + // if we have an agent, then we only let them choose if they have a choice + bool canChoose = gAgent.getID().notNull() && + (gAgent.isMature() || gAgent.isGodlike()); + + if (canChoose) + { + + // if they're not adult or a god, they shouldn't see the adult selection, so delete it + if (!gAgent.isAdult() && !gAgent.isGodlike()) + { + LLComboBox* pMaturityCombo = getChild("maturity_desired_combobox"); + // we're going to remove the adult entry from the combo. This obviously depends + // on the order of items in the XML file, but there doesn't seem to be a reasonable + // way to depend on the field in XML called 'name'. + pMaturityCombo->remove(0); + } + childSetVisible("maturity_desired_combobox", true); + childSetVisible("maturity_desired_textbox", false); + } + else + { + childSetVisible("maturity_desired_combobox", false); + std::string selectedItemLabel = getChild("maturity_desired_combobox")->getSelectedItemLabel(); + childSetValue("maturity_desired_textbox", selectedItemLabel); + childSetVisible("maturity_desired_textbox", true); + } + } + ////////////////////// PanelVoice /////////////////// + if(hasChild("voice_unavailable")) + { + BOOL voice_disabled = gSavedSettings.getBOOL("CmdLineDisableVoice"); + childSetVisible("voice_unavailable", voice_disabled); + childSetVisible("enable_voice_check", !voice_disabled); + } + + //////////////////////PanelSkins /////////////////// + + if (hasChild("skin_selection")) + { + LLFloaterPreference::refreshSkin(this); + + // if skin is set to a skin that no longer exists (silver) set back to default + if (getChild("skin_selection")->getSelectedIndex() < 0) + { + gSavedSettings.setString("SkinCurrent", "default"); + LLFloaterPreference::refreshSkin(this); + } + + } + ////////////////////////Panel Popups///////////////// + if(hasChild("disabled_popups") && hasChild("enabled_popups")) + { + LLFloaterPreference::buildLists(this); + } + ////// + if(hasChild("online_visibility") && hasChild("send_im_to_email")) + { + childSetText("email_address",getString("log_in_to_change") ); +// childSetText("busy_response", getString("log_in_to_change")); + + } + + + if(hasChild("aspect_ratio")) + { + //============================================================================ + // Resolution +/* + S32 num_resolutions = 0; + LLWindow::LLWindowResolution* supported_resolutions = gViewerWindow->getWindow()->getSupportedResolutions(num_resolutions); + + S32 fullscreen_mode = num_resolutions - 1; + + LLComboBox*ctrl_full_screen = getChild( "fullscreen combo"); + LLUIString resolution_label = getString("resolution_format"); + + for (S32 i = 0; i < num_resolutions; i++) + { + resolution_label.setArg("[RES_X]", llformat("%d", supported_resolutions[i].mWidth)); + resolution_label.setArg("[RES_Y]", llformat("%d", supported_resolutions[i].mHeight)); + ctrl_full_screen->add( resolution_label, ADD_BOTTOM ); + } + + { + BOOL targetFullscreen; + S32 targetWidth; + S32 targetHeight; + + gViewerWindow->getTargetWindow(targetFullscreen, targetWidth, targetHeight); + + if (targetFullscreen) + { + fullscreen_mode = 0; // default to 800x600 + for (S32 i = 0; i < num_resolutions; i++) + { + if (targetWidth == supported_resolutions[i].mWidth + && targetHeight == supported_resolutions[i].mHeight) + { + fullscreen_mode = i; + } + } + ctrl_full_screen->setCurrentByIndex(fullscreen_mode); + } + else + { + // set to windowed mode + //fullscreen_mode = mCtrlFullScreen->getItemCount() - 1; + ctrl_full_screen->setCurrentByIndex(0); + } + } + */ + LLFloaterPreference::initWindowSizeControls(this); + + if (gSavedSettings.getBOOL("FullScreenAutoDetectAspectRatio")) + { + LLFloaterPreference::sAspectRatio = gViewerWindow->getDisplayAspectRatio(); + } + else + { + LLFloaterPreference::sAspectRatio = gSavedSettings.getF32("FullScreenAspectRatio"); + } + + getChild("aspect_ratio")->setTextEntryCallback(boost::bind(&LLPanelPreference::setControlFalse, this, LLSD("FullScreenAutoDetectAspectRatio") )); + + + S32 numerator = 0; + S32 denominator = 0; + fractionFromDecimal(LLFloaterPreference::sAspectRatio, numerator, denominator); + + LLUIString aspect_ratio_text = getString("aspect_ratio_text"); + if (numerator != 0) + { + aspect_ratio_text.setArg("[NUM]", llformat("%d", numerator)); + aspect_ratio_text.setArg("[DEN]", llformat("%d", denominator)); + } + else + { + aspect_ratio_text = llformat("%.3f", LLFloaterPreference::sAspectRatio); + } + + LLComboBox* ctrl_aspect_ratio = getChild( "aspect_ratio"); + //mCtrlAspectRatio->setCommitCallback(onSelectAspectRatio, this); + // add default aspect ratios + ctrl_aspect_ratio->add(aspect_ratio_text, &LLFloaterPreference::sAspectRatio, ADD_TOP); + ctrl_aspect_ratio->setCurrentByIndex(0); + + refresh(); + } + + + if(hasChild("user") && hasChild("agent") && hasChild("im") + && hasChild("system") && hasChild("script_error") && hasChild("objects") + && hasChild("owner") && hasChild("background") && hasChild("links")) + { + LLColorSwatchCtrl* color_swatch = getChild("user"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "UserChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("UserChatColor")); + + color_swatch = getChild("agent"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "AgentChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("AgentChatColor")); + + color_swatch = getChild("im"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "IMChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("IMChatColor")); + + color_swatch = getChild("system"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "SystemChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("SystemChatColor")); + + color_swatch = getChild("script_error"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "ScriptErrorColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("ScriptErrorColor")); + + color_swatch = getChild("objects"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "ObjectChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("ObjectChatColor")); + + color_swatch = getChild("owner"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "llOwnerSayChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("llOwnerSayChatColor")); + + color_swatch = getChild("background"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "BackgroundChatColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("BackgroundChatColor")); + + color_swatch = getChild("links"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "HTMLLinkColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("HTMLLinkColor")); + } + + if(hasChild("effect_color_swatch")) + { + LLColorSwatchCtrl* color_swatch = getChild("effect_color_swatch"); + color_swatch->setCommitCallback(boost::bind(&applyUIColor, "EffectColor", _1, _2)); + color_swatch->setOriginal(LLUIColorTable::instance().getColor("EffectColor")); + } + + apply(); + return true; +} + +void LLPanelPreference::apply() +{ + // Save the value of all controls in the hierarchy + mSavedValues.clear(); + std::list view_stack; + view_stack.push_back(this); + while(!view_stack.empty()) + { + // Process view on top of the stack + LLView* curview = view_stack.front(); + view_stack.pop_front(); + + LLColorSwatchCtrl* color_swatch = dynamic_cast(curview); + if (color_swatch) + { + mSavedColors[color_swatch->getName()] = color_swatch->get(); + } + else + { + LLUICtrl* ctrl = dynamic_cast(curview); + if (ctrl) + { + LLControlVariable* control = ctrl->getControlVariable(); + if (control) + { + mSavedValues[control] = control->getValue(); + } + } + } + + // Push children onto the end of the work stack + for (child_list_t::const_iterator iter = curview->getChildList()->begin(); + iter != curview->getChildList()->end(); ++iter) + { + view_stack.push_back(*iter); + } + } + +} + +void LLPanelPreference::cancel() +{ + for (control_values_map_t::iterator iter = mSavedValues.begin(); + iter != mSavedValues.end(); ++iter) + { + LLControlVariable* control = iter->first; + LLSD ctrl_value = iter->second; + control->set(ctrl_value); + } + + for (string_color_map_t::iterator iter = mSavedColors.begin(); + iter != mSavedColors.end(); ++iter) + { + LLColorSwatchCtrl* color_swatch = findChild(iter->first); + if(color_swatch) + { + color_swatch->set(iter->second); + color_swatch->onCommit(); + } + } +} + +void LLPanelPreference::setControlFalse(const LLSD& user_data) +{ + std::string control_name = user_data.asString(); + LLControlVariable* control = findControl(control_name); + + if (control) + control->set(LLSD(FALSE)); +} + diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index f48696ffdb..ce31abcd9e 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -40,94 +40,134 @@ #define LL_LLFLOATERPREFERENCE_H #include "llfloater.h" -#include "lltabcontainervertical.h" -class LLPanelGeneral; -class LLPanelInput; +class LLPanelPreference; class LLPanelLCD; -class LLPanelDisplay; -class LLPanelAudioPrefs; class LLPanelDebug; -class LLPanelNetwork; -class LLPanelWeb; class LLMessageSystem; -class LLPrefsChat; -class LLPrefsVoice; -class LLPrefsIM; -class LLPanelMsgs; -class LLPanelSkins; class LLScrollListCtrl; +class LLSliderCtrl; +class LLSD; +class LLTextBox; -class LLPreferenceCore -{ +typedef enum + { + GS_LOW_GRAPHICS, + GS_MID_GRAPHICS, + GS_HIGH_GRAPHICS, + GS_ULTRA_GRAPHICS + + } EGraphicsSettings; -public: - LLPreferenceCore(LLTabContainer* tab_container, LLButton * default_btn); - ~LLPreferenceCore(); - - void apply(); - void cancel(); - - LLTabContainer* getTabContainer() { return mTabContainer; } - - void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); - - static void onTabChanged(void* user_data, bool from_click); - - // refresh all the graphics preferences menus - void refreshEnabledGraphics(); - -private: - LLTabContainer *mTabContainer; - LLPanelGeneral *mGeneralPanel; - LLPanelSkins *mSkinsPanel; - LLPanelInput *mInputPanel; - LLPanelNetwork *mNetworkPanel; - LLPanelDisplay *mDisplayPanel; - LLPanelAudioPrefs *mAudioPanel; -// LLPanelDebug *mDebugPanel; - LLPrefsChat *mPrefsChat; - LLPrefsVoice *mPrefsVoice; - LLPrefsIM *mPrefsIM; - LLPanelWeb *mWebPanel; - LLPanelMsgs *mMsgPanel; - LLPanelLCD *mLCDPanel; -}; // Floater to control preferences (display, audio, bandwidth, general. class LLFloaterPreference : public LLFloater { public: - LLFloaterPreference(); + LLFloaterPreference(const LLSD& key); ~LLFloaterPreference(); void apply(); void cancel(); + /*virtual*/ void draw(); virtual BOOL postBuild(); - static void show(void*); + virtual void onOpen(const LLSD& key); // static data update, called from message handler static void updateUserInfo(const std::string& visibility, bool im_via_email, const std::string& email); // refresh all the graphics preferences menus static void refreshEnabledGraphics(); - + protected: - LLPreferenceCore *mPreferenceCore; + + void onClose(); + + void onBtnOK(); + void onBtnCancel(); + void onBtnApply(); + void onOpenHelp(); - /*virtual*/ void onClose(bool app_quitting); +// void onClickClearCache(); + void onClickBrowserClearCache(); - LLButton* mAboutBtn; - LLButton *mOKBtn; - LLButton *mCancelBtn; - LLButton *mApplyBtn; + // if the custom settings box is clicked + void onChangeCustom(); + void updateMeterText(LLUICtrl* ctrl); + void onOpenHardwareSettings(); + /// callback for defaults + void setHardwareDefaults(); + // callback for when client turns on shaders + void onVertexShaderEnable(); + - static void onClickAbout(void*); - static void onBtnOK(void*); - static void onBtnCancel(void*); - static void onBtnApply(void*); +public: - static LLFloaterPreference* sInstance; + void onClickSetCache(); + void onClickResetCache(); + void onClickSkin(LLUICtrl* ctrl,const LLSD& userdata); + void onSelectSkin(); + void onClickSetKey(); + void setKey(KEY key); + void onClickSetMiddleMouse(); + void onClickSkipDialogs(); + void onClickResetDialogs(); + void onClickEnablePopup(); + void onClickDisablePopup(); + void resetAllIgnored(); + void setAllIgnored(); + void onClickLogPath(); + void enableHistory(); + void onCommitLogging(); + void setPersonalInfo(const std::string& visibility, bool im_via_email, const std::string& email); + void refreshEnabledState(); + void disableUnavailableSettings(); + void onCommitWindowedMode(); + void refresh(); // Refresh enable/disable + // if the quality radio buttons are changed + void onChangeQuality(const LLSD& data); + + void updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box); + void onUpdateSliderText(LLUICtrl* ctrl, const LLSD& name); + void onKeystrokeAspectRatio(); +// void fractionFromDecimal(F32 decimal_val, S32& numerator, S32& denominator); +// bool extractWindowSizeFromString(const std::string& instr, U32 &width, U32 &height); + + void onCommitAutoDetectAspect(); + void applyResolution(); + void applyWindowSize(); + + static void initWindowSizeControls(LLPanel* panelp); + + static void buildLists(void* data); + static void refreshSkin(void* data); + static void cleanupBadSetting(); + static F32 sAspectRatio; +private: + static std::string sSkin; + bool mGotPersonalInfo; + bool mOriginalIMViaEmail; + + bool mOriginalHideOnlineStatus; + std::string mDirectoryVisibility; + +}; + +class LLPanelPreference : public LLPanel +{ +public: + LLPanelPreference(); + /*virtual*/ BOOL postBuild(); + + virtual void apply(); + virtual void cancel(); + void setControlFalse(const LLSD& user_data); +private: + typedef std::map control_values_map_t; + control_values_map_t mSavedValues; + + typedef std::map string_color_map_t; + string_color_map_t mSavedColors; }; #endif // LL_LLPREFERENCEFLOATER_H diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 406d940cf0..091debe95e 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -37,25 +37,29 @@ #include #include "llcachename.h" #include "lldbstrings.h" +#include "llfloaterreg.h" #include "llinventory.h" #include "llagent.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llfloateravatarinfo.h" -#include "llfloatergroupinfo.h" +#include "llavataractions.h" #include "llinventorymodel.h" #include "lllineeditor.h" +//#include "llspinctrl.h" #include "llradiogroup.h" #include "llresmgr.h" #include "roles_constants.h" #include "llselectmgr.h" #include "lltextbox.h" +#include "lltrans.h" #include "lluiconstants.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llgroupactions.h" #include "lluictrlfactory.h" @@ -73,7 +77,8 @@ class LLPropertiesObserver : public LLInventoryObserver { public: - LLPropertiesObserver() + LLPropertiesObserver(LLFloaterProperties* floater) + : mFloater(floater) { gInventory.addObserver(this); } @@ -82,6 +87,8 @@ public: gInventory.removeObserver(this); } virtual void changed(U32 mask); +private: + LLFloaterProperties* mFloater; }; void LLPropertiesObserver::changed(U32 mask) @@ -89,7 +96,7 @@ void LLPropertiesObserver::changed(U32 mask) // if there's a change we're interested in. if((mask & (LLInventoryObserver::LABEL | LLInventoryObserver::INTERNAL | LLInventoryObserver::REMOVE)) != 0) { - LLFloaterProperties::dirtyAll(); + mFloater->dirty(); } } @@ -99,120 +106,63 @@ void LLPropertiesObserver::changed(U32 mask) /// Class LLFloaterProperties ///---------------------------------------------------------------------------- -// static -LLFloaterProperties::instance_map LLFloaterProperties::sInstances; -LLPropertiesObserver* LLFloaterProperties::sPropertiesObserver = NULL; -S32 LLFloaterProperties::sPropertiesObserverCount = 0; - -// static -LLFloaterProperties* LLFloaterProperties::find(const LLUUID& item_id, - const LLUUID& object_id) -{ - // for simplicity's sake, we key the properties window with a - // single uuid. However, the items are keyed by item and object - // (obj == null -> agent inventory). So, we xor the two ids, and - // use that as a lookup key - instance_map::iterator it = sInstances.find(item_id ^ object_id); - if(it != sInstances.end()) - { - return (*it).second; - } - return NULL; -} - -// static -LLFloaterProperties* LLFloaterProperties::show(const LLUUID& item_id, - const LLUUID& object_id) -{ - LLFloaterProperties* instance = find(item_id, object_id); - if(instance) - { - if (LLFloater::getFloaterHost() && LLFloater::getFloaterHost() != instance->getHost()) - { - // this properties window is being opened in a new context - // needs to be rehosted - LLFloater::getFloaterHost()->addFloater(instance, TRUE); - } - - instance->refresh(); - instance->open(); /* Flawfinder: ignore */ - } - return instance; -} - -void LLFloaterProperties::dirtyAll() -{ - // ...this is more clear. Possibly more correct, because the - // refresh method may delete the object. - for(instance_map::iterator it = sInstances.begin(); it!=sInstances.end(); ) - { - (*it++).second->dirty(); - } -} - // Default constructor -LLFloaterProperties::LLFloaterProperties(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_id, const LLUUID& object_id) : - LLFloater(name, rect, title), +LLFloaterProperties::LLFloaterProperties(const LLUUID& item_id) + : LLFloater(mItemID), mItemID(item_id), - mObjectID(object_id), mDirty(TRUE) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_inventory_item_properties.xml"); - - if (!sPropertiesObserver) - { - sPropertiesObserver = new LLPropertiesObserver; - } - sPropertiesObserverCount++; + mPropertiesObserver = new LLPropertiesObserver(this); - // add the object to the static structure - LLUUID key = mItemID ^ mObjectID; - sInstances.insert(instance_map::value_type(key, this)); - // build the UI - // item name & description - childSetPrevalidate("LabelItemName",&LLLineEditor::prevalidatePrintableNotPipe); - childSetCommitCallback("LabelItemName",onCommitName,this); - childSetPrevalidate("LabelItemDesc",&LLLineEditor::prevalidatePrintableNotPipe); - childSetCommitCallback("LabelItemDesc", onCommitDescription, this); - // Creator information - childSetAction("BtnCreator",onClickCreator,this); - // owner information - childSetAction("BtnOwner",onClickOwner,this); - // acquired date - // owner permissions - // Permissions debug text - // group permissions - childSetCommitCallback("CheckShareWithGroup",&onCommitPermissions, this); - // everyone permissions - childSetCommitCallback("CheckEveryoneCopy",&onCommitPermissions, this); - // next owner permissions - childSetCommitCallback("CheckNextOwnerModify",&onCommitPermissions, this); - childSetCommitCallback("CheckNextOwnerCopy",&onCommitPermissions, this); - childSetCommitCallback("CheckNextOwnerTransfer",&onCommitPermissions, this); - // Mark for sale or not, and sale info - childSetCommitCallback("CheckPurchase",&onCommitSaleInfo, this); - childSetCommitCallback("RadioSaleType",&onCommitSaleType, this); - // "Price" label for edit - childSetCommitCallback("EditPrice",&onCommitSaleInfo, this); - // The UI has been built, now fill in all the values - refresh(); + //LLUICtrlFactory::getInstance()->buildFloater(this,"floater_inventory_item_properties.xml"); } // Destroys the object LLFloaterProperties::~LLFloaterProperties() { - // clean up the static data. - instance_map::iterator it = sInstances.find(mItemID ^ mObjectID); - if(it != sInstances.end()) - { - sInstances.erase(it); - } - sPropertiesObserverCount--; - if (!sPropertiesObserverCount) - { - delete sPropertiesObserver; - sPropertiesObserver = NULL; - } + delete mPropertiesObserver; + mPropertiesObserver = NULL; +} + +// virtual +BOOL LLFloaterProperties::postBuild() +{ + // build the UI + // item name & description + childSetPrevalidate("LabelItemName",&LLLineEditor::prevalidatePrintableNotPipe); + getChild("LabelItemName")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitName,this)); + childSetPrevalidate("LabelItemDesc",&LLLineEditor::prevalidatePrintableNotPipe); + getChild("LabelItemDesc")->setCommitCallback(boost::bind(&LLFloaterProperties:: onCommitDescription, this)); + // Creator information + getChild("BtnCreator")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickCreator,this)); + // owner information + getChild("BtnOwner")->setCommitCallback(boost::bind(&LLFloaterProperties::onClickOwner,this)); + // acquired date + // owner permissions + // Permissions debug text + // group permissions + getChild("CheckShareWithGroup")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this)); + // everyone permissions + getChild("CheckEveryoneCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this)); + // next owner permissions + getChild("CheckNextOwnerModify")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this)); + getChild("CheckNextOwnerCopy")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this)); + getChild("CheckNextOwnerTransfer")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitPermissions, this)); + // Mark for sale or not, and sale info + getChild("CheckPurchase")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this)); + getChild("RadioSaleType")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleType, this)); + // "Price" label for edit + getChild("Edit Cost")->setCommitCallback(boost::bind(&LLFloaterProperties::onCommitSaleInfo, this)); + // The UI has been built, now fill in all the values + refresh(); + + return TRUE; +} + +// virtual +void LLFloaterProperties::onOpen(const LLSD& key) +{ + refresh(); } void LLFloaterProperties::refresh() @@ -246,7 +196,7 @@ void LLFloaterProperties::refresh() "CheckNextOwnerTransfer", "CheckPurchase", "RadioSaleType", - "EditPrice" + "Edit Cost" }; for(size_t t=0; tisComplete(); - + const BOOL cannot_restrict_permissions = LLInventoryType::cannotRestrictPermissions(i->getInventoryType()); + const BOOL is_calling_card = (i->getInventoryType() == LLInventoryType::IT_CALLINGCARD); const LLPermissions& perm = item->getPermissions(); - BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, - GP_OBJECT_MANIPULATE); - BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, - GP_OBJECT_SET_SALE); + const BOOL can_agent_manipulate = gAgent.allowOperation(PERM_OWNER, perm, + GP_OBJECT_MANIPULATE); + const BOOL can_agent_sell = gAgent.allowOperation(PERM_OWNER, perm, + GP_OBJECT_SET_SALE) && + !cannot_restrict_permissions; + const BOOL is_link = i->getIsLinkType(); // You need permission to modify the object to modify an inventory // item in it. @@ -308,11 +261,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) // ITEM NAME & DESC // ////////////////////// BOOL is_modifiable = gAgent.allowOperation(PERM_MODIFY, perm, - GP_OBJECT_MANIPULATE) - && is_obj_modify && is_complete; + GP_OBJECT_MANIPULATE) + && is_obj_modify && is_complete; childSetEnabled("LabelItemNameTitle",TRUE); - childSetEnabled("LabelItemName",is_modifiable); + childSetEnabled("LabelItemName",is_modifiable && !is_calling_card); // for now, don't allow rename of calling cards childSetText("LabelItemName",item->getName()); childSetEnabled("LabelItemDescTitle",TRUE); childSetEnabled("LabelItemDesc",is_modifiable); @@ -372,8 +325,7 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) ////////////////// // ACQUIRE DATE // ////////////////// - - // *TODO: Localize / translate this + time_t time_utc = item->getCreationDate(); if (0 == time_utc) { @@ -381,7 +333,11 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) } else { - childSetText("LabelAcquiredDate", std::string(ctime(&time_utc)) ); + std::string timeStr = getString("acquiredDate"); + LLSD substitution; + substitution["datetime"] = (S32) time_utc; + LLStringUtil::format (timeStr, substitution); + childSetText ("LabelAcquiredDate", timeStr); } /////////////////////// @@ -472,7 +428,12 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) ///////////// // Check for ability to change values. - if (is_obj_modify && can_agent_manipulate) + if (is_link || cannot_restrict_permissions) + { + childSetEnabled("CheckShareWithGroup",FALSE); + childSetEnabled("CheckEveryoneCopy",FALSE); + } + else if (is_obj_modify && can_agent_manipulate) { childSetEnabled("CheckShareWithGroup",TRUE); childSetEnabled("CheckEveryoneCopy",(owner_mask & PERM_COPY) && (owner_mask & PERM_TRANSFER)); @@ -533,13 +494,13 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) childSetEnabled("CheckPurchase",is_complete); childSetEnabled("NextOwnerLabel",TRUE); - childSetEnabled("CheckNextOwnerModify",base_mask & PERM_MODIFY); - childSetEnabled("CheckNextOwnerCopy",base_mask & PERM_COPY); - childSetEnabled("CheckNextOwnerTransfer",next_owner_mask & PERM_COPY); + childSetEnabled("CheckNextOwnerModify",(base_mask & PERM_MODIFY) && !cannot_restrict_permissions); + childSetEnabled("CheckNextOwnerCopy",(base_mask & PERM_COPY) && !cannot_restrict_permissions); + childSetEnabled("CheckNextOwnerTransfer",(next_owner_mask & PERM_COPY) && !cannot_restrict_permissions); childSetEnabled("RadioSaleType",is_complete && is_for_sale); childSetEnabled("TextPrice",is_complete && is_for_sale); - childSetEnabled("EditPrice",is_complete && is_for_sale); + childSetEnabled("Edit Cost",is_complete && is_for_sale); } else { @@ -553,11 +514,13 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) childSetEnabled("RadioSaleType",FALSE); childSetEnabled("TextPrice",FALSE); - childSetEnabled("EditPrice",FALSE); + childSetEnabled("Edit Cost",FALSE); } // Set values. childSetValue("CheckPurchase", is_for_sale); + childSetEnabled("combobox sale copy", is_for_sale); + childSetEnabled("Edit Cost", is_for_sale); childSetValue("CheckNextOwnerModify",LLSD(BOOL(next_owner_mask & PERM_MODIFY))); childSetValue("CheckNextOwnerCopy",LLSD(BOOL(next_owner_mask & PERM_COPY))); childSetValue("CheckNextOwnerTransfer",LLSD(BOOL(next_owner_mask & PERM_TRANSFER))); @@ -568,63 +531,50 @@ void LLFloaterProperties::refreshFromItem(LLInventoryItem* item) radioSaleType->setSelectedIndex((S32)sale_info.getSaleType() - 1); S32 numerical_price; numerical_price = sale_info.getSalePrice(); - childSetText("EditPrice",llformat("%d",numerical_price)); + childSetText("Edit Cost",llformat("%d",numerical_price)); } else { radioSaleType->setSelectedIndex(-1); - childSetText("EditPrice",llformat("%d",0)); + childSetText("Edit Cost",llformat("%d",0)); } } -// static -void LLFloaterProperties::onClickCreator(void* data) +void LLFloaterProperties::onClickCreator() { - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - LLInventoryItem* item = self->findItem(); + LLInventoryItem* item = findItem(); if(!item) return; if(!item->getCreatorUUID().isNull()) { - LLFloaterAvatarInfo::showFromObject(item->getCreatorUUID()); + LLAvatarActions::showProfile(item->getCreatorUUID()); } } // static -void LLFloaterProperties::onClickOwner(void* data) +void LLFloaterProperties::onClickOwner() { - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - LLInventoryItem* item = self->findItem(); + LLInventoryItem* item = findItem(); if(!item) return; if(item->getPermissions().isGroupOwned()) { - LLFloaterGroupInfo::showFromUUID(item->getPermissions().getGroup()); + LLGroupActions::show(item->getPermissions().getGroup()); } else { - if(!item->getPermissions().getOwner().isNull()) - { - LLFloaterAvatarInfo::showFromObject(item->getPermissions().getOwner()); - } + LLAvatarActions::showProfile(item->getPermissions().getOwner()); } } // static -void LLFloaterProperties::onCommitName(LLUICtrl* ctrl, void* data) +void LLFloaterProperties::onCommitName() { //llinfos << "LLFloaterProperties::onCommitName()" << llendl; - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) - { - return; - } - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->findItem(); + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) { return; } - LLLineEditor* labelItemName = self->getChild("LabelItemName"); + LLLineEditor* labelItemName = getChild("LabelItemName"); if(labelItemName&& (item->getName() != labelItemName->getText()) && @@ -632,15 +582,16 @@ void LLFloaterProperties::onCommitName(LLUICtrl* ctrl, void* data) { LLPointer new_item = new LLViewerInventoryItem(item); new_item->rename(labelItemName->getText()); - if(self->mObjectID.isNull()) + if(mObjectID.isNull()) { new_item->updateServer(FALSE); gInventory.updateItem(new_item); + gInventory.updateLinkedObjects(new_item->getUUID()); gInventory.notifyObservers(); } else { - LLViewerObject* object = gObjectList.findObject(self->mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectID); if(object) { object->updateInventory( @@ -652,16 +603,13 @@ void LLFloaterProperties::onCommitName(LLUICtrl* ctrl, void* data) } } -// static -void LLFloaterProperties::onCommitDescription(LLUICtrl* ctrl, void* data) +void LLFloaterProperties::onCommitDescription() { //llinfos << "LLFloaterProperties::onCommitDescription()" << llendl; - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->findItem(); + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) return; - LLLineEditor* labelItemDesc = self->getChild("LabelItemDesc"); + LLLineEditor* labelItemDesc = getChild("LabelItemDesc"); if(!labelItemDesc) { return; @@ -672,7 +620,7 @@ void LLFloaterProperties::onCommitDescription(LLUICtrl* ctrl, void* data) LLPointer new_item = new LLViewerInventoryItem(item); new_item->setDescription(labelItemDesc->getText()); - if(self->mObjectID.isNull()) + if(mObjectID.isNull()) { new_item->updateServer(FALSE); gInventory.updateItem(new_item); @@ -680,7 +628,7 @@ void LLFloaterProperties::onCommitDescription(LLUICtrl* ctrl, void* data) } else { - LLViewerObject* object = gObjectList.findObject(self->mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectID); if(object) { object->updateInventory( @@ -693,17 +641,15 @@ void LLFloaterProperties::onCommitDescription(LLUICtrl* ctrl, void* data) } // static -void LLFloaterProperties::onCommitPermissions(LLUICtrl* ctrl, void* data) +void LLFloaterProperties::onCommitPermissions() { //llinfos << "LLFloaterProperties::onCommitPermissions()" << llendl; - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->findItem(); + LLViewerInventoryItem* item = (LLViewerInventoryItem*)findItem(); if(!item) return; LLPermissions perm(item->getPermissions()); - LLCheckBoxCtrl* CheckShareWithGroup = self->getChild("CheckShareWithGroup"); + LLCheckBoxCtrl* CheckShareWithGroup = getChild("CheckShareWithGroup"); if(CheckShareWithGroup) { @@ -711,26 +657,26 @@ void LLFloaterProperties::onCommitPermissions(LLUICtrl* ctrl, void* data) CheckShareWithGroup->get(), PERM_MODIFY | PERM_MOVE | PERM_COPY); } - LLCheckBoxCtrl* CheckEveryoneCopy = self->getChild("CheckEveryoneCopy"); + LLCheckBoxCtrl* CheckEveryoneCopy = getChild("CheckEveryoneCopy"); if(CheckEveryoneCopy) { perm.setEveryoneBits(gAgent.getID(), gAgent.getGroupID(), CheckEveryoneCopy->get(), PERM_COPY); } - LLCheckBoxCtrl* CheckNextOwnerModify = self->getChild("CheckNextOwnerModify"); + LLCheckBoxCtrl* CheckNextOwnerModify = getChild("CheckNextOwnerModify"); if(CheckNextOwnerModify) { perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), CheckNextOwnerModify->get(), PERM_MODIFY); } - LLCheckBoxCtrl* CheckNextOwnerCopy = self->getChild("CheckNextOwnerCopy"); + LLCheckBoxCtrl* CheckNextOwnerCopy = getChild("CheckNextOwnerCopy"); if(CheckNextOwnerCopy) { perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), CheckNextOwnerCopy->get(), PERM_COPY); } - LLCheckBoxCtrl* CheckNextOwnerTransfer = self->getChild("CheckNextOwnerTransfer"); + LLCheckBoxCtrl* CheckNextOwnerTransfer = getChild("CheckNextOwnerTransfer"); if(CheckNextOwnerTransfer) { perm.setNextOwnerBits(gAgent.getID(), gAgent.getGroupID(), @@ -766,7 +712,7 @@ void LLFloaterProperties::onCommitPermissions(LLUICtrl* ctrl, void* data) flags |= LLInventoryItem::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP; } new_item->setFlags(flags); - if(self->mObjectID.isNull()) + if(mObjectID.isNull()) { new_item->updateServer(FALSE); gInventory.updateItem(new_item); @@ -774,7 +720,7 @@ void LLFloaterProperties::onCommitPermissions(LLUICtrl* ctrl, void* data) } else { - LLViewerObject* object = gObjectList.findObject(self->mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectID); if(object) { object->updateInventory( @@ -787,26 +733,22 @@ void LLFloaterProperties::onCommitPermissions(LLUICtrl* ctrl, void* data) else { // need to make sure we don't just follow the click - self->refresh(); + refresh(); } } // static -void LLFloaterProperties::onCommitSaleInfo(LLUICtrl* ctrl, void* data) +void LLFloaterProperties::onCommitSaleInfo() { //llinfos << "LLFloaterProperties::onCommitSaleInfo()" << llendl; - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - self->updateSaleInfo(); + updateSaleInfo(); } // static -void LLFloaterProperties::onCommitSaleType(LLUICtrl* ctrl, void* data) +void LLFloaterProperties::onCommitSaleType() { //llinfos << "LLFloaterProperties::onCommitSaleType()" << llendl; - LLFloaterProperties* self = (LLFloaterProperties*)data; - if(!self) return; - self->updateSaleInfo(); + updateSaleInfo(); } void LLFloaterProperties::updateSaleInfo() @@ -851,13 +793,11 @@ void LLFloaterProperties::updateSaleInfo() sale_type = LLSaleInfo::FS_ORIGINAL; } - LLLineEditor* EditPrice = getChild("EditPrice"); + S32 price = -1; - if(EditPrice) - { - price = atoi(EditPrice->getText().c_str()); - } + price = getChild("Edit Cost")->getValue().asInteger();; + // Invalid data - turn off the sale if (price < 0) { @@ -932,13 +872,15 @@ LLInventoryItem* LLFloaterProperties::findItem() const return item; } -void LLFloaterProperties::closeByID(const LLUUID& item_id, const LLUUID &object_id) +//static +void LLFloaterProperties::dirtyAll() { - LLFloaterProperties* floaterp = find(item_id, object_id); - - if (floaterp) + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("properties"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); + iter != inst_list.end(); ++iter) { - floaterp->close(); + LLFloaterProperties* floater = dynamic_cast(*iter); + floater->dirty(); } } @@ -946,8 +888,24 @@ void LLFloaterProperties::closeByID(const LLUUID& item_id, const LLUUID &object_ /// LLMultiProperties ///---------------------------------------------------------------------------- -LLMultiProperties::LLMultiProperties(const LLRect &rect) : LLMultiFloater(std::string("Properties"), rect) +LLMultiProperties::LLMultiProperties() + : LLMultiFloater(LLSD()) { + // *TODO: There should be a .xml file for this + const LLRect& nextrect = LLFloaterReg::getFloaterRect("properties"); // place where the next properties should show up + if (nextrect.getWidth() > 0) + { + setRect(nextrect); + } + else + { + // start with a small rect in the top-left corner ; will get resized + LLRect rect; + rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeight(), 20, 20); + setRect(rect); + } + setTitle(LLTrans::getString("MultiPropertiesTitle")); + buildTabContainer(); } ///---------------------------------------------------------------------------- diff --git a/indra/newview/llfloaterproperties.h b/indra/newview/llfloaterproperties.h index 2f5d97d384..586719a4dc 100644 --- a/indra/newview/llfloaterproperties.h +++ b/indra/newview/llfloaterproperties.h @@ -34,7 +34,7 @@ #define LL_LLFLOATERPROPERTIES_H #include -#include "llfloater.h" +#include "llmultifloater.h" #include "lliconctrl.h" //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -53,30 +53,27 @@ class LLPropertiesObserver; class LLFloaterProperties : public LLFloater { public: - static LLFloaterProperties* find(const LLUUID& item_id, - const LLUUID& object_id); - static LLFloaterProperties* show(const LLUUID& item_id, - const LLUUID& object_id); - static void dirtyAll(); + LLFloaterProperties(const LLUUID& item_id); + /*virtual*/ ~LLFloaterProperties(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + void setObjectID(const LLUUID& object_id) { mObjectID = object_id; } - static void closeByID(const LLUUID& item_id, const LLUUID& object_id); - - LLFloaterProperties(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_id, const LLUUID& object_id); - virtual ~LLFloaterProperties(); - - // do everything necessary void dirty() { mDirty = TRUE; } void refresh(); - + + static void dirtyAll(); + protected: // ui callbacks - static void onClickCreator(void* data); - static void onClickOwner(void* data); - static void onCommitName(LLUICtrl* ctrl, void* data); - static void onCommitDescription(LLUICtrl* ctrl, void* data); - static void onCommitPermissions(LLUICtrl* ctrl, void* data); - static void onCommitSaleInfo(LLUICtrl* ctrl, void* data); - static void onCommitSaleType(LLUICtrl* ctrl, void* data); + void onClickCreator(); + void onClickOwner(); + void onCommitName(); + void onCommitDescription(); + void onCommitPermissions(); + void onCommitSaleInfo(); + void onCommitSaleType(); void updateSaleInfo(); LLInventoryItem* findItem() const; @@ -93,18 +90,15 @@ protected: // inventory. LLUUID mObjectID; - BOOL mDirty; + BOOL mDirty; - typedef std::map instance_map; - static instance_map sInstances; - static LLPropertiesObserver* sPropertiesObserver; - static S32 sPropertiesObserverCount; + LLPropertiesObserver* mPropertiesObserver; }; class LLMultiProperties : public LLMultiFloater { public: - LLMultiProperties(const LLRect& rect); + LLMultiProperties(); }; #endif // LL_LLFLOATERPROPERTIES_H diff --git a/indra/newview/llfloaterregioninfo.cpp b/indra/newview/llfloaterregioninfo.cpp index 9d6c26d834..10276ba36d 100644 --- a/indra/newview/llfloaterregioninfo.cpp +++ b/indra/newview/llfloaterregioninfo.cpp @@ -58,12 +58,14 @@ #include "llfloatergodtools.h" // for send_sim_wide_deletes() #include "llfloatertopobjects.h" // added to fix SL-32336 #include "llfloatergroups.h" +#include "llfloaterreg.h" #include "llfloatertelehub.h" #include "llfloaterwindlight.h" #include "llinventorymodel.h" #include "lllineeditor.h" #include "llalertdialog.h" #include "llnamelistctrl.h" +#include "llscrolllistitem.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "lltabcontainer.h" @@ -73,13 +75,16 @@ #include "lltrans.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewerinventory.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewertexteditor.h" #include "llviewerwindow.h" #include "llvlcomposition.h" +#include "lltrans.h" +#include "llagentui.h" #define ELAR_ENABLED 0 // Enable when server support is implemented @@ -161,8 +166,9 @@ bool estate_dispatch_initialized = false; LLUUID LLFloaterRegionInfo::sRequestInvoice; LLFloaterRegionInfo::LLFloaterRegionInfo(const LLSD& seed) + : LLFloater(seed) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_info.xml", NULL, FALSE); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_region_info.xml", FALSE); } BOOL LLFloaterRegionInfo::postBuild() @@ -174,32 +180,32 @@ BOOL LLFloaterRegionInfo::postBuild() panel = new LLPanelRegionGeneralInfo; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_general.xml"); - mTab->addTabPanel(panel, panel->getLabel(), TRUE); + mTab->addTabPanel(LLTabContainer::TabPanelParams().panel(panel).select_tab(true)); panel = new LLPanelRegionDebugInfo; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_debug.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); + mTab->addTabPanel(panel); panel = new LLPanelRegionTextureInfo; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_texture.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); + mTab->addTabPanel(panel); panel = new LLPanelRegionTerrainInfo; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_terrain.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); + mTab->addTabPanel(panel); panel = new LLPanelEstateInfo; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_estate.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); + mTab->addTabPanel(panel); panel = new LLPanelEstateCovenant; mInfoPanels.push_back(panel); LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_region_covenant.xml"); - mTab->addTabPanel(panel, panel->getLabel(), FALSE); + mTab->addTabPanel(panel); gMessageSystem->setHandlerFunc( "EstateOwnerMessage", @@ -212,22 +218,16 @@ LLFloaterRegionInfo::~LLFloaterRegionInfo() { } -void LLFloaterRegionInfo::onOpen() +void LLFloaterRegionInfo::onOpen(const LLSD& key) { - LLRect rect = gSavedSettings.getRect("FloaterRegionInfo"); - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - rect.translate(left,top); - refreshFromRegion(gAgent.getRegion()); requestRegionInfo(); - LLFloater::onOpen(); } // static void LLFloaterRegionInfo::requestRegionInfo() { - LLTabContainer* tab = findInstance()->getChild("region_panels"); + LLTabContainer* tab = getChild("region_panels"); tab->getChild("General")->setCtrlsEnabled(FALSE); tab->getChild("Debug")->setCtrlsEnabled(FALSE); @@ -249,7 +249,8 @@ void LLFloaterRegionInfo::requestRegionInfo() void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) { static LLDispatcher dispatch; - if(!findInstance()) + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); + if(!floater) { return; } @@ -259,7 +260,7 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) LLPanelEstateInfo::initDispatch(dispatch); } - LLTabContainer* tab = findInstance()->getChild("region_panels"); + LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); // unpack the message @@ -285,14 +286,14 @@ void LLFloaterRegionInfo::processEstateOwnerRequest(LLMessageSystem* msg,void**) void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) { LLPanel* panel; - + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); llinfos << "LLFloaterRegionInfo::processRegionInfo" << llendl; - if(!findInstance()) + if(!floater) { return; } - LLTabContainer* tab = findInstance()->getChild("region_panels"); + LLTabContainer* tab = floater->getChild("region_panels"); LLViewerRegion* region = gAgent.getRegion(); BOOL allow_modify = gAgent.isGodlike() || (region && region->canManageEstate()); @@ -379,13 +380,13 @@ void LLFloaterRegionInfo::processRegionInfo(LLMessageSystem* msg) panel->childSetEnabled("sun_hour_slider", allow_modify && !use_estate_sun); panel->setCtrlsEnabled(allow_modify); - getInstance()->refreshFromRegion( gAgent.getRegion() ); + floater->refreshFromRegion( gAgent.getRegion() ); } // static LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() { - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); if (!floater) return NULL; LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateInfo* panel = (LLPanelEstateInfo*)tab->getChild("Estate"); @@ -395,7 +396,7 @@ LLPanelEstateInfo* LLFloaterRegionInfo::getPanelEstate() // static LLPanelEstateCovenant* LLFloaterRegionInfo::getPanelCovenant() { - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); if (!floater) return NULL; LLTabContainer* tab = floater->getChild("region_panels"); LLPanelEstateCovenant* panel = (LLPanelEstateCovenant*)tab->getChild("Covenant"); @@ -436,6 +437,11 @@ void LLFloaterRegionInfo::refresh() // LLPanelRegionInfo // +LLPanelRegionInfo::LLPanelRegionInfo() + : LLPanel() +{ +} + // static void LLPanelRegionInfo::onBtnSet(void* user_data) { @@ -608,7 +614,8 @@ BOOL LLPanelRegionGeneralInfo::postBuild() childSetAction("kick_btn", onClickKick, this); childSetAction("kick_all_btn", onClickKickAll, this); childSetAction("im_btn", onClickMessage, this); - childSetAction("manage_telehub_btn", onClickManageTelehub, this); +// childSetAction("manage_telehub_btn", onClickManageTelehub, this); + mCommitCallbackRegistrar.add("RegionInfo.Cancel", boost::bind(&LLPanelRegionGeneralInfo::onClickManageTelehub, this)); return LLPanelRegionInfo::postBuild(); } @@ -708,7 +715,7 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L gAgent.getID().toString(buffer); strings.push_back(buffer); std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); strings.push_back(strings_t::value_type(name)); strings.push_back(strings_t::value_type(text)); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); @@ -716,12 +723,10 @@ bool LLPanelRegionGeneralInfo::onMessageCommit(const LLSD& notification, const L return false; } -// static -void LLPanelRegionGeneralInfo::onClickManageTelehub(void* data) +void LLPanelRegionGeneralInfo::onClickManageTelehub() { - LLFloaterRegionInfo::getInstance()->close(); - - LLFloaterTelehub::show(); + LLFloaterReg::hideInstance("region_info"); + LLFloaterReg::showInstance("telehubs"); } // setregioninfo @@ -955,8 +960,10 @@ void LLPanelRegionDebugInfo::onClickTopColliders(void* data) strings_t strings; strings.push_back("1"); // one physics step LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - LLFloaterTopObjects::show(); - LLFloaterTopObjects::clearList(); + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; + LLFloaterReg::showInstance("top_objects"); + instance->clearList(); self->sendEstateOwnerMessage(gMessageSystem, "colliders", invoice, strings); } @@ -967,8 +974,10 @@ void LLPanelRegionDebugInfo::onClickTopScripts(void* data) strings_t strings; strings.push_back("6"); // top 5 scripts LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); - LLFloaterTopObjects::show(); - LLFloaterTopObjects::clearList(); + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; + LLFloaterReg::showInstance("top_objects"); + instance->clearList(); self->sendEstateOwnerMessage(gMessageSystem, "scripts", invoice, strings); } @@ -1074,7 +1083,7 @@ BOOL LLPanelRegionTextureInfo::postBuild() initCtrl(buffer); } -// LLButton* btn = new LLButton("dump", LLRect(0, 20, 100, 0), "", onClickDump, this); +// LLButton* btn = ("dump", LLRect(0, 20, 100, 0), "", onClickDump, this); // btn->setFollows(FOLLOWS_TOP|FOLLOWS_LEFT); // addChild(btn); @@ -1136,11 +1145,11 @@ BOOL LLPanelRegionTextureInfo::validateTextureSizes() if (!texture_ctrl) continue; LLUUID image_asset_id = texture_ctrl->getImageAssetID(); - LLViewerImage* img = gImageList.getImage(image_asset_id); + LLViewerTexture* img = LLViewerTextureManager::getFetchedTexture(image_asset_id); S32 components = img->getComponents(); // Must ask for highest resolution version's width. JC - S32 width = img->getWidth(0); - S32 height = img->getHeight(0); + S32 width = img->getFullWidth(); + S32 height = img->getFullHeight(); //llinfos << "texture detail " << i << " is " << width << "x" << height << "x" << components << llendl; @@ -1251,7 +1260,7 @@ BOOL LLPanelRegionTerrainInfo::sendUpdate() // Grab estate information in case the user decided to set the // region back to estate time. JC - LLFloaterRegionInfo* floater = LLFloaterRegionInfo::getInstance(); + LLFloaterRegionInfo* floater = LLFloaterReg::getTypedInstance("region_info"); if (!floater) return true; LLTabContainer* tab = floater->getChild("region_panels"); @@ -1363,9 +1372,10 @@ void LLPanelRegionTerrainInfo::onClickUploadRaw(void* data) // static void LLPanelRegionTerrainInfo::onClickBakeTerrain(void* data) { - LLNotifications::instance().add( - LLNotification::Params("ConfirmBakeTerrain") - .functor(boost::bind(&LLPanelRegionTerrainInfo::callbackBakeTerrain, (LLPanelRegionTerrainInfo*)data, _1, _2))); + LLNotification::Params::Functor functor_params; + functor_params.function(boost::bind(&LLPanelRegionTerrainInfo::callbackBakeTerrain, (LLPanelRegionTerrainInfo*)data, _1, _2)); + + LLNotifications::instance().add(LLNotification::Params("ConfirmBakeTerrain").functor(functor_params)); } bool LLPanelRegionTerrainInfo::callbackBakeTerrain(const LLSD& notification, const LLSD& response) @@ -1446,12 +1456,12 @@ void LLPanelEstateInfo::onChangeFixedSun(LLUICtrl* ctrl, void* user_data) //--------------------------------------------------------------------------- void LLPanelEstateInfo::onClickEditSky(void* user_data) { - LLFloaterWindLight::show(); + LLFloaterReg::showInstance("env_windlight"); } void LLPanelEstateInfo::onClickEditDayCycle(void* user_data) { - LLFloaterDayCycle::show(); + LLFloaterReg::showInstance("env_day_cycle"); } // static @@ -1478,11 +1488,9 @@ void LLPanelEstateInfo::onClickRemoveAllowedAgent(void* user_data) accessRemoveCore(ESTATE_ACCESS_ALLOWED_AGENT_REMOVE, "EstateAllowedAgentRemove", "allowed_avatar_name_list"); } -// static -void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data) +void LLPanelEstateInfo::onClickAddAllowedGroup() { - LLPanelEstateInfo* self = (LLPanelEstateInfo*)user_data; - LLCtrlListInterface *list = self->childGetListInterface("allowed_group_name_list"); + LLCtrlListInterface *list = childGetListInterface("allowed_group_name_list"); if (!list) return; if (list->getItemCount() >= ESTATE_MAX_ACCESS_IDS) { @@ -1493,7 +1501,7 @@ void LLPanelEstateInfo::onClickAddAllowedGroup(void* user_data) } LLNotification::Params params("ChangeLindenAccess"); - params.functor(boost::bind(&LLPanelEstateInfo::addAllowedGroup, self, _1, _2)); + params.functor.function(boost::bind(&LLPanelEstateInfo::addAllowedGroup, this, _1, _2)); if (isLindenEstate()) { LLNotifications::instance().add(params); @@ -1511,11 +1519,10 @@ bool LLPanelEstateInfo::addAllowedGroup(const LLSD& notification, const LLSD& re LLFloater* parent_floater = gFloaterView->getParentFloater(this); - LLFloaterGroupPicker* widget; - widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); + LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance("group_picker", LLSD(gAgent.getID())); if (widget) { - widget->setSelectCallback(addAllowedGroup2, NULL); + widget->setSelectGroupCallback(boost::bind(&LLPanelEstateInfo::addAllowedGroup2, this, _1)); if (parent_floater) { LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, widget); @@ -1656,26 +1663,29 @@ bool LLPanelEstateInfo::kickUserConfirm(const LLSD& notification, const LLSD& re std::string all_estates_text() { LLPanelEstateInfo* panel = LLFloaterRegionInfo::getPanelEstate(); - if (!panel) return "(error)"; + if (!panel) return "(" + LLTrans::getString("RegionInfoError") + ")"; + LLStringUtil::format_map_t args; std::string owner = panel->getOwnerName(); LLViewerRegion* region = gAgent.getRegion(); if (gAgent.isGodlike()) { - return llformat("all estates\nowned by %s", owner.c_str()); + args["[OWNER]"] = owner.c_str(); + return LLTrans::getString("RegionInfoAllEstatesOwnedBy", args); } else if (region && region->getOwner() == gAgent.getID()) { - return "all estates you own"; + return LLTrans::getString("AllEstatesYouOwn"); } else if (region && region->isEstateManager()) { - return llformat("all estates that\nyou manage for %s", owner.c_str()); + args["[OWNER]"] = owner.c_str(); + return LLTrans::getString("RegionInfoAllEstatesYouManage", args); } else { - return "(error)"; + return "(" + LLTrans::getString("RegionInfoError") + ")"; } } @@ -1725,8 +1735,7 @@ struct LLEstateAccessChangeInfo }; // Special case callback for groups, since it has different callback format than names -// static -void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data) +void LLPanelEstateInfo::addAllowedGroup2(LLUUID id) { LLSD payload; payload["operation"] = (S32)ESTATE_ACCESS_ALLOWED_GROUP_ADD; @@ -1739,7 +1748,7 @@ void LLPanelEstateInfo::addAllowedGroup2(LLUUID id, void* user_data) LLNotification::Params params("EstateAllowedGroupAdd"); params.payload(payload) .substitutions(args) - .functor(accessCoreConfirm); + .functor.function(accessCoreConfirm); if (isLindenEstate()) { LLNotifications::instance().forceResponse(params, 0); @@ -1760,7 +1769,7 @@ void LLPanelEstateInfo::accessAddCore(U32 operation_flag, const std::string& dia LLNotification::Params params("ChangeLindenAccess"); params.payload(payload) - .functor(accessAddCore2); + .functor.function(accessAddCore2); if (isLindenEstate()) { @@ -1848,7 +1857,7 @@ void LLPanelEstateInfo::accessAddCore3(const std::vector& names, co LLNotification::Params params(change_info->mDialogName); params.substitutions(args) .payload(change_info->asLLSD()) - .functor(accessCoreConfirm); + .functor.function(accessCoreConfirm); if (isLindenEstate()) { @@ -1888,7 +1897,7 @@ void LLPanelEstateInfo::accessRemoveCore(U32 operation_flag, const std::string& LLNotification::Params params("ChangeLindenAccess"); params.payload(payload) - .functor(accessRemoveCore2); + .functor.function(accessRemoveCore2); if (isLindenEstate()) { @@ -2121,7 +2130,7 @@ BOOL LLPanelEstateInfo::postBuild() initCtrl("limit_age_verified"); initCtrl("voice_chat_check"); childSetCommitCallback("abuse_email_address", onChangeAnything, this); - childSetKeystrokeCallback("abuse_email_address", onChangeText, this); + getChild("abuse_email_address")->setKeystrokeCallback(onChangeText, this); initHelpBtn("estate_manager_help", "HelpEstateEstateManager"); initHelpBtn("use_global_time_help", "HelpEstateUseGlobalTime"); @@ -2161,7 +2170,7 @@ BOOL LLPanelEstateInfo::postBuild() group_name_list->setMaxItemCount(ESTATE_MAX_ACCESS_IDS); } - childSetAction("add_allowed_group_btn", onClickAddAllowedGroup, this); + getChild("add_allowed_group_btn")->setCommitCallback(boost::bind(&LLPanelEstateInfo::onClickAddAllowedGroup, this)); childSetAction("remove_allowed_group_btn", onClickRemoveAllowedGroup, this); childSetCommitCallback("banned_avatar_name_list", onChangeChildCtrl, this); @@ -2213,7 +2222,7 @@ BOOL LLPanelEstateInfo::sendUpdate() llinfos << "LLPanelEsateInfo::sendUpdate()" << llendl; LLNotification::Params params("ChangeLindenEstate"); - params.functor(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); + params.functor.function(boost::bind(&LLPanelEstateInfo::callbackChangeLindenEstate, this, _1, _2)); if (getEstateID() <= ESTATE_LAST_LINDEN) { @@ -2556,8 +2565,7 @@ void LLPanelEstateInfo::callbackCacheName( const LLUUID& id, const std::string& first, const std::string& last, - BOOL is_group, - void*) + BOOL is_group) { LLPanelEstateInfo* self = LLFloaterRegionInfo::getPanelEstate(); if (!self) return; @@ -2652,7 +2660,7 @@ bool LLPanelEstateInfo::onMessageCommit(const LLSD& notification, const LLSD& re strings_t strings; //integers_t integers; std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); strings.push_back(strings_t::value_type(name)); strings.push_back(strings_t::value_type(text)); LLUUID invoice(LLFloaterRegionInfo::getLastInvoice()); @@ -2739,7 +2747,6 @@ BOOL LLPanelEstateCovenant::postBuild() mEstateOwnerText = getChild("estate_owner_text"); mLastModifiedText = getChild("covenant_timestamp_text"); mEditor = getChild("covenant_editor"); - if (mEditor) mEditor->setHandleEditKeysDirectly(TRUE); LLButton* reset_button = getChild("reset_covenant"); reset_button->setEnabled(gAgent.canManageEstate()); reset_button->setClickedCallback(LLPanelEstateCovenant::resetCovenantID, NULL); @@ -2852,7 +2859,7 @@ void LLPanelEstateCovenant::loadInvItem(LLInventoryItem *itemp) else { mAssetStatus = ASSET_LOADED; - setCovenantTextEditor("There is no Covenant provided for this Estate."); + setCovenantTextEditor(LLTrans::getString("RegionNoCovenant")); sendChangeCovenantID(LLUUID::null); } } @@ -3063,7 +3070,7 @@ bool LLDispatchEstateUpdateInfo::operator()( regionp->setOwner(owner_id); // Update estate owner name in UI const BOOL is_group = FALSE; - gCacheName->getNameFromUUID(owner_id, is_group, LLPanelEstateInfo::callbackCacheName); + gCacheName->get(owner_id, is_group, &LLPanelEstateInfo::callbackCacheName); U32 estate_id = strtoul(strings[2].c_str(), NULL, 10); panel->setEstateID(estate_id); @@ -3162,9 +3169,10 @@ bool LLDispatchSetEstateAccess::operator()( totalAllowedAgents += allowed_agent_name_list->getItemCount(); } - std::string msg = llformat("Allowed residents: (%d, max %d)", - totalAllowedAgents, - ESTATE_MAX_ACCESS_IDS); + LLStringUtil::format_map_t args; + args["[ALLOWEDAGENTS]"] = llformat ("%d", totalAllowedAgents); + args["[MAXACCESS]"] = llformat ("%d", ESTATE_MAX_ACCESS_IDS); + std::string msg = LLTrans::getString("RegionInfoAllowedResidents", args); panel->childSetValue("allow_resident_label", LLSD(msg)); if (allowed_agent_name_list) @@ -3186,9 +3194,10 @@ bool LLDispatchSetEstateAccess::operator()( LLNameListCtrl* allowed_group_name_list; allowed_group_name_list = panel->getChild("allowed_group_name_list"); - std::string msg = llformat("Allowed groups: (%d, max %d)", - num_allowed_groups, - (S32) ESTATE_MAX_GROUP_IDS); + LLStringUtil::format_map_t args; + args["[ALLOWEDGROUPS]"] = llformat ("%d", num_allowed_groups); + args["[MAXACCESS]"] = llformat ("%d", ESTATE_MAX_GROUP_IDS); + std::string msg = LLTrans::getString("RegionInfoAllowedGroups", args); panel->childSetValue("allow_group_label", LLSD(msg)); if (allowed_group_name_list) diff --git a/indra/newview/llfloaterregioninfo.h b/indra/newview/llfloaterregioninfo.h index 806d1f57d6..be4becf7e7 100644 --- a/indra/newview/llfloaterregioninfo.h +++ b/indra/newview/llfloaterregioninfo.h @@ -59,13 +59,13 @@ class LLPanelRegionTerrainInfo; class LLPanelEstateInfo; class LLPanelEstateCovenant; -class LLFloaterRegionInfo : public LLFloater, public LLFloaterSingleton +class LLFloaterRegionInfo : public LLFloater { - friend class LLUISingleton >; + friend class LLFloaterReg; public: - ~LLFloaterRegionInfo(); - /*virtual*/ void onOpen(); + + /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ BOOL postBuild(); static void processEstateOwnerRequest(LLMessageSystem* msg, void**); @@ -84,10 +84,14 @@ public: // from LLPanel virtual void refresh(); - static void requestRegionInfo(); + void requestRegionInfo(); -protected: +private: + LLFloaterRegionInfo(const LLSD& seed); + ~LLFloaterRegionInfo(); + +protected: void refreshFromRegion(LLViewerRegion* region); // member data @@ -103,7 +107,8 @@ protected: class LLPanelRegionInfo : public LLPanel { public: - LLPanelRegionInfo() : LLPanel(std::string("Region Info Panel")) {} + LLPanelRegionInfo(); + static void onBtnSet(void* user_data); static void onChangeChildCtrl(LLUICtrl* ctrl, void* user_data); static void onChangeAnything(LLUICtrl* ctrl, void* user_data); @@ -165,7 +170,7 @@ protected: bool onKickAllCommit(const LLSD& notification, const LLSD& response); static void onClickMessage(void* userdata); bool onMessageCommit(const LLSD& notification, const LLSD& response); - static void onClickManageTelehub(void* data); + void onClickManageTelehub(); }; ///////////////////////////////////////////////////////////////////////////// @@ -261,7 +266,7 @@ public: static void onClickAddAllowedAgent(void* user_data); static void onClickRemoveAllowedAgent(void* user_data); - static void onClickAddAllowedGroup(void* user_data); + void onClickAddAllowedGroup(); static void onClickRemoveAllowedGroup(void* user_data); static void onClickAddBannedAgent(void* user_data); static void onClickRemoveBannedAgent(void* user_data); @@ -271,7 +276,7 @@ public: // Group picker callback is different, can't use core methods below bool addAllowedGroup(const LLSD& notification, const LLSD& response); - static void addAllowedGroup2(LLUUID id, void* data); + void addAllowedGroup2(LLUUID id); // Core methods for all above add/remove button clicks static void accessAddCore(U32 operation_flag, const std::string& dialog_name); @@ -339,8 +344,7 @@ public: const LLUUID& id, const std::string& first, const std::string& last, - BOOL is_group, - void*); + BOOL is_group); protected: virtual BOOL sendUpdate(); diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp index 412494eeb3..4d154c4cd3 100644 --- a/indra/newview/llfloaterreporter.cpp +++ b/indra/newview/llfloaterreporter.cpp @@ -48,19 +48,19 @@ #include "llversionviewer.h" #include "message.h" #include "v3math.h" +#include "lltexteditor.h" // viewer project includes #include "llagent.h" #include "llbutton.h" #include "llcheckboxctrl.h" -#include "llinventoryview.h" +#include "llfloaterreg.h" #include "lllineeditor.h" #include "lltexturectrl.h" #include "llscrolllistctrl.h" #include "llimview.h" #include "lltextbox.h" #include "lldispatcher.h" -#include "llviewertexteditor.h" #include "llviewerobject.h" #include "llviewerregion.h" #include "llcombobox.h" @@ -73,7 +73,7 @@ #include "lltoolmgr.h" #include "llresourcedata.h" // for LLResourceData #include "llviewerwindow.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llworldmap.h" #include "llfilepicker.h" #include "llfloateravatarpicker.h" @@ -84,6 +84,7 @@ #include "llviewernetwork.h" #include "llassetuploadresponders.h" +#include "llagentui.h" const U32 INCLUDE_SCREENSHOT = 0x01 << 0; @@ -91,28 +92,14 @@ const U32 INCLUDE_SCREENSHOT = 0x01 << 0; // Globals //----------------------------------------------------------------------------- -// this map keeps track of current reporter instances -// there can only be one instance of each reporter type -LLMap< EReportType, LLFloaterReporter* > gReporterInstances; - -// keeps track of where email is going to - global to avoid a pile -// of static/non-static access outside my control -namespace { - static BOOL gEmailToEstateOwner = FALSE; - static BOOL gDialogVisible = FALSE; -} - //----------------------------------------------------------------------------- // Member functions //----------------------------------------------------------------------------- -LLFloaterReporter::LLFloaterReporter( - const std::string& name, - const LLRect& rect, - const std::string& title, - EReportType report_type) - : - LLFloater(name, rect, title), - mReportType(report_type), + +LLFloaterReporter::LLFloaterReporter(const LLSD& key) +: LLFloater(key), + mReportType(COMPLAINT_REPORT), + mEmailToEstateOwner(FALSE), mObjectID(), mScreenID(), mAbuserID(), @@ -122,37 +109,35 @@ LLFloaterReporter::LLFloaterReporter( mCopyrightWarningSeen( FALSE ), mResourceDatap(new LLResourceData()) { - if (report_type == BUG_REPORT) + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_report_abuse.xml"); +} + +// static +void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg) +{ + U32 region_flags; + msg->getU32("RegionInfo", "RegionFlags", region_flags); + + if ( LLFloaterReg::instanceVisible("reporter") ) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_report_bug.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_report_abuse.xml"); - } + LLFloaterReporter *f = LLFloaterReg::findTypedInstance("reporter"); + BOOL email_to_estate_owner = ( region_flags & REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER ); + f->mEmailToEstateOwner = email_to_estate_owner; - childSetText("abuse_location_edit", gAgent.getSLURL() ); - - LLButton* pick_btn = getChild("pick_btn"); - if (pick_btn) - { - // XUI: Why aren't these in viewerart.ini? - pick_btn->setImages( std::string("UIImgFaceUUID"), - std::string("UIImgFaceSelectedUUID") ); - childSetAction("pick_btn", onClickObjPicker, this); - } - - if (report_type != BUG_REPORT) - { - // abuser name is selected from a list - LLLineEditor* le = getChild("abuser_name_edit"); - le->setEnabled( FALSE ); - } - - childSetAction("select_abuser", onClickSelectAbuser, this); - - childSetAction("send_btn", onClickSend, this); - childSetAction("cancel_btn", onClickCancel, this); + if ( email_to_estate_owner ) + { + LLNotifications::instance().add("HelpReportAbuseEmailEO"); + } + else + { + LLNotifications::instance().add("HelpReportAbuseEmailLL"); + } + }; +} +// virtual +BOOL LLFloaterReporter::postBuild() +{ + childSetText("abuse_location_edit", LLAgentUI::buildSLURL()); enableControls(TRUE); @@ -165,8 +150,6 @@ LLFloaterReporter::LLFloaterReporter( } setPosBox(pos); - gReporterInstances.addData(report_type, this); - // Take a screenshot, but don't draw this floater. setVisible(FALSE); takeScreenshot(); @@ -180,44 +163,43 @@ LLFloaterReporter::LLFloaterReporter( mDefaultSummary = childGetText("details_edit"); - gDialogVisible = TRUE; + // send a message and ask for information about this region - + // result comes back in processRegionInfo(..) + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("RequestRegionInfo"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID", gAgent.getID()); + msg->addUUID("SessionID", gAgent.getSessionID()); + gAgent.sendReliableMessage(); + + + // abuser name is selected from a list + LLLineEditor* le = getChild("abuser_name_edit"); + le->setEnabled( FALSE ); - // only request details for abuse reports (not BUG reports) - if (report_type != BUG_REPORT) - { - // send a message and ask for information about this region - - // result comes back in processRegionInfo(..) - LLMessageSystem* msg = gMessageSystem; - msg->newMessage("RequestRegionInfo"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - gAgent.sendReliableMessage(); - }; + setPosBox((LLVector3d)mPosition.getValue()); + LLButton* pick_btn = getChild("pick_btn"); + pick_btn->setImages(std::string("tool_face.tga"), + std::string("tool_face_active.tga") ); + childSetAction("pick_btn", onClickObjPicker, this); + + childSetAction("select_abuser", onClickSelectAbuser, this); + + childSetAction("send_btn", onClickSend, this); + childSetAction("cancel_btn", onClickCancel, this); + + // grab the user's name + std::string fullname; + LLAgentUI::buildFullname(fullname); + childSetText("reporter_field", fullname); + + center(); + + return TRUE; } - -// static -void LLFloaterReporter::processRegionInfo(LLMessageSystem* msg) -{ - U32 region_flags; - msg->getU32("RegionInfo", "RegionFlags", region_flags); - gEmailToEstateOwner = ( region_flags & REGION_FLAGS_ABUSE_EMAIL_TO_ESTATE_OWNER ); - - if ( gDialogVisible ) - { - if ( gEmailToEstateOwner ) - { - LLNotifications::instance().add("HelpReportAbuseEmailEO"); - } - else - LLNotifications::instance().add("HelpReportAbuseEmailLL"); - }; -} - // virtual LLFloaterReporter::~LLFloaterReporter() { - gReporterInstances.removeData(mReportType); // child views automatically deleted mObjectID = LLUUID::null; @@ -232,7 +214,6 @@ LLFloaterReporter::~LLFloaterReporter() mMCDList.clear(); delete mResourceDatap; - gDialogVisible = FALSE; } // virtual @@ -241,7 +222,7 @@ void LLFloaterReporter::draw() // this is set by a static callback sometime after the dialog is created. // Only disable screenshot for abuse reports to estate owners - bug reports always // allow screenshots to be taken. - if ( gEmailToEstateOwner && ( mReportType != BUG_REPORT ) ) + if ( mEmailToEstateOwner ) { childSetValue("screen_check", FALSE ); childSetEnabled("screen_check", FALSE ); @@ -257,11 +238,7 @@ void LLFloaterReporter::draw() void LLFloaterReporter::enableControls(BOOL enable) { childSetEnabled("category_combo", enable); - // bug reports never include the chat history - if (mReportType != BUG_REPORT) - { - childSetEnabled("chat_check", enable); - } + childSetEnabled("chat_check", enable); childSetEnabled("screen_check", enable); childDisable("screenshot"); childSetEnabled("pick_btn", enable); @@ -332,7 +309,7 @@ void LLFloaterReporter::getObjectInfo(const LLUUID& object_id) // we have to query the simulator for information // about this object LLMessageSystem* msg = gMessageSystem; - U32 request_flags = (mReportType == BUG_REPORT) ? BUG_REPORT_REQUEST : COMPLAINT_REPORT_REQUEST; + U32 request_flags = COMPLAINT_REPORT_REQUEST; msg->newMessageFast(_PREHASH_RequestObjectPropertiesFamily); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -363,15 +340,12 @@ void LLFloaterReporter::callbackAvatarID(const std::vector& names, if (ids.empty() || names.empty()) return; - // this should never be called in a bug report but here for safety. - if ( self->mReportType != BUG_REPORT ) - { - self->childSetText("abuser_name_edit", names[0] ); - - self->mAbuserID = ids[0]; + self->childSetText("abuser_name_edit", names[0] ); + + self->mAbuserID = ids[0]; + + self->refresh(); - self->refresh(); - }; } // static @@ -386,9 +360,7 @@ void LLFloaterReporter::onClickSend(void *userdata) if(self->validateReport()) { - // only show copyright alert for abuse reports - if ( self->mReportType != BUG_REPORT ) - { + const int IP_CONTENT_REMOVAL = 66; const int IP_PERMISSONS_EXPLOIT = 37; LLComboBox* combo = self->getChild( "category_combo"); @@ -418,7 +390,7 @@ void LLFloaterReporter::onClickSend(void *userdata) LLNotifications::instance().add("HelpReportAbuseContainsCopyright"); return; } - } + LLUploadDialog::modalUploadDialog("Uploading...\n\nReport"); // *TODO don't upload image if checkbox isn't checked @@ -427,7 +399,7 @@ void LLFloaterReporter::onClickSend(void *userdata) if(!url.empty() || !sshot_url.empty()) { self->sendReportViaCaps(url, sshot_url, self->gatherReport()); - self->close(); + self->closeFloater(); } else { @@ -442,7 +414,7 @@ void LLFloaterReporter::onClickSend(void *userdata) { self->sendReportViaLegacy(self->gatherReport()); LLUploadDialog::modalUploadFinished(); - self->close(); + self->closeFloater(); } } } @@ -461,7 +433,7 @@ void LLFloaterReporter::onClickCancel(void *userdata) { closePickTool(self); } - self->close(); + self->closeFloater(); } @@ -497,30 +469,16 @@ void LLFloaterReporter::closePickTool(void *userdata) // static void LLFloaterReporter::showFromMenu(EReportType report_type) { - if (gReporterInstances.checkData(report_type)) + if (COMPLAINT_REPORT != report_type) { - // ...bring that window to front - LLFloaterReporter *f = gReporterInstances.getData(report_type); - f->open(); /* Flawfinder: ignore */ + llwarns << "Unknown LLViewerReporter type : " << report_type << llendl; + return; } - else + + LLFloaterReporter* f = LLFloaterReg::showTypedInstance("reporter", LLSD()); + if (f) { - LLFloaterReporter *f; - if (BUG_REPORT == report_type) - { - f = LLFloaterReporter::createNewBugReporter(); - } - else if (COMPLAINT_REPORT == report_type) - { - f = LLFloaterReporter::createNewAbuseReporter(); - } - else - { - llwarns << "Unknown LLViewerReporter type : " << report_type << llendl; - return; - } - - f->center(); + f->setReportType(report_type); if (report_type == BUG_REPORT) { @@ -530,11 +488,6 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) { // popup for abuse reports is triggered elsewhere } - - // grab the user's name - std::string fullname; - gAgent.buildFullname(fullname); - f->childSetText("reporter_field", fullname); } } @@ -542,13 +495,11 @@ void LLFloaterReporter::showFromMenu(EReportType report_type) // static void LLFloaterReporter::showFromObject(const LLUUID& object_id) { - LLFloaterReporter* f = createNewAbuseReporter(); - f->center(); - f->setFocus(TRUE); + LLFloaterReporter* f = LLFloaterReg::showTypedInstance("reporter"); // grab the user's name std::string fullname; - gAgent.buildFullname(fullname); + LLAgentUI::buildFullname(fullname); f->childSetText("reporter_field", fullname); // Request info for this object @@ -557,41 +508,10 @@ void LLFloaterReporter::showFromObject(const LLUUID& object_id) // Need to deselect on close f->mDeselectOnClose = TRUE; - f->open(); /* Flawfinder: ignore */ + f->openFloater(); } -// static -LLFloaterReporter* LLFloaterReporter::getReporter(EReportType report_type) -{ - LLFloaterReporter *self = NULL; - if (gReporterInstances.checkData(report_type)) - { - // ...bring that window to front - self = gReporterInstances.getData(report_type); - } - return self; -} - -LLFloaterReporter* LLFloaterReporter::createNewAbuseReporter() -{ - return new LLFloaterReporter("complaint_reporter", - LLRect(), - "Report Abuse", - COMPLAINT_REPORT); -} - -//static -LLFloaterReporter* LLFloaterReporter::createNewBugReporter() -{ - return new LLFloaterReporter("bug_reporter", - LLRect(), - "Report Bug", - BUG_REPORT); -} - - - void LLFloaterReporter::setPickedObjectProperties(const std::string& object_name, const std::string& owner_name, const LLUUID owner_id) { childSetText("object_name", object_name); @@ -619,21 +539,26 @@ bool LLFloaterReporter::validateReport() return false; } - if ( mReportType != BUG_REPORT ) + + if ( childGetText("abuser_name_edit").empty() ) { - if ( childGetText("abuser_name_edit").empty() ) - { - LLNotifications::instance().add("HelpReportAbuseAbuserNameEmpty"); - return false; - }; - - if ( childGetText("abuse_location_edit").empty() ) - { - LLNotifications::instance().add("HelpReportAbuseAbuserLocationEmpty"); - return false; - }; + LLNotifications::instance().add("HelpReportAbuseAbuserNameEmpty"); + return false; }; + if ( childGetText("abuse_location_edit").empty() ) + { + LLNotifications::instance().add("HelpReportAbuseAbuserLocationEmpty"); + return false; + }; + + if ( childGetText("abuse_location_edit").empty() ) + { + LLNotifications::instance().add("HelpReportAbuseAbuserLocationEmpty"); + return false; + }; + + if ( childGetText("summary_edit").empty() ) { if ( mReportType != BUG_REPORT ) @@ -685,50 +610,34 @@ LLSD LLFloaterReporter::gatherReport() #if LL_WINDOWS const char* platform = "Win"; - const char* short_platform = "O:W"; #elif LL_DARWIN const char* platform = "Mac"; - const char* short_platform = "O:M"; #elif LL_LINUX const char* platform = "Lnx"; - const char* short_platform = "O:L"; #elif LL_SOLARIS const char* platform = "Sol"; const char* short_platform = "O:S"; #else const char* platform = "???"; - const char* short_platform = "O:?"; #endif - if ( mReportType == BUG_REPORT) - { - summary << short_platform << " V" << LL_VERSION_MAJOR << "." - << LL_VERSION_MINOR << "." - << LL_VERSION_PATCH << "." - << LL_VIEWER_BUILD - << " (" << regionp->getName() << ")" - << "[" << category_name << "] " - << "\"" << childGetValue("summary_edit").asString() << "\""; - } - else - { - summary << "" - << " |" << regionp->getName() << "|" // region reporter is currently in. - << " (" << childGetText("abuse_location_edit") << ")" // region abuse occured in (freeform text - no LLRegionPicker tool) - << " [" << category_name << "] " // updated category - << " {" << childGetText("abuser_name_edit") << "} " // name of abuse entered in report (chosen using LLAvatarPicker) - << " \"" << childGetValue("summary_edit").asString() << "\""; // summary as entered - }; + + summary << "" + << " |" << regionp->getName() << "|" // region reporter is currently in. + << " (" << childGetText("abuse_location_edit") << ")" // region abuse occured in (freeform text - no LLRegionPicker tool) + << " [" << category_name << "] " // updated category + << " {" << childGetText("abuser_name_edit") << "} " // name of abuse entered in report (chosen using LLAvatarPicker) + << " \"" << childGetValue("summary_edit").asString() << "\""; // summary as entered + std::ostringstream details; - if (mReportType != BUG_REPORT) - { - details << "V" << LL_VERSION_MAJOR << "." // client version moved to body of email for abuse reports - << LL_VERSION_MINOR << "." - << LL_VERSION_PATCH << "." - << LL_VIEWER_BUILD << std::endl << std::endl; - } + + details << "V" << LL_VERSION_MAJOR << "." // client version moved to body of email for abuse reports + << LL_VERSION_MINOR << "." + << LL_VERSION_PATCH << "." + << LL_VIEWER_BUILD << std::endl << std::endl; + std::string object_name = childGetText("object_name"); std::string owner_name = childGetText("owner_name"); if (!object_name.empty() && !owner_name.empty()) @@ -737,11 +646,9 @@ LLSD LLFloaterReporter::gatherReport() details << "Owner: " << owner_name << "\n"; } - if ( mReportType != BUG_REPORT ) - { - details << "Abuser name: " << childGetText("abuser_name_edit") << " \n"; - details << "Abuser location: " << childGetText("abuse_location_edit") << " \n"; - }; + + details << "Abuser name: " << childGetText("abuser_name_edit") << " \n"; + details << "Abuser location: " << childGetText("abuse_location_edit") << " \n"; details << childGetValue("details_edit").asString(); @@ -761,17 +668,11 @@ LLSD LLFloaterReporter::gatherReport() LLUUID screenshot_id = LLUUID::null; if (childGetValue("screen_check")) { - if ( mReportType != BUG_REPORT ) - { - if ( gEmailToEstateOwner == FALSE ) - { - screenshot_id = childGetValue("screenshot"); - } - } - else + + if ( mEmailToEstateOwner == FALSE ) { screenshot_id = childGetValue("screenshot"); - }; + } }; LLSD report = LLSD::emptyMap(); @@ -883,7 +784,7 @@ void LLFloaterReporter::takeScreenshot() llwarns << "Unable to take screenshot" << llendl; return; } - LLPointer upload_data = LLViewerImageList::convertToUploadFile(raw); + LLPointer upload_data = LLViewerTextureList::convertToUploadFile(raw); // create a resource data mResourceDatap->mInventoryType = LLInventoryType::IT_NONE; @@ -891,12 +792,8 @@ void LLFloaterReporter::takeScreenshot() mResourceDatap->mExpectedUploadCost = 0; // we expect that abuse screenshots are free mResourceDatap->mAssetInfo.mTransactionID.generate(); mResourceDatap->mAssetInfo.mUuid = mResourceDatap->mAssetInfo.mTransactionID.makeAssetID(gAgent.getSecureSessionID()); - if (BUG_REPORT == mReportType) - { - mResourceDatap->mAssetInfo.mType = LLAssetType::AT_TEXTURE; - mResourceDatap->mPreferredLocation = LLAssetType::EType(-1); - } - else if (COMPLAINT_REPORT == mReportType) + + if (COMPLAINT_REPORT == mReportType) { mResourceDatap->mAssetInfo.mType = LLAssetType::AT_TEXTURE; mResourceDatap->mPreferredLocation = LLAssetType::EType(-2); @@ -917,17 +814,17 @@ void LLFloaterReporter::takeScreenshot() mResourceDatap->mAssetInfo.mType); // store in the image list so it doesn't try to fetch from the server - LLPointer image_in_list = new LLViewerImage(mResourceDatap->mAssetInfo.mUuid, TRUE); + LLPointer image_in_list = + LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, TRUE, FALSE, LLViewerTexture::FETCHED_TEXTURE); image_in_list->createGLTexture(0, raw); - gImageList.addImage(image_in_list); - + // the texture picker then uses that texture LLTexturePicker* texture = getChild("screenshot"); if (texture) { texture->setImageAssetID(mResourceDatap->mAssetInfo.mUuid); texture->setDefaultImageAssetID(mResourceDatap->mAssetInfo.mUuid); - texture->setCaption(std::string("Screenshot")); + texture->setCaption(getString("Screenshot")); } } @@ -967,11 +864,7 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, } EReportType report_type = UNKNOWN_REPORT; - if (data->mPreferredLocation == -1) - { - report_type = BUG_REPORT; - } - else if (data->mPreferredLocation == -2) + if (data->mPreferredLocation == -2) { report_type = COMPLAINT_REPORT; } @@ -980,13 +873,13 @@ void LLFloaterReporter::uploadDoneCallback(const LLUUID &uuid, void *user_data, llwarns << "Unknown report type : " << data->mPreferredLocation << llendl; } - LLFloaterReporter *self = getReporter(report_type); + LLFloaterReporter *self = LLFloaterReg::findTypedInstance("reporter"); if (self) { self->mScreenID = uuid; llinfos << "Got screen shot " << uuid << llendl; self->sendReportViaLegacy(self->gatherReport()); - self->close(); + self->closeFloater(); } } @@ -1001,35 +894,35 @@ void LLFloaterReporter::setPosBox(const LLVector3d &pos) childSetText("pos_field", pos_string); } -void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd) -{ - LLFloaterReporter *self = gReporterInstances[COMPLAINT_REPORT]; - if (self) - { - self->childSetText("details_edit", description); +// void LLFloaterReporter::setDescription(const std::string& description, LLMeanCollisionData *mcd) +// { +// LLFloaterReporter *self = LLFloaterReg::findTypedInstance("reporter"); +// if (self) +// { +// self->childSetText("details_edit", description); - for_each(self->mMCDList.begin(), self->mMCDList.end(), DeletePointer()); - self->mMCDList.clear(); - if (mcd) - { - self->mMCDList.push_back(new LLMeanCollisionData(mcd)); - } - } -} +// for_each(self->mMCDList.begin(), self->mMCDList.end(), DeletePointer()); +// self->mMCDList.clear(); +// if (mcd) +// { +// self->mMCDList.push_back(new LLMeanCollisionData(mcd)); +// } +// } +// } -void LLFloaterReporter::addDescription(const std::string& description, LLMeanCollisionData *mcd) -{ - LLFloaterReporter *self = gReporterInstances[COMPLAINT_REPORT]; - if (self) - { - LLTextEditor* text = self->getChild("details_edit"); - if (text) - { - text->insertText(description); - } - if (mcd) - { - self->mMCDList.push_back(new LLMeanCollisionData(mcd)); - } - } -} +// void LLFloaterReporter::addDescription(const std::string& description, LLMeanCollisionData *mcd) +// { +// LLFloaterReporter *self = LLFloaterReg::findTypedInstance("reporter"); +// if (self) +// { +// LLTextEditor* text = self->getChild("details_edit"); +// if (text) +// { +// text->insertText(description); +// } +// if (mcd) +// { +// self->mMCDList.push_back(new LLMeanCollisionData(mcd)); +// } +// } +// } diff --git a/indra/newview/llfloaterreporter.h b/indra/newview/llfloaterreporter.h index 86bc60559e..f363b9531e 100644 --- a/indra/newview/llfloaterreporter.h +++ b/indra/newview/llfloaterreporter.h @@ -39,7 +39,7 @@ #include "v3math.h" class LLMessageSystem; -class LLViewerImage; +class LLViewerTexture; class LLInventoryItem; class LLViewerObject; class LLAgent; @@ -82,14 +82,13 @@ class LLFloaterReporter : public LLFloater { public: - LLFloaterReporter(const std::string& name, - const LLRect &rect, - const std::string& title, - EReportType = UNKNOWN_REPORT); + LLFloaterReporter(const LLSD& key); /*virtual*/ ~LLFloaterReporter(); - + /*virtual*/ BOOL postBuild(); virtual void draw(); - + + void setReportType(EReportType type) { mReportType = type; } + // Enables all buttons static void showFromMenu(EReportType report_type); @@ -104,11 +103,6 @@ public: static void addDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); static void setDescription(const std::string& description, LLMeanCollisionData *mcd = NULL); - // returns a pointer to reporter of report_type - static LLFloaterReporter* getReporter(EReportType report_type); - static LLFloaterReporter* createNewAbuseReporter(); - static LLFloaterReporter* createNewBugReporter(); - // static static void processRegionInfo(LLMessageSystem* msg); @@ -130,6 +124,7 @@ private: private: EReportType mReportType; + BOOL mEmailToEstateOwner; LLUUID mObjectID; LLUUID mScreenID; LLUUID mAbuserID; diff --git a/indra/newview/llfloaterscriptdebug.cpp b/indra/newview/llfloaterscriptdebug.cpp index bc774e77ac..328fb6450e 100644 --- a/indra/newview/llfloaterscriptdebug.cpp +++ b/indra/newview/llfloaterscriptdebug.cpp @@ -32,9 +32,10 @@ #include "llviewerprecompiledheaders.h" -#include "lluictrlfactory.h" #include "llfloaterscriptdebug.h" +#include "llfloaterreg.h" +#include "lluictrlfactory.h" #include "llfontgl.h" #include "llrect.h" #include "llerror.h" @@ -45,19 +46,20 @@ #include "llviewertexteditor.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" // // Statics // -LLFloaterScriptDebug* LLFloaterScriptDebug::sInstance = NULL; // // Member Functions // -LLFloaterScriptDebug::LLFloaterScriptDebug() : - LLMultiFloater() +LLFloaterScriptDebug::LLFloaterScriptDebug(const LLSD& key) + : LLMultiFloater(key) { +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_script_debug.xml"); + // avoid resizing of the window to match // the initial size of the tabbed-childs, whenever a tab is opened or closed mAutoResize = FALSE; @@ -65,17 +67,11 @@ LLFloaterScriptDebug::LLFloaterScriptDebug() : LLFloaterScriptDebug::~LLFloaterScriptDebug() { - sInstance = NULL; } void LLFloaterScriptDebug::show(const LLUUID& object_id) { - LLFloater* floaterp = addOutputWindow(object_id); - if (sInstance) - { - sInstance->open(); /* Flawfinder: ignore */ - sInstance->showFloater(floaterp); - } + addOutputWindow(object_id); } BOOL LLFloaterScriptDebug::postBuild() @@ -84,41 +80,22 @@ BOOL LLFloaterScriptDebug::postBuild() if (mTabContainer) { - // *FIX: apparantly fails for tab containers? -// mTabContainer->requires("all_scripts"); -// mTabContainer->checkRequirements(); return TRUE; } return FALSE; } -void* getOutputWindow(void* data) -{ - return new LLFloaterScriptDebugOutput(); -} - LLFloater* LLFloaterScriptDebug::addOutputWindow(const LLUUID &object_id) { - if (!sInstance) - { - sInstance = new LLFloaterScriptDebug(); - LLCallbackMap::map_t factory_map; - factory_map["all_scripts"] = LLCallbackMap(getOutputWindow, NULL); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_script_debug.xml", &factory_map); - sInstance->setVisible(FALSE); - } + LLMultiFloater* host = LLFloaterReg::showTypedInstance("script_debug", LLSD()); + if (!host) + return NULL; - LLFloater* floaterp = NULL; - LLFloater::setFloaterHost(sInstance); - { - floaterp = LLFloaterScriptDebugOutput::show(object_id); - } + LLFloater::setFloaterHost(host); + LLFloater* floaterp = LLFloaterReg::showInstance("script_debug_output", object_id); LLFloater::setFloaterHost(NULL); - // Tabs sometimes overlap resize handle - sInstance->moveResizeHandlesToFront(); - return floaterp; } @@ -129,7 +106,7 @@ void LLFloaterScriptDebug::addScriptLine(const std::string &utf8mesg, const std: if (objectp) { - objectp->setIcon(gImageList.getImageFromFile("script_error.j2c", TRUE, TRUE)); + objectp->setIcon(LLViewerTextureManager::getFetchedTextureFromFile("script_error.j2c", TRUE, TRUE)); floater_label = llformat("%s(%.2f, %.2f)", user_name.c_str(), objectp->getPositionRegion().mV[VX], objectp->getPositionRegion().mV[VY]); } else @@ -141,119 +118,55 @@ void LLFloaterScriptDebug::addScriptLine(const std::string &utf8mesg, const std: addOutputWindow(source_id); // add to "All" floater - LLFloaterScriptDebugOutput* floaterp = LLFloaterScriptDebugOutput::getFloaterByID(LLUUID::null); - floaterp->addLine(utf8mesg, user_name, color); - + LLFloaterScriptDebugOutput* floaterp = LLFloaterReg::getTypedInstance("script_debug_output", LLUUID::null); + if (floaterp) + { + floaterp->addLine(utf8mesg, user_name, color); + } + // add to specific script instance floater - floaterp = LLFloaterScriptDebugOutput::getFloaterByID(source_id); - floaterp->addLine(utf8mesg, floater_label, color); + floaterp = LLFloaterReg::getTypedInstance("script_debug_output", source_id); + if (floaterp) + { + floaterp->addLine(utf8mesg, floater_label, color); + } } // // LLFloaterScriptDebugOutput // -std::map LLFloaterScriptDebugOutput::sInstanceMap; - -LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput() -: mObjectID(LLUUID::null) +LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput(const LLSD& object_id) + : LLFloater(LLSD(object_id)), + mObjectID(object_id.asUUID()) { - sInstanceMap[mObjectID] = this; + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_script_debug_panel.xml"); } -LLFloaterScriptDebugOutput::LLFloaterScriptDebugOutput(const LLUUID& object_id) -: LLFloater(std::string("script instance floater"), LLRect(0, 200, 200, 0), std::string("Script"), TRUE), mObjectID(object_id) +BOOL LLFloaterScriptDebugOutput::postBuild() { - S32 y = getRect().getHeight() - LLFLOATER_HEADER_SIZE - LLFLOATER_VPAD; - S32 x = LLFLOATER_HPAD; - // History editor - // Give it a border on the top - LLRect history_editor_rect( - x, - y, - getRect().getWidth() - LLFLOATER_HPAD, - LLFLOATER_VPAD ); - mHistoryEditor = new LLViewerTextEditor( std::string("Chat History Editor"), - history_editor_rect, S32_MAX, LLStringUtil::null, LLFontGL::getFontSansSerif()); - mHistoryEditor->setWordWrap( TRUE ); - mHistoryEditor->setFollowsAll(); - mHistoryEditor->setEnabled( FALSE ); - mHistoryEditor->setTabStop( TRUE ); // We want to be able to cut or copy from the history. - addChild(mHistoryEditor); -} - -void LLFloaterScriptDebugOutput::initFloater(const std::string& title, BOOL resizable, - S32 min_width, S32 min_height, BOOL drag_on_left, - BOOL minimizable, BOOL close_btn) -{ - LLFloater::initFloater(title, resizable, min_width, min_height, drag_on_left, minimizable, close_btn); - S32 y = getRect().getHeight() - LLFLOATER_HEADER_SIZE - LLFLOATER_VPAD; - S32 x = LLFLOATER_HPAD; - // History editor - // Give it a border on the top - LLRect history_editor_rect( - x, - y, - getRect().getWidth() - LLFLOATER_HPAD, - LLFLOATER_VPAD ); - mHistoryEditor = new LLViewerTextEditor( std::string("Chat History Editor"), - history_editor_rect, S32_MAX, LLStringUtil::null, LLFontGL::getFontSansSerif()); - mHistoryEditor->setWordWrap( TRUE ); - mHistoryEditor->setFollowsAll(); - mHistoryEditor->setEnabled( FALSE ); - mHistoryEditor->setTabStop( TRUE ); // We want to be able to cut or copy from the history. - addChild(mHistoryEditor); + LLFloater::postBuild(); + mHistoryEditor = getChild("Chat History Editor"); + return TRUE; } LLFloaterScriptDebugOutput::~LLFloaterScriptDebugOutput() { - sInstanceMap.erase(mObjectID); } void LLFloaterScriptDebugOutput::addLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color) { if (mObjectID.isNull()) { - //setTitle("[All scripts]"); setCanTearOff(FALSE); setCanClose(FALSE); } else { setTitle(user_name); + setShortTitle(user_name); } mHistoryEditor->appendColoredText(utf8mesg, false, true, color); } -//static -LLFloaterScriptDebugOutput* LLFloaterScriptDebugOutput::show(const LLUUID& object_id) -{ - LLFloaterScriptDebugOutput* floaterp = NULL; - instance_map_t::iterator found_it = sInstanceMap.find(object_id); - if (found_it == sInstanceMap.end()) - { - floaterp = new LLFloaterScriptDebugOutput(object_id); - sInstanceMap[object_id] = floaterp; - floaterp->open(); /* Flawfinder: ignore*/ - } - else - { - floaterp = found_it->second; - } - - return floaterp; -} - -//static -LLFloaterScriptDebugOutput* LLFloaterScriptDebugOutput::getFloaterByID(const LLUUID& object_id) -{ - LLFloaterScriptDebugOutput* floaterp = NULL; - instance_map_t::iterator found_it = sInstanceMap.find(object_id); - if (found_it != sInstanceMap.end()) - { - floaterp = found_it->second; - } - - return floaterp; -} diff --git a/indra/newview/llfloaterscriptdebug.h b/indra/newview/llfloaterscriptdebug.h index 59c0ba1c8b..ffc60e5554 100644 --- a/indra/newview/llfloaterscriptdebug.h +++ b/indra/newview/llfloaterscriptdebug.h @@ -33,7 +33,7 @@ #ifndef LL_LLFLOATERSCRIPTDEBUG_H #define LL_LLFLOATERSCRIPTDEBUG_H -#include "llfloater.h" +#include "llmultifloater.h" class LLTextEditor; class LLUUID; @@ -41,15 +41,13 @@ class LLUUID; class LLFloaterScriptDebug : public LLMultiFloater { public: + LLFloaterScriptDebug(const LLSD& key); virtual ~LLFloaterScriptDebug(); - virtual void onClose(bool app_quitting) { setVisible(FALSE); } virtual BOOL postBuild(); static void show(const LLUUID& object_id); static void addScriptLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color, const LLUUID& source_id); protected: - LLFloaterScriptDebug(); - static LLFloater* addOutputWindow(const LLUUID& object_id); protected: @@ -59,26 +57,17 @@ protected: class LLFloaterScriptDebugOutput : public LLFloater { public: - LLFloaterScriptDebugOutput(); - LLFloaterScriptDebugOutput(const LLUUID& object_id); + LLFloaterScriptDebugOutput(const LLSD& object_id); ~LLFloaterScriptDebugOutput(); - virtual void initFloater(const std::string& title, BOOL resizable, - S32 min_width, S32 min_height, BOOL drag_on_left, - BOOL minimizable, BOOL close_btn); - void addLine(const std::string &utf8mesg, const std::string &user_name, const LLColor4& color); - static LLFloaterScriptDebugOutput* show(const LLUUID& object_id); - static LLFloaterScriptDebugOutput* getFloaterByID(const LLUUID& id); - + virtual BOOL postBuild(); + protected: - LLTextEditor* mHistoryEditor; + LLTextEditor* mHistoryEditor; - typedef std::map instance_map_t; - static instance_map_t sInstanceMap; - - LLUUID mObjectID; + LLUUID mObjectID; }; #endif // LL_LLFLOATERSCRIPTDEBUG_H diff --git a/indra/newview/llfloatersellland.cpp b/indra/newview/llfloatersellland.cpp index 92e070f766..a6aa01e83b 100644 --- a/indra/newview/llfloatersellland.cpp +++ b/indra/newview/llfloatersellland.cpp @@ -34,7 +34,7 @@ #include "llfloatersellland.h" #include "llfloateravatarpicker.h" -#include "llfloater.h" +#include "llfloaterreg.h" #include "llfloaterland.h" #include "lllineeditor.h" #include "llnotify.h" @@ -55,10 +55,21 @@ enum Badge { BADGE_OK, BADGE_NOTE, BADGE_WARN, BADGE_ERROR }; class LLFloaterSellLandUI : public LLFloater { -private: - LLFloaterSellLandUI(); +public: + LLFloaterSellLandUI(const LLSD& key); virtual ~LLFloaterSellLandUI(); - + +private: + class SelectionObserver : public LLParcelObserver + { + public: + SelectionObserver(LLFloaterSellLandUI* floater) : mFloater(floater) {} + virtual void changed(); + private: + LLFloaterSellLandUI* mFloater; + }; + +private: LLViewerRegion* mRegion; LLParcelSelectionHandle mParcelSelection; bool mParcelIsForSale; @@ -69,13 +80,12 @@ private: LLUUID mParcelSnapshot; LLUUID mAuthorizedBuyer; bool mParcelSoldWithObjects; + SelectionObserver mParcelSelectionObserver; void updateParcelInfo(); void refreshUI(); void setBadge(const char* id, Badge badge); - static LLFloaterSellLandUI* sInstance; - static void onChangeValue(LLUICtrl *ctrl, void *userdata); static void doSelectAgent(void *userdata); static void doCancel(void *userdata); @@ -88,91 +98,57 @@ private: public: virtual BOOL postBuild(); - virtual void onClose(bool app_quitting); - static LLFloaterSellLandUI* soleInstance(bool createIfNeeded); - bool setParcel(LLViewerRegion* region, LLParcelSelectionHandle parcel); - -private: - class SelectionObserver : public LLParcelObserver - { - public: - virtual void changed(); - }; }; // static void LLFloaterSellLand::sellLand( LLViewerRegion* region, LLParcelSelectionHandle parcel) { - LLFloaterSellLandUI* ui = LLFloaterSellLandUI::soleInstance(true); - if (ui->setParcel(region, parcel)) - { - ui->open(); /* Flawfinder: ignore */ - } + LLFloaterSellLandUI* ui = LLFloaterReg::showTypedInstance("sell_land"); + ui->setParcel(region, parcel); } // static -LLFloaterSellLandUI* LLFloaterSellLandUI::sInstance = NULL; - -// static -LLFloaterSellLandUI* LLFloaterSellLandUI::soleInstance(bool createIfNeeded) +LLFloater* LLFloaterSellLand::buildFloater(const LLSD& key) { - if (!sInstance && createIfNeeded) - { - sInstance = new LLFloaterSellLandUI(); - - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_sell_land.xml"); - sInstance->center(); - } - - - static SelectionObserver* parcelSelectionObserver = NULL; - if (!parcelSelectionObserver) - { - parcelSelectionObserver = new SelectionObserver; - LLViewerParcelMgr::getInstance()->addObserver(parcelSelectionObserver); - } - - return sInstance; + LLFloaterSellLandUI* floater = new LLFloaterSellLandUI(key); + return floater; } -LLFloaterSellLandUI::LLFloaterSellLandUI() -: LLFloater(std::string("Sell Land")), +#if LL_WINDOWS +// passing 'this' during construction generates a warning. The callee +// only uses the pointer to hold a reference to 'this' which is +// already valid, so this call does the correct thing. Disable the +// warning so that we can compile without generating a warning. +#pragma warning(disable : 4355) +#endif +LLFloaterSellLandUI::LLFloaterSellLandUI(const LLSD& key) +: LLFloater(key), + mParcelSelectionObserver(this), mRegion(0) { + LLViewerParcelMgr::getInstance()->addObserver(&mParcelSelectionObserver); +// LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_sell_land.xml"); } LLFloaterSellLandUI::~LLFloaterSellLandUI() { - if (sInstance == this) - { - sInstance = NULL; - } + LLViewerParcelMgr::getInstance()->removeObserver(&mParcelSelectionObserver); } void LLFloaterSellLandUI::SelectionObserver::changed() { - LLFloaterSellLandUI* ui = LLFloaterSellLandUI::soleInstance(false); - if (ui) + if (LLViewerParcelMgr::getInstance()->selectionEmpty()) { - if (LLViewerParcelMgr::getInstance()->selectionEmpty()) - { - ui->close(); - } - else { - ui->setParcel( - LLViewerParcelMgr::getInstance()->getSelectionRegion(), - LLViewerParcelMgr::getInstance()->getParcelSelection()); - } + mFloater->closeFloater(); + } + else + { + mFloater->setParcel(LLViewerParcelMgr::getInstance()->getSelectionRegion(), + LLViewerParcelMgr::getInstance()->getParcelSelection()); } -} - -void LLFloaterSellLandUI::onClose(bool app_quitting) -{ - LLFloater::onClose(app_quitting); - destroy(); } BOOL LLFloaterSellLandUI::postBuild() @@ -185,6 +161,7 @@ BOOL LLFloaterSellLandUI::postBuild() childSetAction("cancel_btn", doCancel, this); childSetAction("sell_btn", doSellLand, this); childSetAction("show_objects", doShowObjects, this); + center(); return TRUE; } @@ -432,7 +409,7 @@ void LLFloaterSellLandUI::callbackAvatarPick(const std::vector& nam void LLFloaterSellLandUI::doCancel(void *userdata) { LLFloaterSellLandUI* self = (LLFloaterSellLandUI*)userdata; - self->close(); + self->closeFloater(); } // static @@ -490,7 +467,7 @@ void LLFloaterSellLandUI::doSellLand(void *userdata) LLNotification::Params params("ConfirmLandSaleChange"); params.substitutions(args) - .functor(boost::bind(&LLFloaterSellLandUI::onConfirmSale, self, _1, _2)); + .functor.function(boost::bind(&LLFloaterSellLandUI::onConfirmSale, self, _1, _2)); if (sell_to_anyone) { @@ -556,6 +533,6 @@ bool LLFloaterSellLandUI::onConfirmSale(const LLSD& notification, const LLSD& re // Send update to server LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); - close(); + closeFloater(); return false; } diff --git a/indra/newview/llfloatersellland.h b/indra/newview/llfloatersellland.h index 1b3a33ebb8..1adf08052b 100644 --- a/indra/newview/llfloatersellland.h +++ b/indra/newview/llfloatersellland.h @@ -31,8 +31,10 @@ #ifndef LL_LLFLOATERSELLLAND_H #define LL_LLFLOATERSELLLAND_H -#include "llmemory.h" +#include "llsafehandle.h" + +class LLFloater; class LLParcel; class LLViewerRegion; class LLParcelSelection; @@ -42,6 +44,8 @@ class LLFloaterSellLand public: static void sellLand(LLViewerRegion* region, LLSafeHandle parcel); + + static LLFloater* buildFloater(const LLSD& key); }; #endif // LL_LLFLOATERSELLLAND_H diff --git a/indra/newview/llfloatersettingsdebug.cpp b/indra/newview/llfloatersettingsdebug.cpp index 2677467611..616e9bac35 100644 --- a/indra/newview/llfloatersettingsdebug.cpp +++ b/indra/newview/llfloatersettingsdebug.cpp @@ -39,17 +39,21 @@ #include "llspinctrl.h" #include "llcolorswatch.h" #include "llviewercontrol.h" +#include "lltexteditor.h" -LLFloaterSettingsDebug* LLFloaterSettingsDebug::sInstance = NULL; -LLFloaterSettingsDebug::LLFloaterSettingsDebug() : LLFloater(std::string("Configuration Editor")) +LLFloaterSettingsDebug::LLFloaterSettingsDebug(const LLSD& key) +: LLFloater(key) { + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_settings_debug.xml"); + mCommitCallbackRegistrar.add("SettingSelect", boost::bind(&LLFloaterSettingsDebug::onSettingSelect, this,_1)); + mCommitCallbackRegistrar.add("CommitSettings", boost::bind(&LLFloaterSettingsDebug::onCommitSettings, this)); + mCommitCallbackRegistrar.add("ClickDefault", boost::bind(&LLFloaterSettingsDebug::onClickDefault, this)); + } LLFloaterSettingsDebug::~LLFloaterSettingsDebug() -{ - sInstance = NULL; -} +{} BOOL LLFloaterSettingsDebug::postBuild() { @@ -68,30 +72,18 @@ BOOL LLFloaterSettingsDebug::postBuild() } } func(settings_combo); - gSavedSettings.applyToAll(&func); - gSavedPerAccountSettings.applyToAll(&func); - gColors.applyToAll(&func); + std::string key = getKey().asString(); + if (key == "all" || key == "base") + { + gSavedSettings.applyToAll(&func); + } + if (key == "all" || key == "account") + { + gSavedPerAccountSettings.applyToAll(&func); + } settings_combo->sortByName(); - settings_combo->setCommitCallback(onSettingSelect); - settings_combo->setCallbackUserData(this); settings_combo->updateSelection(); - - childSetCommitCallback("val_spinner_1", onCommitSettings); - childSetUserData("val_spinner_1", this); - childSetCommitCallback("val_spinner_2", onCommitSettings); - childSetUserData("val_spinner_2", this); - childSetCommitCallback("val_spinner_3", onCommitSettings); - childSetUserData("val_spinner_3", this); - childSetCommitCallback("val_spinner_4", onCommitSettings); - childSetUserData("val_spinner_4", this); - childSetCommitCallback("val_text", onCommitSettings); - childSetUserData("val_text", this); - childSetCommitCallback("boolean_combo", onCommitSettings); - childSetUserData("boolean_combo", this); - childSetCommitCallback("color_swatch", onCommitSettings); - childSetUserData("color_swatch", this); - childSetAction("default_btn", onClickDefault, this); mComment = getChild("comment_text"); return TRUE; } @@ -105,35 +97,18 @@ void LLFloaterSettingsDebug::draw() LLFloater::draw(); } -//static -void LLFloaterSettingsDebug::show(void*) -{ - if (sInstance == NULL) - { - sInstance = new LLFloaterSettingsDebug(); - - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_settings_debug.xml"); - } - - sInstance->open(); /* Flawfinder: ignore */ -} - //static -void LLFloaterSettingsDebug::onSettingSelect(LLUICtrl* ctrl, void* user_data) +void LLFloaterSettingsDebug::onSettingSelect(LLUICtrl* ctrl) { - LLFloaterSettingsDebug* floaterp = (LLFloaterSettingsDebug*)user_data; LLComboBox* combo_box = (LLComboBox*)ctrl; LLControlVariable* controlp = (LLControlVariable*)combo_box->getCurrentUserdata(); - floaterp->updateControl(controlp); + updateControl(controlp); } -//static -void LLFloaterSettingsDebug::onCommitSettings(LLUICtrl* ctrl, void* user_data) +void LLFloaterSettingsDebug::onCommitSettings() { - LLFloaterSettingsDebug* floaterp = (LLFloaterSettingsDebug*)user_data; - - LLComboBox* settings_combo = floaterp->getChild("settings_combo"); + LLComboBox* settings_combo = getChild("settings_combo"); LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); LLVector3 vector; @@ -147,73 +122,66 @@ void LLFloaterSettingsDebug::onCommitSettings(LLUICtrl* ctrl, void* user_data) switch(controlp->type()) { case TYPE_U32: - controlp->set(floaterp->childGetValue("val_spinner_1")); + controlp->set(childGetValue("val_spinner_1")); break; case TYPE_S32: - controlp->set(floaterp->childGetValue("val_spinner_1")); + controlp->set(childGetValue("val_spinner_1")); break; case TYPE_F32: - controlp->set(LLSD(floaterp->childGetValue("val_spinner_1").asReal())); + controlp->set(LLSD(childGetValue("val_spinner_1").asReal())); break; case TYPE_BOOLEAN: - controlp->set(floaterp->childGetValue("boolean_combo")); + controlp->set(childGetValue("boolean_combo")); break; case TYPE_STRING: - controlp->set(LLSD(floaterp->childGetValue("val_text").asString())); + controlp->set(LLSD(childGetValue("val_text").asString())); break; case TYPE_VEC3: - vector.mV[VX] = (F32)floaterp->childGetValue("val_spinner_1").asReal(); - vector.mV[VY] = (F32)floaterp->childGetValue("val_spinner_2").asReal(); - vector.mV[VZ] = (F32)floaterp->childGetValue("val_spinner_3").asReal(); + vector.mV[VX] = (F32)childGetValue("val_spinner_1").asReal(); + vector.mV[VY] = (F32)childGetValue("val_spinner_2").asReal(); + vector.mV[VZ] = (F32)childGetValue("val_spinner_3").asReal(); controlp->set(vector.getValue()); break; case TYPE_VEC3D: - vectord.mdV[VX] = floaterp->childGetValue("val_spinner_1").asReal(); - vectord.mdV[VY] = floaterp->childGetValue("val_spinner_2").asReal(); - vectord.mdV[VZ] = floaterp->childGetValue("val_spinner_3").asReal(); + vectord.mdV[VX] = childGetValue("val_spinner_1").asReal(); + vectord.mdV[VY] = childGetValue("val_spinner_2").asReal(); + vectord.mdV[VZ] = childGetValue("val_spinner_3").asReal(); controlp->set(vectord.getValue()); break; case TYPE_RECT: - rect.mLeft = floaterp->childGetValue("val_spinner_1").asInteger(); - rect.mRight = floaterp->childGetValue("val_spinner_2").asInteger(); - rect.mBottom = floaterp->childGetValue("val_spinner_3").asInteger(); - rect.mTop = floaterp->childGetValue("val_spinner_4").asInteger(); + rect.mLeft = childGetValue("val_spinner_1").asInteger(); + rect.mRight = childGetValue("val_spinner_2").asInteger(); + rect.mBottom = childGetValue("val_spinner_3").asInteger(); + rect.mTop = childGetValue("val_spinner_4").asInteger(); controlp->set(rect.getValue()); break; case TYPE_COL4: - col3.setValue(floaterp->childGetValue("color_swatch")); - col4 = LLColor4(col3, (F32)floaterp->childGetValue("val_spinner_4").asReal()); + col3.setValue(childGetValue("val_color_swatch")); + col4 = LLColor4(col3, (F32)childGetValue("val_spinner_4").asReal()); controlp->set(col4.getValue()); break; case TYPE_COL3: - controlp->set(floaterp->childGetValue("color_swatch")); + controlp->set(childGetValue("val_color_swatch")); //col3.mV[VRED] = (F32)floaterp->childGetValue("val_spinner_1").asC(); //col3.mV[VGREEN] = (F32)floaterp->childGetValue("val_spinner_2").asReal(); //col3.mV[VBLUE] = (F32)floaterp->childGetValue("val_spinner_3").asReal(); //controlp->set(col3.getValue()); break; - case TYPE_COL4U: - col3.setValue(floaterp->childGetValue("color_swatch")); - col4U.setVecScaleClamp(col3); - col4U.mV[VALPHA] = floaterp->childGetValue("val_spinner_4").asInteger(); - controlp->set(col4U.getValue()); - break; default: break; } } // static -void LLFloaterSettingsDebug::onClickDefault(void* user_data) +void LLFloaterSettingsDebug::onClickDefault() { - LLFloaterSettingsDebug* floaterp = (LLFloaterSettingsDebug*)user_data; - LLComboBox* settings_combo = floaterp->getChild("settings_combo"); + LLComboBox* settings_combo = getChild("settings_combo"); LLControlVariable* controlp = (LLControlVariable*)settings_combo->getCurrentUserdata(); if (controlp) { controlp->resetToDefault(); - floaterp->updateControl(controlp); + updateControl(controlp); } } @@ -224,7 +192,7 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) LLSpinCtrl* spinner2 = getChild("val_spinner_2"); LLSpinCtrl* spinner3 = getChild("val_spinner_3"); LLSpinCtrl* spinner4 = getChild("val_spinner_4"); - LLColorSwatchCtrl* color_swatch = getChild("color_swatch"); + LLColorSwatchCtrl* color_swatch = getChild("val_color_swatch"); if (!spinner1 || !spinner2 || !spinner3 || !spinner4 || !color_swatch) { @@ -464,29 +432,6 @@ void LLFloaterSettingsDebug::updateControl(LLControlVariable* controlp) color_swatch->setValue(sd); break; } - case TYPE_COL4U: - { - LLColor4U clr; - clr.setValue(sd); - color_swatch->setVisible(TRUE); - if(LLColor4(clr) != LLColor4(color_swatch->getValue())) - { - color_swatch->set(LLColor4(clr), TRUE, FALSE); - } - spinner4->setVisible(TRUE); - spinner4->setLabel(std::string("Alpha")); - if(!spinner4->hasFocus()) - { - spinner4->setPrecision(0); - spinner4->setValue(clr.mV[VALPHA]); - } - - spinner4->setMinValue(0); - spinner4->setMaxValue(255); - spinner4->setIncrement(1.f); - - break; - } default: mComment->setText(std::string("unknown")); break; diff --git a/indra/newview/llfloatersettingsdebug.h b/indra/newview/llfloatersettingsdebug.h index e08e6b5d74..65803fbf70 100644 --- a/indra/newview/llfloatersettingsdebug.h +++ b/indra/newview/llfloatersettingsdebug.h @@ -35,27 +35,31 @@ #include "llcontrol.h" #include "llfloater.h" -#include "lltexteditor.h" -class LLFloaterSettingsDebug : public LLFloater +class LLFloaterSettingsDebug +: public LLFloater { + friend class LLFloaterReg; + public: - LLFloaterSettingsDebug(); - virtual ~LLFloaterSettingsDebug(); virtual BOOL postBuild(); virtual void draw(); void updateControl(LLControlVariable* control); - static void show(void*); - static void onSettingSelect(LLUICtrl* ctrl, void* user_data); - static void onCommitSettings(LLUICtrl* ctrl, void* user_data); - static void onClickDefault(void* user_data); + void onSettingSelect(LLUICtrl* ctrl); + void onCommitSettings(); + void onClickDefault(); +private: + // key - selects which settings to show, one of: + // "all", "base", "account", "skin" + LLFloaterSettingsDebug(const LLSD& key); + virtual ~LLFloaterSettingsDebug(); + protected: - static LLFloaterSettingsDebug* sInstance; - LLTextEditor* mComment; + class LLTextEditor* mComment; }; #endif //LLFLOATERDEBUGSETTINGS_H diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index e68d699d03..b5c36b1083 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -34,20 +34,13 @@ #include "llfloatersnapshot.h" -#include "llfontgl.h" -#include "llsys.h" -#include "llgl.h" -#include "llrender.h" -#include "v3dmath.h" -#include "llmath.h" -#include "lldir.h" -#include "llsdserialize.h" +#include "llfloaterreg.h" +// Viewer includes #include "llagent.h" #include "llcallbacklist.h" #include "llcriticaldamp.h" #include "llui.h" -#include "llviewertexteditor.h" #include "llfocusmgr.h" #include "llbutton.h" #include "llcombobox.h" @@ -66,15 +59,26 @@ #include "lltoolfocus.h" #include "lltoolmgr.h" #include "llworld.h" +#include "llagentui.h" +// Linden library includes +#include "llfontgl.h" +#include "llsys.h" +#include "llrender.h" +#include "v3dmath.h" +#include "llmath.h" +#include "lldir.h" +#include "llsdserialize.h" #include "llgl.h" #include "llglheaders.h" #include "llimagejpeg.h" #include "llimagepng.h" #include "llimagebmp.h" #include "llimagej2c.h" +#include "llresmgr.h" // LLLocale #include "llvfile.h" #include "llvfs.h" +#include "llwindow.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -85,8 +89,6 @@ S32 LLFloaterSnapshot::sUIWinWidth = 215 ; LLSnapshotFloaterView* gSnapshotFloaterView = NULL; -LLFloaterSnapshot* LLFloaterSnapshot::sInstance = NULL; - const F32 AUTO_SNAPSHOT_TIME_DELAY = 1.f; F32 SHINE_TIME = 0.5f; @@ -112,7 +114,17 @@ public: }; - LLSnapshotLivePreview(const LLRect& rect); + struct Params : public LLInitParam::Block + { + Params() + { + name = "snapshot_live_preview"; + mouse_opaque = false; + } + }; + + + LLSnapshotLivePreview(const LLSnapshotLivePreview::Params& p); ~LLSnapshotLivePreview(); /*virtual*/ void draw(); @@ -128,12 +140,12 @@ public: LLFloaterSnapshot::ESnapshotFormat getSnapshotFormat() const { return mSnapshotFormat; } BOOL getSnapshotUpToDate() const { return mSnapshotUpToDate; } BOOL isSnapshotActive() { return mSnapshotActive; } - LLImageGL* getThumbnailImage() const { return mThumbnailImage ; } + LLViewerTexture* getThumbnailImage() const { return mThumbnailImage ; } S32 getThumbnailWidth() const { return mThumbnailWidth ; } S32 getThumbnailHeight() const { return mThumbnailHeight ; } BOOL getThumbnailLock() const { return mThumbnailUpdateLock ; } BOOL getThumbnailUpToDate() const { return mThumbnailUpToDate ;} - LLImageGL* getCurrentImage(); + LLViewerTexture* getCurrentImage(); F32 getImageAspect(); F32 getAspect() ; LLRect getImageRect(); @@ -158,7 +170,7 @@ public: private: LLColor4 mColor; - LLPointer mViewerImage[2]; //used to represent the scene when the frame is frozen. + LLPointer mViewerImage[2]; //used to represent the scene when the frame is frozen. LLRect mImageRect[2]; S32 mWidth[2]; S32 mHeight[2]; @@ -166,7 +178,7 @@ private: S32 mMaxImageSize ; //thumbnail image - LLPointer mThumbnailImage ; + LLPointer mThumbnailImage ; S32 mThumbnailWidth ; S32 mThumbnailHeight ; LLRect mPreviewRect ; @@ -200,8 +212,9 @@ public: }; std::set LLSnapshotLivePreview::sList; -LLSnapshotLivePreview::LLSnapshotLivePreview (const LLRect& rect) : - LLView(std::string("snapshot_live_preview"), rect, FALSE), + +LLSnapshotLivePreview::LLSnapshotLivePreview (const LLSnapshotLivePreview::Params& p) +: LLView(p), mColor(1.f, 0.f, 0.f, 0.5f), mCurImageIndex(0), mPreviewImage(NULL), @@ -265,7 +278,7 @@ void LLSnapshotLivePreview::setMaxImageSize(S32 size) } } -LLImageGL* LLSnapshotLivePreview::getCurrentImage() +LLViewerTexture* LLSnapshotLivePreview::getCurrentImage() { return mViewerImage[mCurImageIndex]; } @@ -472,10 +485,6 @@ void LLSnapshotLivePreview::draw() } else if (mShineAnimTimer.getStarted()) { - //LLDebugVarMessageBox::show("Shine time", &SHINE_TIME, 10.f, 0.1f); - //LLDebugVarMessageBox::show("Shine width", &SHINE_WIDTH, 2.f, 0.05f); - //LLDebugVarMessageBox::show("Shine opacity", &SHINE_OPACITY, 1.f, 0.05f); - F32 shine_interp = llmin(1.f, mShineAnimTimer.getElapsedTimeF32() / SHINE_TIME); // draw "shine" effect @@ -714,7 +723,7 @@ void LLSnapshotLivePreview::generateThumbnailImage(BOOL force_update) if(raw) { - mThumbnailImage = new LLImageGL(raw, FALSE); + mThumbnailImage = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); mThumbnailUpToDate = TRUE ; } @@ -862,8 +871,8 @@ BOOL LLSnapshotLivePreview::onIdle( void* snapshot_preview ) scaled->expandToPowerOfTwo(1024, FALSE); } - previewp->mViewerImage[previewp->mCurImageIndex] = new LLImageGL(scaled, FALSE); - LLPointer curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; + previewp->mViewerImage[previewp->mCurImageIndex] = LLViewerTextureManager::getLocalTexture(scaled.get(), FALSE); + LLPointer curr_preview_image = previewp->mViewerImage[previewp->mCurImageIndex]; gGL.getTexUnit(0)->bind(curr_preview_image); if (previewp->getSnapshotType() != SNAPSHOT_TEXTURE) { @@ -959,9 +968,9 @@ void LLSnapshotLivePreview::saveTexture() { LLVFile::writeFile(formatted->getData(), formatted->getDataSize(), gVFS, new_asset_id, LLAssetType::AT_TEXTURE); std::string pos_string; - gAgent.buildLocationString(pos_string); + LLAgentUI::buildLocationString(pos_string, LLAgentUI::LOCATION_FORMAT_FULL); std::string who_took_it; - gAgent.buildFullname(who_took_it); + LLAgentUI::buildFullname(who_took_it); LLAssetStorage::LLStoreAssetCallback callback = NULL; S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(); void *userdata = NULL; @@ -1053,9 +1062,6 @@ public: static void updateLayout(LLFloaterSnapshot* floater); static void updateResolutionTextEntry(LLFloaterSnapshot* floater); - static LLHandle sPreviewHandle; - static BOOL sAspectRatioCheckOff ; - private: static LLSnapshotLivePreview::ESnapshotType getTypeIndex(LLFloaterSnapshot* floater); static ESnapshotFormat getFormatIndex(LLFloaterSnapshot* floater); @@ -1068,18 +1074,14 @@ public: std::vector mAvatarPauseHandles; LLToolset* mLastToolset; + LLHandle mPreviewHandle; + BOOL mAspectRatioCheckOff ; }; -// static -LLHandle LLFloaterSnapshot::Impl::sPreviewHandle; - -//static -BOOL LLFloaterSnapshot::Impl::sAspectRatioCheckOff = FALSE ; - // static LLSnapshotLivePreview* LLFloaterSnapshot::Impl::getPreviewView(LLFloaterSnapshot *floater) { - LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)sPreviewHandle.get(); + LLSnapshotLivePreview* previewp = (LLSnapshotLivePreview*)floater->impl.mPreviewHandle.get(); return previewp; } @@ -1186,7 +1188,7 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) iter != LLCharacter::sInstances.end(); ++iter) { avatarp = *iter; - sInstance->impl.mAvatarPauseHandles.push_back(avatarp->requestPause()); + floaterp->impl.mAvatarPauseHandles.push_back(avatarp->requestPause()); } // freeze everything else @@ -1194,7 +1196,7 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) if (LLToolMgr::getInstance()->getCurrentToolset() != gCameraToolset) { - sInstance->impl.mLastToolset = LLToolMgr::getInstance()->getCurrentToolset(); + floaterp->impl.mLastToolset = LLToolMgr::getInstance()->getCurrentToolset(); LLToolMgr::getInstance()->setCurrentToolset(gCameraToolset); } } @@ -1209,15 +1211,15 @@ void LLFloaterSnapshot::Impl::updateLayout(LLFloaterSnapshot* floaterp) } //RN: thaw all avatars - sInstance->impl.mAvatarPauseHandles.clear(); + floaterp->impl.mAvatarPauseHandles.clear(); // thaw everything else gSavedSettings.setBOOL("FreezeTime", FALSE); // restore last tool (e.g. pie menu, etc) - if (sInstance->impl.mLastToolset) + if (floaterp->impl.mLastToolset) { - LLToolMgr::getInstance()->setCurrentToolset(sInstance->impl.mLastToolset); + LLToolMgr::getInstance()->setCurrentToolset(floaterp->impl.mLastToolset); } } } @@ -1248,7 +1250,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) floater->childSetVisible("upload_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_TEXTURE); floater->childSetVisible("send_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD); floater->childSetVisible("save_btn", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); - floater->childSetEnabled("keep_aspect_check", shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE && !sAspectRatioCheckOff); + floater->childSetEnabled("keep_aspect_check", shot_type != LLSnapshotLivePreview::SNAPSHOT_TEXTURE && !floater->impl.mAspectRatioCheckOff); floater->childSetEnabled("layer_types", shot_type == LLSnapshotLivePreview::SNAPSHOT_LOCAL); BOOL is_advance = gSavedSettings.getBOOL("AdvanceSnapshot"); @@ -1295,7 +1297,7 @@ void LLFloaterSnapshot::Impl::updateControls(LLFloaterSnapshot* floater) floater->childSetColor("file_size_label", shot_type == LLSnapshotLivePreview::SNAPSHOT_POSTCARD && got_bytes - && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLColor4::red : gColors.getColor( "LabelTextColor" )); + && previewp->getDataSize() > MAX_POSTCARD_DATASIZE ? LLUIColor(LLColor4::red) : LLUIColorTable::instance().getColor( "LabelTextColor" )); switch(shot_type) { @@ -1369,7 +1371,7 @@ void LLFloaterSnapshot::Impl::onClickDiscard(void* data) LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; if (view) { - view->close(); + view->closeFloater(); } } @@ -1415,7 +1417,7 @@ void LLFloaterSnapshot::Impl::onClickKeep(void* data) if (gSavedSettings.getBOOL("CloseSnapshotOnKeep")) { - view->close(); + view->closeFloater(); } else { @@ -1596,7 +1598,7 @@ void LLFloaterSnapshot::Impl::checkAspectRatio(LLFloaterSnapshot *view, S32 inde if(0 == index) //current window size { - sAspectRatioCheckOff = TRUE ; + view->impl.mAspectRatioCheckOff = TRUE ; view->childSetEnabled("keep_aspect_check", FALSE) ; if(previewp) @@ -1606,7 +1608,7 @@ void LLFloaterSnapshot::Impl::checkAspectRatio(LLFloaterSnapshot *view, S32 inde } else if(-1 == index) //custom { - sAspectRatioCheckOff = FALSE ; + view->impl.mAspectRatioCheckOff = FALSE ; //if(LLSnapshotLivePreview::SNAPSHOT_TEXTURE != gSavedSettings.getS32("LastSnapshotType")) { view->childSetEnabled("keep_aspect_check", TRUE) ; @@ -1619,7 +1621,7 @@ void LLFloaterSnapshot::Impl::checkAspectRatio(LLFloaterSnapshot *view, S32 inde } else { - sAspectRatioCheckOff = TRUE ; + view->impl.mAspectRatioCheckOff = TRUE ; view->childSetEnabled("keep_aspect_check", FALSE) ; if(previewp) @@ -1955,21 +1957,17 @@ void LLFloaterSnapshot::Impl::onCommitCustomResolution(LLUICtrl *ctrl, void* dat ///---------------------------------------------------------------------------- // Default constructor -LLFloaterSnapshot::LLFloaterSnapshot() - : LLFloater(std::string("Snapshot Floater")), +LLFloaterSnapshot::LLFloaterSnapshot(const LLSD& key) + : LLFloater(key), impl (*(new Impl)) { + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_snapshot.xml", FALSE); } // Destroys the object LLFloaterSnapshot::~LLFloaterSnapshot() { - if (sInstance == this) - { - LLView::deleteViewByHandle(Impl::sPreviewHandle); - Impl::sPreviewHandle = LLHandle(); - sInstance = NULL; - } + LLView::deleteViewByHandle(impl.mPreviewHandle); //unfreeze everything else gSavedSettings.setBOOL("FreezeTime", FALSE); @@ -2034,16 +2032,22 @@ BOOL LLFloaterSnapshot::postBuild() childSetCommitCallback("local_size_combo", Impl::onCommitResolution, this); // create preview window - LLRect full_screen_rect = sInstance->getRootView()->getRect(); - LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(full_screen_rect); - sInstance->getRootView()->removeChild(gSnapshotFloaterView); + LLRect full_screen_rect = getRootView()->getRect(); + LLSnapshotLivePreview::Params p; + p.rect(full_screen_rect); + LLSnapshotLivePreview* previewp = new LLSnapshotLivePreview(p); + getRootView()->removeChild(gSnapshotFloaterView); // make sure preview is below snapshot floater - sInstance->getRootView()->addChild(previewp); - sInstance->getRootView()->addChild(gSnapshotFloaterView); - - Impl::sPreviewHandle = previewp->getHandle(); + getRootView()->addChild(previewp); + getRootView()->addChild(gSnapshotFloaterView); + + //move snapshot floater to special purpose snapshotfloaterview + gFloaterView->removeChild(this); + gSnapshotFloaterView->addChild(this); + impl.mPreviewHandle = previewp->getHandle(); impl.updateControls(this); + impl.updateLayout(this); return TRUE; } @@ -2077,54 +2081,26 @@ void LLFloaterSnapshot::draw() } } -void LLFloaterSnapshot::onClose(bool app_quitting) +void LLFloaterSnapshot::onOpen(const LLSD& key) { - gSnapshotFloaterView->setEnabled(FALSE); - // Set invisible so it doesn't eat tooltips. JC - gSnapshotFloaterView->setVisible(FALSE); - destroy(); -} - -// static -void LLFloaterSnapshot::show(void*) -{ - if (!sInstance) + LLSnapshotLivePreview* preview = LLFloaterSnapshot::Impl::getPreviewView(this); + if(preview) { - sInstance = new LLFloaterSnapshot(); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_snapshot.xml", NULL, FALSE); - //move snapshot floater to special purpose snapshotfloaterview - gFloaterView->removeChild(sInstance); - gSnapshotFloaterView->addChild(sInstance); - - sInstance->impl.updateLayout(sInstance); + preview->updateSnapshot(TRUE); } - else // just refresh the snapshot in the existing floater instance (DEV-12255) - { - LLSnapshotLivePreview* preview = LLFloaterSnapshot::Impl::getPreviewView(sInstance); - if(preview) - { - preview->updateSnapshot(TRUE); - } - } - - sInstance->open(); /* Flawfinder: ignore */ - sInstance->focusFirstItem(FALSE); + focusFirstItem(FALSE); gSnapshotFloaterView->setEnabled(TRUE); gSnapshotFloaterView->setVisible(TRUE); - gSnapshotFloaterView->adjustToFitScreen(sInstance, FALSE); -} - -void LLFloaterSnapshot::hide(void*) -{ - if (sInstance && !sInstance->isDead()) - { - sInstance->close(); - } + gSnapshotFloaterView->adjustToFitScreen(this, FALSE); } //static void LLFloaterSnapshot::update() { + LLFloaterSnapshot* inst = LLFloaterReg::findTypedInstance("snapshot"); + if (!inst) + return; + BOOL changed = FALSE; for (std::set::iterator iter = LLSnapshotLivePreview::sList.begin(); iter != LLSnapshotLivePreview::sList.end(); ++iter) @@ -2133,7 +2109,7 @@ void LLFloaterSnapshot::update() } if(changed) { - sInstance->impl.updateControls(sInstance); + inst->impl.updateControls(inst); } } @@ -2142,10 +2118,8 @@ void LLFloaterSnapshot::update() /// Class LLSnapshotFloaterView ///---------------------------------------------------------------------------- -LLSnapshotFloaterView::LLSnapshotFloaterView( const std::string& name, const LLRect& rect ) : LLFloaterView(name, rect) +LLSnapshotFloaterView::LLSnapshotFloaterView (const Params& p) : LLFloaterView (p) { - setMouseOpaque(TRUE); - setEnabled(FALSE); } LLSnapshotFloaterView::~LLSnapshotFloaterView() diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 14f1872cd1..bd01f6c573 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -35,10 +35,6 @@ #include "llfloater.h" -#include "llmemory.h" -#include "llimagegl.h" -#include "llcharacter.h" - class LLFloaterSnapshot : public LLFloater { @@ -50,17 +46,15 @@ public: SNAPSHOT_FORMAT_BMP } ESnapshotFormat; - LLFloaterSnapshot(); + LLFloaterSnapshot(const LLSD& key); virtual ~LLFloaterSnapshot(); - + /*virtual*/ BOOL postBuild(); /*virtual*/ void draw(); - /*virtual*/ void onClose(bool app_quitting); - - static void show(void*); - static void hide(void*); + /*virtual*/ void onOpen(const LLSD& key); + static void update(); - + static S32 getUIWinHeightLong() {return sUIWinHeightLong ;} static S32 getUIWinHeightShort() {return sUIWinHeightShort ;} static S32 getUIWinWidth() {return sUIWinWidth ;} @@ -69,7 +63,6 @@ private: class Impl; Impl& impl; - static LLFloaterSnapshot* sInstance; static S32 sUIWinHeightLong ; static S32 sUIWinHeightShort ; static S32 sUIWinWidth ; @@ -78,7 +71,16 @@ private: class LLSnapshotFloaterView : public LLFloaterView { public: - LLSnapshotFloaterView( const std::string& name, const LLRect& rect ); + struct Params + : public LLInitParam::Block + { + }; + +protected: + LLSnapshotFloaterView (const Params& p); + friend class LLUICtrlFactory; + +public: virtual ~LLSnapshotFloaterView(); /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); diff --git a/indra/newview/llfloatertelehub.cpp b/indra/newview/llfloatertelehub.cpp index 530bb87983..9841cd2796 100644 --- a/indra/newview/llfloatertelehub.cpp +++ b/indra/newview/llfloatertelehub.cpp @@ -39,6 +39,7 @@ #include "llfontgl.h" #include "llagent.h" +#include "llfloaterreg.h" #include "llfloatertools.h" #include "llscrolllistctrl.h" #include "llselectmgr.h" @@ -48,56 +49,25 @@ #include "llviewerobjectlist.h" #include "lluictrlfactory.h" -LLFloaterTelehub* LLFloaterTelehub::sInstance = NULL; - - -// static -void LLFloaterTelehub::show() -{ - if (sInstance) - { - sInstance->setVisibleAndFrontmost(); - return; - } - - sInstance = new LLFloaterTelehub(); - - // Show tools floater by selecting translate (select) tool - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); - - // Find tools floater, glue to bottom - if (gFloaterTools) - { - LLRect tools_rect = gFloaterTools->getRect(); - S32 our_width = sInstance->getRect().getWidth(); - S32 our_height = sInstance->getRect().getHeight(); - LLRect our_rect; - our_rect.setLeftTopAndSize(tools_rect.mLeft, tools_rect.mBottom, our_width, our_height); - sInstance->setRect(our_rect); - } - - sInstance->sendTelehubInfoRequest(); -} - -LLFloaterTelehub::LLFloaterTelehub() -: LLFloater(std::string("telehub")), +LLFloaterTelehub::LLFloaterTelehub(const LLSD& key) +: LLFloater(key), mTelehubObjectID(), mTelehubObjectName(), mTelehubPos(), mTelehubRot(), mNumSpawn(0) { - sInstance = this; + //LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_telehub.xml"); +} +BOOL LLFloaterTelehub::postBuild() +{ gMessageSystem->setHandlerFunc("TelehubInfo", processTelehubInfo); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_telehub.xml"); - - childSetAction("connect_btn", onClickConnect, this); - childSetAction("disconnect_btn", onClickDisconnect, this); - childSetAction("add_spawn_point_btn", onClickAddSpawnPoint, this); - childSetAction("remove_spawn_point_btn", onClickRemoveSpawnPoint, this); + getChild("connect_btn")->setCommitCallback(boost::bind(&LLFloaterTelehub::onClickConnect, this)); + getChild("disconnect_btn")->setCommitCallback(boost::bind(&LLFloaterTelehub::onClickDisconnect, this)); + getChild("add_spawn_point_btn")->setCommitCallback(boost::bind(&LLFloaterTelehub::onClickAddSpawnPoint, this)); + getChild("remove_spawn_point_btn")->setCommitCallback(boost::bind(&LLFloaterTelehub::onClickRemoveSpawnPoint, this)); LLScrollListCtrl* list = getChild("spawn_points_list"); if (list) @@ -106,13 +76,32 @@ LLFloaterTelehub::LLFloaterTelehub() list->setAllowKeyboardMovement(FALSE); } + return TRUE; +} +void LLFloaterTelehub::onOpen(const LLSD& key) +{ + // Show tools floater by selecting translate (select) tool + LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompTranslate::getInstance() ); + + // Find tools floater, glue to bottom + if (gFloaterTools) + { + LLRect tools_rect = gFloaterTools->getRect(); + S32 our_width = getRect().getWidth(); + S32 our_height = getRect().getHeight(); + LLRect our_rect; + our_rect.setLeftTopAndSize(tools_rect.mLeft, tools_rect.mBottom, our_width, our_height); + setRect(our_rect); + } + + sendTelehubInfoRequest(); + mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); } LLFloaterTelehub::~LLFloaterTelehub() { - sInstance = NULL; - // no longer interested in this message gMessageSystem->setHandlerFunc("TelehubInfo", NULL); } @@ -154,19 +143,22 @@ void LLFloaterTelehub::refresh() BOOL LLFloaterTelehub::renderBeacons() { // only render if we've got a telehub - return sInstance && sInstance->mTelehubObjectID.notNull(); + LLFloaterTelehub* floater = LLFloaterReg::findTypedInstance("telehubs"); + return floater && floater->mTelehubObjectID.notNull(); } // static void LLFloaterTelehub::addBeacons() { - if (!sInstance) return; - + LLFloaterTelehub* floater = LLFloaterReg::findTypedInstance("telehubs"); + if (!floater) + return; + // Find the telehub position, either our cached old position, or // an updated one based on the actual object position. - LLVector3 hub_pos_region = sInstance->mTelehubPos; - LLQuaternion hub_rot = sInstance->mTelehubRot; - LLViewerObject* obj = gObjectList.findObject(sInstance->mTelehubObjectID); + LLVector3 hub_pos_region = floater->mTelehubPos; + LLQuaternion hub_rot = floater->mTelehubRot; + LLViewerObject* obj = gObjectList.findObject(floater->mTelehubObjectID); if (obj) { hub_pos_region = obj->getPositionRegion(); @@ -175,13 +167,13 @@ void LLFloaterTelehub::addBeacons() // Draw nice thick 3-pixel lines. gObjectList.addDebugBeacon(hub_pos_region, "", LLColor4::yellow, LLColor4::white, 4); - LLScrollListCtrl* list = sInstance->getChild("spawn_points_list"); + LLScrollListCtrl* list = floater->getChild("spawn_points_list"); if (list) { S32 spawn_index = list->getFirstSelectedIndex(); if (spawn_index >= 0) { - LLVector3 spawn_pos = hub_pos_region + (sInstance->mSpawnPointPos[spawn_index] * hub_rot); + LLVector3 spawn_pos = hub_pos_region + (floater->mSpawnPointPos[spawn_index] * hub_rot); gObjectList.addDebugBeacon(spawn_pos, "", LLColor4::orange, LLColor4::white, 4); } } @@ -192,32 +184,27 @@ void LLFloaterTelehub::sendTelehubInfoRequest() LLSelectMgr::getInstance()->sendGodlikeRequest("telehub", "info ui"); } -// static -void LLFloaterTelehub::onClickConnect(void* data) +void LLFloaterTelehub::onClickConnect() { LLSelectMgr::getInstance()->sendGodlikeRequest("telehub", "connect"); } -// static -void LLFloaterTelehub::onClickDisconnect(void* data) +void LLFloaterTelehub::onClickDisconnect() { LLSelectMgr::getInstance()->sendGodlikeRequest("telehub", "delete"); } -// static -void LLFloaterTelehub::onClickAddSpawnPoint(void* data) +void LLFloaterTelehub::onClickAddSpawnPoint() { LLSelectMgr::getInstance()->sendGodlikeRequest("telehub", "spawnpoint add"); LLSelectMgr::getInstance()->deselectAll(); } -// static -void LLFloaterTelehub::onClickRemoveSpawnPoint(void* data) +void LLFloaterTelehub::onClickRemoveSpawnPoint() { - if (!sInstance) return; - - LLScrollListCtrl* list = sInstance->getChild("spawn_points_list"); - if (!list) return; + LLScrollListCtrl* list = getChild("spawn_points_list"); + if (!list) + return; S32 spawn_index = list->getFirstSelectedIndex(); if (spawn_index < 0) return; // nothing selected @@ -255,9 +242,10 @@ void LLFloaterTelehub::onClickRemoveSpawnPoint(void* data) // static void LLFloaterTelehub::processTelehubInfo(LLMessageSystem* msg, void**) { - if (sInstance) + LLFloaterTelehub* floater = LLFloaterReg::findTypedInstance("telehubs"); + if (floater) { - sInstance->unpackTelehubInfo(msg); + floater->unpackTelehubInfo(msg); } } diff --git a/indra/newview/llfloatertelehub.h b/indra/newview/llfloatertelehub.h index 28c9d16573..5b654585f1 100644 --- a/indra/newview/llfloatertelehub.h +++ b/indra/newview/llfloatertelehub.h @@ -44,25 +44,24 @@ const S32 MAX_SPAWNPOINTS_PER_TELEHUB = 16; class LLFloaterTelehub : public LLFloater { public: - // Opens the floater on screen. - static void show(); - - virtual void draw(); + LLFloaterTelehub(const LLSD& key); + ~LLFloaterTelehub(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ void draw(); + static BOOL renderBeacons(); static void addBeacons(); -private: - LLFloaterTelehub(); - ~LLFloaterTelehub(); - void refresh(); void sendTelehubInfoRequest(); - static void onClickConnect(void* data); - static void onClickDisconnect(void* data); - static void onClickAddSpawnPoint(void* data); - static void onClickRemoveSpawnPoint(void* data); + void onClickConnect(); + void onClickDisconnect(); + void onClickAddSpawnPoint(); + void onClickRemoveSpawnPoint(); static void processTelehubInfo(LLMessageSystem* msg, void**); void unpackTelehubInfo(LLMessageSystem* msg); diff --git a/indra/newview/llfloatertestlistview.cpp b/indra/newview/llfloatertestlistview.cpp new file mode 100644 index 0000000000..5c942d0ed9 --- /dev/null +++ b/indra/newview/llfloatertestlistview.cpp @@ -0,0 +1,77 @@ +/** +* @file llfloatertestlistview.cpp +* @brief Tests of programmatic manipulation of LLListView widgets +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#include "llviewerprecompiledheaders.h" + +#include "llfloatertestlistview.h" + +// Viewer includes +#include "lllistview.h" + +// Linden library includes +//#include "lluictrlfactory.h" + +LLFloaterTestListView::LLFloaterTestListView(const LLSD& seed) +: LLFloater(seed), + mListView(NULL) +{ + // set up named callback functions for test buttons + mCommitCallbackRegistrar.add("TestListView.Test1", + boost::bind(&LLFloaterTestListView::onClickTest1, this)); + mCommitCallbackRegistrar.add("TestListView.Test2", + boost::bind(&LLFloaterTestListView::onClickTest2, this)); +} + +LLFloaterTestListView::~LLFloaterTestListView() +{} + +BOOL LLFloaterTestListView::postBuild() +{ + mListView = getChild("test_list_view"); + // just set a random property + mListView->setString("set programmatically"); + return LLFloater::postBuild(); +} + +void LLFloaterTestListView::onListViewChanged() +{ + llinfos << "list view changed" << llendl; +} + +void LLFloaterTestListView::onClickTest1() +{ + llinfos << "test 1" << llendl; +} + +void LLFloaterTestListView::onClickTest2() +{ + llinfos << "test 2" << llendl; +} diff --git a/indra/newview/llfloatertestlistview.h b/indra/newview/llfloatertestlistview.h new file mode 100644 index 0000000000..053da95def --- /dev/null +++ b/indra/newview/llfloatertestlistview.h @@ -0,0 +1,64 @@ +/** +* @file llfloatertestlistview.h +* @brief Tests of programmatic manipulation of LLListView widgets +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#ifndef LLFLOATERTESTLISTVIEW_H +#define LLFLOATERTESTLISTVIEW_H + +#include "llfloater.h" + +class LLListView; +class LLSD; + +class LLFloaterTestListView : public LLFloater +{ + friend class LLFloaterReg; +public: + // nothing yet + +private: + // Construction handled by LLFloaterReg + LLFloaterTestListView(const LLSD& seed); + ~LLFloaterTestListView(); + + /*virtual*/ BOOL postBuild(); + + // Perform some debug action when the list-view sends change notification + void onListViewChanged(); + + // Debug function hookups for buttons + void onClickTest1(); + void onClickTest2(); + +private: + LLListView* mListView; +}; + +#endif diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp index a33b49563c..d05c9cb9a7 100644 --- a/indra/newview/llfloatertools.cpp +++ b/indra/newview/llfloatertools.cpp @@ -45,6 +45,7 @@ #include "lldraghandle.h" #include "llfloaterbuildoptions.h" #include "llfloateropenobject.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llmenugl.h" #include "llpanelcontents.h" @@ -54,6 +55,7 @@ #include "llpanelobject.h" #include "llpanelvolume.h" #include "llpanelpermissions.h" +#include "llradiogroup.h" #include "llresmgr.h" #include "llselectmgr.h" #include "llslider.h" @@ -95,25 +97,21 @@ const std::string PANEL_NAMES[LLFloaterTools::PANEL_COUNT] = }; // Local prototypes -void commit_select_tool(LLUICtrl *ctrl, void *data); void commit_select_component(LLUICtrl *ctrl, void *data); void click_show_more(void*); void click_popup_info(void*); void click_popup_done(void*); void click_popup_minimize(void*); -void click_popup_grab_drag(LLUICtrl *, void*); -void click_popup_grab_lift(LLUICtrl *, void*); -void click_popup_grab_spin(LLUICtrl *, void*); void click_popup_rotate_left(void*); void click_popup_rotate_reset(void*); void click_popup_rotate_right(void*); -void click_popup_dozer_mode(LLUICtrl *, void *user); void commit_slider_dozer_size(LLUICtrl *, void*); void commit_slider_dozer_force(LLUICtrl *, void*); void click_apply_to_selection(void*); -void commit_radio_zoom(LLUICtrl *, void*); -void commit_radio_orbit(LLUICtrl *, void*); -void commit_radio_pan(LLUICtrl *, void*); +void commit_radio_group_focus(LLUICtrl* ctrl, void* data); +void commit_radio_group_move(LLUICtrl* ctrl, void* data); +void commit_radio_group_edit(LLUICtrl* ctrl, void* data); +void commit_radio_group_land(LLUICtrl* ctrl, void* data); void commit_grid_mode(LLUICtrl *, void*); void commit_slider_zoom(LLUICtrl *, void*); @@ -122,14 +120,14 @@ void commit_slider_zoom(LLUICtrl *, void*); void* LLFloaterTools::createPanelPermissions(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelPermissions = new LLPanelPermissions("General"); + floater->mPanelPermissions = new LLPanelPermissions(); return floater->mPanelPermissions; } //static void* LLFloaterTools::createPanelObject(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelObject = new LLPanelObject("Object"); + floater->mPanelObject = new LLPanelObject(); return floater->mPanelObject; } @@ -137,7 +135,7 @@ void* LLFloaterTools::createPanelObject(void* data) void* LLFloaterTools::createPanelVolume(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelVolume = new LLPanelVolume("Features"); + floater->mPanelVolume = new LLPanelVolume(); return floater->mPanelVolume; } @@ -145,7 +143,7 @@ void* LLFloaterTools::createPanelVolume(void* data) void* LLFloaterTools::createPanelFace(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelFace = new LLPanelFace("Texture"); + floater->mPanelFace = new LLPanelFace(); return floater->mPanelFace; } @@ -153,28 +151,54 @@ void* LLFloaterTools::createPanelFace(void* data) void* LLFloaterTools::createPanelContents(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelContents = new LLPanelContents("Contents"); + floater->mPanelContents = new LLPanelContents(); return floater->mPanelContents; } -//static -void* LLFloaterTools::createPanelContentsInventory(void* data) -{ - LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelContents->mPanelInventory = new LLPanelInventory(std::string("ContentsInventory"), LLRect()); - return floater->mPanelContents->mPanelInventory; -} - //static void* LLFloaterTools::createPanelLandInfo(void* data) { LLFloaterTools* floater = (LLFloaterTools*)data; - floater->mPanelLandInfo = new LLPanelLandInfo(std::string("land info panel")); + floater->mPanelLandInfo = new LLPanelLandInfo(); return floater->mPanelLandInfo; } +static const std::string toolNames[]={ + "ToolCube", + "ToolPrism", + "ToolPyramid", + "ToolTetrahedron", + "ToolCylinder", + "ToolHemiCylinder", + "ToolCone", + "ToolHemiCone", + "ToolSphere", + "ToolHemiSphere", + "ToolTorus", + "ToolTube", + "ToolRing", + "ToolTree", + "ToolGrass"}; +LLPCode toolData[]={ + LL_PCODE_CUBE, + LL_PCODE_PRISM, + LL_PCODE_PYRAMID, + LL_PCODE_TETRAHEDRON, + LL_PCODE_CYLINDER, + LL_PCODE_CYLINDER_HEMI, + LL_PCODE_CONE, + LL_PCODE_CONE_HEMI, + LL_PCODE_SPHERE, + LL_PCODE_SPHERE_HEMI, + LL_PCODE_TORUS, + LLViewerObject::LL_VO_SQUARE_TORUS, + LLViewerObject::LL_VO_TRIANGLE_TORUS, + LL_PCODE_LEGACY_TREE, + LL_PCODE_LEGACY_GRASS}; + BOOL LLFloaterTools::postBuild() { + mCloseSignal.connect(boost::bind(&LLFloaterTools::onClose, this)); // Hide until tool selected setVisible(FALSE); @@ -200,27 +224,15 @@ BOOL LLFloaterTools::postBuild() childSetCommitCallback("slider zoom",commit_slider_zoom,this); - mRadioZoom = getChild("radio zoom"); - childSetCommitCallback("radio zoom",commit_radio_zoom,this); - mRadioOrbit = getChild("radio orbit"); - childSetCommitCallback("radio orbit",commit_radio_orbit,this); - mRadioPan = getChild("radio pan"); - childSetCommitCallback("radio pan",commit_radio_pan,this); + mRadioGroupFocus = getChild("focus_radio_group"); + childSetCommitCallback("focus_radio_group", commit_radio_group_focus, this); + + mRadioGroupMove = getChild("move_radio_group"); + childSetCommitCallback("move_radio_group", commit_radio_group_move, this); + + mRadioGroupEdit = getChild("edit_radio_group"); + childSetCommitCallback("edit_radio_group", commit_radio_group_edit, this); - mRadioMove = getChild("radio move"); - childSetCommitCallback("radio move",click_popup_grab_drag,this); - mRadioLift = getChild("radio lift"); - childSetCommitCallback("radio lift",click_popup_grab_lift,this); - mRadioSpin = getChild("radio spin"); - childSetCommitCallback("radio spin",click_popup_grab_spin,NULL); - mRadioPosition = getChild("radio position"); - childSetCommitCallback("radio position",commit_select_tool,LLToolCompTranslate::getInstance()); - mRadioRotate = getChild("radio rotate"); - childSetCommitCallback("radio rotate",commit_select_tool,LLToolCompRotate::getInstance()); - mRadioStretch = getChild("radio stretch"); - childSetCommitCallback("radio stretch",commit_select_tool,LLToolCompScale::getInstance()); - mRadioSelectFace = getChild("radio select face"); - childSetCommitCallback("radio select face",commit_select_tool,LLToolFace::getInstance()); mCheckSelectIndividual = getChild("checkbox edit linked parts"); childSetValue("checkbox edit linked parts",(BOOL)gSavedSettings.getBOOL("EditLinkedParts")); childSetCommitCallback("checkbox edit linked parts",commit_select_component,this); @@ -239,44 +251,12 @@ BOOL LLFloaterTools::postBuild() // Create Buttons // - static const std::string toolNames[]={ - "ToolCube", - "ToolPrism", - "ToolPyramid", - "ToolTetrahedron", - "ToolCylinder", - "ToolHemiCylinder", - "ToolCone", - "ToolHemiCone", - "ToolSphere", - "ToolHemiSphere", - "ToolTorus", - "ToolTube", - "ToolRing", - "ToolTree", - "ToolGrass"}; - void* toolData[]={ - &LLToolPlacerPanel::sCube, - &LLToolPlacerPanel::sPrism, - &LLToolPlacerPanel::sPyramid, - &LLToolPlacerPanel::sTetrahedron, - &LLToolPlacerPanel::sCylinder, - &LLToolPlacerPanel::sCylinderHemi, - &LLToolPlacerPanel::sCone, - &LLToolPlacerPanel::sConeHemi, - &LLToolPlacerPanel::sSphere, - &LLToolPlacerPanel::sSphereHemi, - &LLToolPlacerPanel::sTorus, - &LLToolPlacerPanel::sSquareTorus, - &LLToolPlacerPanel::sTriangleTorus, - &LLToolPlacerPanel::sTree, - &LLToolPlacerPanel::sGrass}; for(size_t t=0; t(toolNames[t]); if(found) { - found->setClickedCallback(setObjectType,toolData[t]); + found->setClickedCallback(boost::bind(&LLFloaterTools::setObjectType, toolData[t])); mButtons.push_back( found ); }else{ llwarns << "Tool button not found! DOA Pending." << llendl; @@ -290,20 +270,10 @@ BOOL LLFloaterTools::postBuild() childSetValue("checkbox copy centers",(BOOL)gSavedSettings.getBOOL("CreateToolCopyCenters")); mCheckCopyRotates = getChild("checkbox copy rotates"); childSetValue("checkbox copy rotates",(BOOL)gSavedSettings.getBOOL("CreateToolCopyRotates")); - mRadioSelectLand = getChild("radio select land"); - childSetCommitCallback("radio select land",commit_select_tool, LLToolSelectLand::getInstance()); - mRadioDozerFlatten = getChild("radio flatten"); - childSetCommitCallback("radio flatten",click_popup_dozer_mode, (void*)0); - mRadioDozerRaise = getChild("radio raise"); - childSetCommitCallback("radio raise",click_popup_dozer_mode, (void*)1); - mRadioDozerLower = getChild("radio lower"); - childSetCommitCallback("radio lower",click_popup_dozer_mode, (void*)2); - mRadioDozerSmooth = getChild("radio smooth"); - childSetCommitCallback("radio smooth",click_popup_dozer_mode, (void*)3); - mRadioDozerNoise = getChild("radio noise"); - childSetCommitCallback("radio noise",click_popup_dozer_mode, (void*)4); - mRadioDozerRevert = getChild("radio revert"); - childSetCommitCallback("radio revert",click_popup_dozer_mode, (void*)5); + + mRadioGroupLand = getChild("land_radio_group"); + childSetCommitCallback("land_radio_group", commit_radio_group_land, this); + mBtnApplyToSelection = getChild("button apply to selection"); childSetAction("button apply to selection",click_apply_to_selection, (void*)0); @@ -338,8 +308,8 @@ BOOL LLFloaterTools::postBuild() // Create the popupview with a dummy center. It will be moved into place // during LLViewerWindow's per-frame hover processing. -LLFloaterTools::LLFloaterTools() -: LLFloater(std::string("toolbox floater")), +LLFloaterTools::LLFloaterTools(const LLSD& key) +: LLFloater(key), mBtnFocus(NULL), mBtnMove(NULL), mBtnEdit(NULL), @@ -347,18 +317,10 @@ LLFloaterTools::LLFloaterTools() mBtnLand(NULL), mTextStatus(NULL), - mRadioOrbit(NULL), - mRadioZoom(NULL), - mRadioPan(NULL), + mRadioGroupFocus(NULL), + mRadioGroupMove(NULL), + mRadioGroupEdit(NULL), - mRadioMove(NULL), - mRadioLift(NULL), - mRadioSpin(NULL), - - mRadioPosition(NULL), - mRadioRotate(NULL), - mRadioStretch(NULL), - mRadioSelectFace(NULL), mCheckSelectIndividual(NULL), mCheckSnapToGrid(NULL), @@ -380,13 +342,7 @@ LLFloaterTools::LLFloaterTools() mCheckCopySelection(NULL), mCheckCopyCenters(NULL), mCheckCopyRotates(NULL), - mRadioSelectLand(NULL), - mRadioDozerFlatten(NULL), - mRadioDozerRaise(NULL), - mRadioDozerLower(NULL), - mRadioDozerSmooth(NULL), - mRadioDozerNoise(NULL), - mRadioDozerRevert(NULL), + mRadioGroupLand(NULL), mSliderDozerSize(NULL), mSliderDozerForce(NULL), mBtnApplyToSelection(NULL), @@ -402,22 +358,23 @@ LLFloaterTools::LLFloaterTools() mTabLand(NULL), mDirty(TRUE) { + gFloaterTools = this; + setAutoFocus(FALSE); - LLCallbackMap::map_t factory_map; - factory_map["General"] = LLCallbackMap(createPanelPermissions, this);//LLPanelPermissions - factory_map["Object"] = LLCallbackMap(createPanelObject, this);//LLPanelObject - factory_map["Features"] = LLCallbackMap(createPanelVolume, this);//LLPanelVolume - factory_map["Texture"] = LLCallbackMap(createPanelFace, this);//LLPanelFace - factory_map["Contents"] = LLCallbackMap(createPanelContents, this);//LLPanelContents - factory_map["ContentsInventory"] = LLCallbackMap(createPanelContentsInventory, this);//LLPanelContents - factory_map["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_tools.xml",&factory_map,FALSE); + mFactoryMap["General"] = LLCallbackMap(createPanelPermissions, this);//LLPanelPermissions + mFactoryMap["Object"] = LLCallbackMap(createPanelObject, this);//LLPanelObject + mFactoryMap["Features"] = LLCallbackMap(createPanelVolume, this);//LLPanelVolume + mFactoryMap["Texture"] = LLCallbackMap(createPanelFace, this);//LLPanelFace + mFactoryMap["Contents"] = LLCallbackMap(createPanelContents, this);//LLPanelContents + mFactoryMap["land info panel"] = LLCallbackMap(createPanelLandInfo, this);//LLPanelLandInfo + + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_tools.xml",FALSE); } LLFloaterTools::~LLFloaterTools() { // children automatically deleted + gFloaterTools = NULL; } void LLFloaterTools::setStatusText(const std::string& text) @@ -489,7 +446,8 @@ void LLFloaterTools::draw() void LLFloaterTools::dirty() { mDirty = TRUE; - LLFloaterOpenObject::dirty(); + LLFloaterOpenObject* instance = LLFloaterReg::findTypedInstance("openobject"); + if (instance) instance->dirty(); } // Clean up any tool state that should not persist when the @@ -525,26 +483,31 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) mBtnFocus ->setToggleState( focus_visible ); - mRadioZoom ->setVisible( focus_visible ); - mRadioOrbit ->setVisible( focus_visible ); - mRadioPan ->setVisible( focus_visible ); + mRadioGroupFocus->setVisible( focus_visible ); childSetVisible("slider zoom", focus_visible); childSetEnabled("slider zoom", gCameraBtnZoom); - mRadioZoom ->set( !gCameraBtnOrbit && - !gCameraBtnPan && - !(mask == MASK_ORBIT) && - !(mask == (MASK_ORBIT | MASK_ALT)) && - !(mask == MASK_PAN) && - !(mask == (MASK_PAN | MASK_ALT)) ); - - mRadioOrbit ->set( gCameraBtnOrbit || - (mask == MASK_ORBIT) || - (mask == (MASK_ORBIT | MASK_ALT)) ); - - mRadioPan ->set( gCameraBtnPan || - (mask == MASK_PAN) || - (mask == (MASK_PAN | MASK_ALT)) ); + if (!gCameraBtnOrbit && + !gCameraBtnPan && + !(mask == MASK_ORBIT) && + !(mask == (MASK_ORBIT | MASK_ALT)) && + !(mask == MASK_PAN) && + !(mask == (MASK_PAN | MASK_ALT)) ) + { + mRadioGroupFocus->setValue("radio zoom"); + } + else if ( gCameraBtnOrbit || + (mask == MASK_ORBIT) || + (mask == (MASK_ORBIT | MASK_ALT)) ) + { + mRadioGroupFocus->setValue("radio orbit"); + } + else if ( gCameraBtnPan || + (mask == MASK_PAN) || + (mask == (MASK_PAN | MASK_ALT)) ) + { + mRadioGroupFocus->setValue("radio pan"); + } // multiply by correction factor because volume sliders go [0, 0.5] childSetValue( "slider zoom", gAgent.getCameraZoomFraction() * 0.5f); @@ -555,27 +518,23 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) if (mBtnMove) mBtnMove ->setToggleState( move_visible ); // HACK - highlight buttons for next click - if (mRadioMove) + mRadioGroupMove->setVisible(move_visible); + if (!gGrabBtnSpin && + !gGrabBtnVertical && + !(mask == MASK_VERTICAL) && + !(mask == MASK_SPIN) ) { - mRadioMove ->setVisible( move_visible ); - mRadioMove ->set( !gGrabBtnSpin && - !gGrabBtnVertical && - !(mask == MASK_VERTICAL) && - !(mask == MASK_SPIN) ); + mRadioGroupMove->setValue("radio move"); } - - if (mRadioLift) + else if (gGrabBtnVertical || + (mask == MASK_VERTICAL) ) { - mRadioLift ->setVisible( move_visible ); - mRadioLift ->set( gGrabBtnVertical || - (mask == MASK_VERTICAL) ); + mRadioGroupMove->setValue("radio lift"); } - - if (mRadioSpin) + else if (gGrabBtnSpin || + (mask == MASK_SPIN) ) { - mRadioSpin ->setVisible( move_visible ); - mRadioSpin ->set( gGrabBtnSpin || - (mask == MASK_SPIN) ); + mRadioGroupMove->setValue("radio spin"); } // Edit buttons @@ -587,15 +546,7 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) tool == LLToolPipette::getInstance(); mBtnEdit ->setToggleState( edit_visible ); - - mRadioPosition ->setVisible( edit_visible ); - mRadioRotate ->setVisible( edit_visible ); - mRadioStretch ->setVisible( edit_visible ); - if (mRadioSelectFace) - { - mRadioSelectFace->setVisible( edit_visible ); - mRadioSelectFace->set( tool == LLToolFace::getInstance() ); - } + mRadioGroupEdit->setVisible( edit_visible ); if (mCheckSelectIndividual) { @@ -603,9 +554,22 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) //mCheckSelectIndividual->set(gSavedSettings.getBOOL("EditLinkedParts")); } - mRadioPosition ->set( tool == LLToolCompTranslate::getInstance() ); - mRadioRotate ->set( tool == LLToolCompRotate::getInstance() ); - mRadioStretch ->set( tool == LLToolCompScale::getInstance() ); + if ( tool == LLToolCompTranslate::getInstance() ) + { + mRadioGroupEdit->setValue("radio position"); + } + else if ( tool == LLToolCompRotate::getInstance() ) + { + mRadioGroupEdit->setValue("radio rotate"); + } + else if ( tool == LLToolCompScale::getInstance() ) + { + mRadioGroupEdit->setValue("radio stretch"); + } + else if ( tool == LLToolFace::getInstance() ) + { + mRadioGroupEdit->setValue("radio select face"); + } if (mComboGridMode) { @@ -662,15 +626,13 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) else { // Highlight the correct placer button - for( std::vector::size_type i = 0; i < mButtons.size(); i++ ) + for( S32 t = 0; t < (S32)mButtons.size(); t++ ) { LLPCode pcode = LLToolPlacer::getObjectType(); - void *userdata = mButtons[i]->getCallbackUserData(); - LLPCode *cur = (LLPCode*) userdata; - - BOOL state = (pcode == *cur); - mButtons[i]->setToggleState( state ); - mButtons[i]->setVisible( create_visible ); + LLPCode button_pcode = toolData[t]; + BOOL state = (pcode == button_pcode); + mButtons[t]->setToggleState( state ); + mButtons[t]->setVisible( create_visible ); } } @@ -687,44 +649,39 @@ void LLFloaterTools::updatePopup(LLCoordGL center, MASK mask) if (mBtnLand) mBtnLand ->setToggleState( land_visible ); - // mRadioEditLand ->set( tool == LLToolBrushLand::getInstance() ); - if (mRadioSelectLand) mRadioSelectLand->set( tool == LLToolSelectLand::getInstance() ); + mRadioGroupLand->setVisible( land_visible ); + if ( tool == LLToolSelectLand::getInstance() ) + { + mRadioGroupLand->setValue("radio select land"); + } + else if ( tool == LLToolBrushLand::getInstance() ) + { + S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction"); + switch(dozer_mode) + { + case 0: + mRadioGroupLand->setValue("radio flatten"); + break; + case 1: + mRadioGroupLand->setValue("radio raise"); + break; + case 2: + mRadioGroupLand->setValue("radio lower"); + break; + case 3: + mRadioGroupLand->setValue("radio smooth"); + break; + case 4: + mRadioGroupLand->setValue("radio noise"); + break; + case 5: + mRadioGroupLand->setValue("radio revert"); + break; + default: + break; + } + } - // mRadioEditLand ->setVisible( land_visible ); - if (mRadioSelectLand) mRadioSelectLand->setVisible( land_visible ); - - S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction"); - - if (mRadioDozerFlatten) - { - mRadioDozerFlatten ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 0); - mRadioDozerFlatten ->setVisible( land_visible ); - } - if (mRadioDozerRaise) - { - mRadioDozerRaise ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 1); - mRadioDozerRaise ->setVisible( land_visible ); - } - if (mRadioDozerLower) - { - mRadioDozerLower ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 2); - mRadioDozerLower ->setVisible( land_visible ); - } - if (mRadioDozerSmooth) - { - mRadioDozerSmooth ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 3); - mRadioDozerSmooth ->setVisible( land_visible ); - } - if (mRadioDozerNoise) - { - mRadioDozerNoise ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 4); - mRadioDozerNoise ->setVisible( land_visible ); - } - if (mRadioDozerRevert) - { - mRadioDozerRevert ->set( tool == LLToolBrushLand::getInstance() && dozer_mode == 5); - mRadioDozerRevert ->setVisible( land_visible ); - } if (mBtnApplyToSelection) { mBtnApplyToSelection->setVisible( land_visible ); @@ -757,20 +714,22 @@ BOOL LLFloaterTools::canClose() } // virtual -void LLFloaterTools::onOpen() +void LLFloaterTools::onOpen(const LLSD& key) { mParcelSelection = LLViewerParcelMgr::getInstance()->getFloatingParcelSelection(); mObjectSelection = LLSelectMgr::getInstance()->getEditSelection(); - // gMenuBarView->setItemVisible(std::string("Tools"), TRUE); - // gMenuBarView->arrange(); + std::string panel = key.asString(); + if (!panel.empty()) + { + mTab->selectTabByName(panel); + } + + gMenuBarView->setItemVisible("BuildTools", TRUE); } -// virtual -void LLFloaterTools::onClose(bool app_quitting) +void LLFloaterTools::onClose() { - setMinimized(FALSE); - setVisible(FALSE); mTab->setVisible(FALSE); LLViewerJoystick::getInstance()->moveAvatar(false); @@ -796,19 +755,11 @@ void LLFloaterTools::onClose(bool app_quitting) // so manually reset tool to default (pie menu tool) LLToolMgr::getInstance()->getCurrentToolset()->selectFirstTool(); - // gMenuBarView->setItemVisible(std::string("Tools"), FALSE); - // gMenuBarView->arrange(); -} - -void LLFloaterTools::showPanel(EInfoPanel panel) -{ - llassert(panel >= 0 && panel < PANEL_COUNT); - mTab->selectTabByName(PANEL_NAMES[panel]); + gMenuBarView->setItemVisible("BuildTools", FALSE); } void click_popup_info(void*) { -// gBuildView->setPropertiesPanelOpen(TRUE); } void click_popup_done(void*) @@ -816,43 +767,49 @@ void click_popup_done(void*) handle_reset_view(); } -void click_popup_grab_drag(LLUICtrl*, void*) +void commit_radio_group_move(LLUICtrl* ctrl, void* data) { - gGrabBtnVertical = FALSE; - gGrabBtnSpin = FALSE; + LLRadioGroup* group = (LLRadioGroup*)ctrl; + std::string selected = group->getValue().asString(); + if (selected == "radio move") + { + gGrabBtnVertical = FALSE; + gGrabBtnSpin = FALSE; + } + else if (selected == "radio lift") + { + gGrabBtnVertical = TRUE; + gGrabBtnSpin = FALSE; + } + else if (selected == "radio spin") + { + gGrabBtnVertical = FALSE; + gGrabBtnSpin = TRUE; + } } -void click_popup_grab_lift(LLUICtrl*, void*) +void commit_radio_group_focus(LLUICtrl* ctrl, void* data) { - gGrabBtnVertical = TRUE; - gGrabBtnSpin = FALSE; -} - -void click_popup_grab_spin(LLUICtrl*, void*) -{ - gGrabBtnVertical = FALSE; - gGrabBtnSpin = TRUE; -} - -void commit_radio_zoom(LLUICtrl *, void*) -{ - gCameraBtnZoom = TRUE; - gCameraBtnOrbit = FALSE; - gCameraBtnPan = FALSE; -} - -void commit_radio_orbit(LLUICtrl *, void*) -{ - gCameraBtnZoom = FALSE; - gCameraBtnOrbit = TRUE; - gCameraBtnPan = FALSE; -} - -void commit_radio_pan(LLUICtrl *, void*) -{ - gCameraBtnZoom = FALSE; - gCameraBtnOrbit = FALSE; - gCameraBtnPan = TRUE; + LLRadioGroup* group = (LLRadioGroup*)ctrl; + std::string selected = group->getValue().asString(); + if (selected == "radio zoom") + { + gCameraBtnZoom = TRUE; + gCameraBtnOrbit = FALSE; + gCameraBtnPan = FALSE; + } + else if (selected == "radio orbit") + { + gCameraBtnZoom = FALSE; + gCameraBtnOrbit = TRUE; + gCameraBtnPan = FALSE; + } + else if (selected == "radio pan") + { + gCameraBtnZoom = FALSE; + gCameraBtnOrbit = FALSE; + gCameraBtnPan = TRUE; + } } void commit_slider_zoom(LLUICtrl *ctrl, void*) @@ -881,13 +838,6 @@ void click_popup_rotate_right(void*) } -void click_popup_dozer_mode(LLUICtrl *, void *user) -{ - S32 mode = (S32)(intptr_t) user; - gFloaterTools->setEditTool( LLToolBrushLand::getInstance() ); - gSavedSettings.setS32("RadioLandBrushAction", mode); -} - void commit_slider_dozer_size(LLUICtrl *ctrl, void*) { F32 size = (F32)ctrl->getValue().asReal(); @@ -901,21 +851,64 @@ void commit_slider_dozer_force(LLUICtrl *ctrl, void*) gSavedSettings.setF32("LandBrushForce", dozer_force); } - - - void click_apply_to_selection(void* user) { LLToolBrushLand::getInstance()->modifyLandInSelectionGlobal(); } -void commit_select_tool(LLUICtrl *ctrl, void *data) +void commit_radio_group_edit(LLUICtrl *ctrl, void *data) { S32 show_owners = gSavedSettings.getBOOL("ShowParcelOwners"); - gFloaterTools->setEditTool(data); + + LLRadioGroup* group = (LLRadioGroup*)ctrl; + std::string selected = group->getValue().asString(); + if (selected == "radio position") + { + LLFloaterTools::setEditTool( LLToolCompTranslate::getInstance() ); + } + else if (selected == "radio rotate") + { + LLFloaterTools::setEditTool( LLToolCompRotate::getInstance() ); + } + else if (selected == "radio stretch") + { + LLFloaterTools::setEditTool( LLToolCompScale::getInstance() ); + } + else if (selected == "radio select face") + { + LLFloaterTools::setEditTool( LLToolFace::getInstance() ); + } gSavedSettings.setBOOL("ShowParcelOwners", show_owners); } +void commit_radio_group_land(LLUICtrl* ctrl, void* data) +{ + LLRadioGroup* group = (LLRadioGroup*)ctrl; + std::string selected = group->getValue().asString(); + if (selected == "radio select land") + { + LLFloaterTools::setEditTool( LLToolSelectLand::getInstance() ); + } + else + { + LLFloaterTools::setEditTool( LLToolBrushLand::getInstance() ); + S32 dozer_mode = gSavedSettings.getS32("RadioLandBrushAction"); + if (selected == "radio flatten") + dozer_mode = 0; + else if (selected == "radio raise") + dozer_mode = 1; + else if (selected == "radio lower") + dozer_mode = 2; + else if (selected == "radio smooth") + dozer_mode = 3; + else if (selected == "radio noise") + dozer_mode = 4; + else if (selected == "radio revert") + dozer_mode = 5; + gSavedSettings.setS32("RadioLandBrushAction", dozer_mode); + } +} + void commit_select_component(LLUICtrl *ctrl, void *data) { LLFloaterTools* floaterp = (LLFloaterTools*)data; @@ -948,9 +941,8 @@ void commit_grid_mode(LLUICtrl *ctrl, void *data) } // static -void LLFloaterTools::setObjectType( void* data ) +void LLFloaterTools::setObjectType( LLPCode pcode ) { - LLPCode pcode = *(LLPCode*) data; LLToolPlacer::setObjectType( pcode ); gSavedSettings.setBOOL("CreateToolCopySelection", FALSE); gFocusMgr.setMouseCapture(NULL); @@ -960,14 +952,16 @@ void LLFloaterTools::setObjectType( void* data ) void LLFloaterTools::onClickGridOptions(void* data) { //LLFloaterTools* floaterp = (LLFloaterTools*)data; - LLFloaterBuildOptions::show(NULL); + LLFloaterReg::showInstance("build_options"); // RN: this makes grid options dependent on build tools window //floaterp->addDependentFloater(LLFloaterBuildOptions::getInstance(), FALSE); } +// static void LLFloaterTools::setEditTool(void* tool_pointer) { - select_tool(tool_pointer); + LLTool *tool = (LLTool *)tool_pointer; + LLToolMgr::getInstance()->getCurrentToolset()->selectTool( tool ); } void LLFloaterTools::onFocusReceived() diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h index 833a8a7b73..1b9f1d31ec 100644 --- a/indra/newview/llfloatertools.h +++ b/indra/newview/llfloatertools.h @@ -38,18 +38,20 @@ #include "llparcelselection.h" class LLButton; -class LLTextBox; -class LLTool; +class LLComboBox; class LLCheckBoxCtrl; -class LLTabContainer; class LLPanelPermissions; class LLPanelObject; class LLPanelVolume; class LLPanelContents; class LLPanelFace; class LLPanelLandInfo; -class LLComboBox; +class LLRadioCtrl; +class LLRadioGroup; class LLSlider; +class LLTabContainer; +class LLTextBox; +class LLTool; class LLParcelSelection; class LLObjectSelection; @@ -65,15 +67,15 @@ public: static void* createPanelVolume(void* vdata); static void* createPanelFace(void* vdata); static void* createPanelContents(void* vdata); - static void* createPanelContentsInventory(void* vdata); static void* createPanelLandInfo(void* vdata); - LLFloaterTools(); + LLFloaterTools(const LLSD& key); virtual ~LLFloaterTools(); - virtual void onOpen(); - virtual void onClose(bool app_quitting); - virtual BOOL canClose(); + /*virtual*/ void onOpen(const LLSD& key); + /*virtual*/ BOOL canClose(); + /*virtual*/ void draw(); + /*virtual*/ void onFocusReceived(); // call this once per frame to handle visibility, rect location, // button highlights, etc. @@ -93,24 +95,20 @@ public: PANEL_COUNT }; - /*virtual*/ void draw(); - void dirty(); void showPanel(EInfoPanel panel); void setStatusText(const std::string& text); - virtual void onFocusReceived(); static void setEditTool(void* data); void saveLastTool(); private: - static void setObjectType( void* data ); - + void onClose(); void refresh(); + static void setObjectType( LLPCode pcode ); static void onClickGridOptions(void* data); public: - LLButton *mBtnFocus; LLButton *mBtnMove; LLButton *mBtnEdit; @@ -120,20 +118,13 @@ public: LLTextBox *mTextStatus; // Focus buttons - LLCheckBoxCtrl *mRadioOrbit; - LLCheckBoxCtrl *mRadioZoom; - LLCheckBoxCtrl *mRadioPan; + LLRadioGroup* mRadioGroupFocus; // Move buttons - LLCheckBoxCtrl *mRadioMove; - LLCheckBoxCtrl *mRadioLift; - LLCheckBoxCtrl *mRadioSpin; + LLRadioGroup* mRadioGroupMove; // Edit buttons - LLCheckBoxCtrl *mRadioPosition; - LLCheckBoxCtrl *mRadioRotate; - LLCheckBoxCtrl *mRadioStretch; - LLCheckBoxCtrl *mRadioSelectFace; + LLRadioGroup* mRadioGroupEdit; LLCheckBoxCtrl *mCheckSelectIndividual; @@ -159,15 +150,7 @@ public: LLCheckBoxCtrl *mCheckCopyRotates; // Land buttons -// LLCheckBoxCtrl *mRadioEditLand; - LLCheckBoxCtrl *mRadioSelectLand; - - LLCheckBoxCtrl *mRadioDozerFlatten; - LLCheckBoxCtrl *mRadioDozerRaise; - LLCheckBoxCtrl *mRadioDozerLower; - LLCheckBoxCtrl *mRadioDozerSmooth; - LLCheckBoxCtrl *mRadioDozerNoise; - LLCheckBoxCtrl *mRadioDozerRevert; + LLRadioGroup* mRadioGroupLand; LLSlider *mSliderDozerSize; LLSlider *mSliderDozerForce; diff --git a/indra/newview/llfloatertopobjects.cpp b/indra/newview/llfloatertopobjects.cpp index fa6ba162ec..bf5a1141a6 100644 --- a/indra/newview/llfloatertopobjects.cpp +++ b/indra/newview/llfloatertopobjects.cpp @@ -40,8 +40,11 @@ #include "llagent.h" #include "llbutton.h" #include "llfloatergodtools.h" +#include "llfloaterreg.h" #include "llparcel.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lllineeditor.h" #include "lltextbox.h" #include "lltracker.h" @@ -51,11 +54,11 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" -LLFloaterTopObjects* LLFloaterTopObjects::sInstance = NULL; +//LLFloaterTopObjects* LLFloaterTopObjects::sInstance = NULL; // Globals // const U32 TIME_STR_LENGTH = 30; - +/* // static void LLFloaterTopObjects::show() { @@ -66,64 +69,53 @@ void LLFloaterTopObjects::show() } sInstance = new LLFloaterTopObjects(); - LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_top_objects.xml"); +// LLUICtrlFactory::getInstance()->buildFloater(sInstance, "floater_top_objects.xml"); sInstance->center(); } - -LLFloaterTopObjects::LLFloaterTopObjects() -: LLFloater(std::string("top_objects")), +*/ +LLFloaterTopObjects::LLFloaterTopObjects(const LLSD& key) +: LLFloater(key), mInitialized(FALSE), mtotalScore(0.f) { - sInstance = this; + mCommitCallbackRegistrar.add("TopObjects.ShowBeacon", boost::bind(&LLFloaterTopObjects::onClickShowBeacon, this)); + mCommitCallbackRegistrar.add("TopObjects.ReturnSelected", boost::bind(&LLFloaterTopObjects::onReturnSelected, this)); + mCommitCallbackRegistrar.add("TopObjects.ReturnAll", boost::bind(&LLFloaterTopObjects::onReturnAll, this)); + mCommitCallbackRegistrar.add("TopObjects.DisableSelected", boost::bind(&LLFloaterTopObjects::onDisableSelected, this)); + mCommitCallbackRegistrar.add("TopObjects.DisableAll", boost::bind(&LLFloaterTopObjects::onDisableAll, this)); + mCommitCallbackRegistrar.add("TopObjects.Refresh", boost::bind(&LLFloaterTopObjects::onRefresh, this)); + mCommitCallbackRegistrar.add("TopObjects.GetByObjectName", boost::bind(&LLFloaterTopObjects::onGetByObjectName, this)); + mCommitCallbackRegistrar.add("TopObjects.GetByOwnerName", boost::bind(&LLFloaterTopObjects::onGetByOwnerName, this)); + mCommitCallbackRegistrar.add("TopObjects.CommitObjectsList",boost::bind(&LLFloaterTopObjects::onCommitObjectsList, this)); } LLFloaterTopObjects::~LLFloaterTopObjects() { - sInstance = NULL; } // virtual BOOL LLFloaterTopObjects::postBuild() { - childSetCommitCallback("objects_list", onCommitObjectsList, this); - childSetDoubleClickCallback("objects_list", onDoubleClickObjectsList); - childSetFocus("objects_list"); LLScrollListCtrl *objects_list = getChild("objects_list"); - if (objects_list) - { - objects_list->setCommitOnSelectionChange(TRUE); - } + childSetFocus("objects_list"); + objects_list->setDoubleClickCallback(onDoubleClickObjectsList, this); + objects_list->setCommitOnSelectionChange(TRUE); - childSetAction("show_beacon_btn", onClickShowBeacon, this); setDefaultBtn("show_beacon_btn"); - childSetAction("return_selected_btn", onReturnSelected, this); - childSetAction("return_all_btn", onReturnAll, this); - childSetAction("disable_selected_btn", onDisableSelected, this); - childSetAction("disable_all_btn", onDisableAll, this); - childSetAction("refresh_btn", onRefresh, this); - - - childSetAction("filter_object_btn", onGetByObjectNameClicked, this); - childSetAction("filter_owner_btn", onGetByOwnerNameClicked, this); - - /* LLLineEditor* line_editor = getChild("owner_name_editor"); if (line_editor) { line_editor->setCommitOnFocusLost(FALSE); - line_editor->setCommitCallback(onGetByOwnerName); - line_editor->setCallbackUserData(this); + line_editor->setCommitCallback(onGetByOwnerName, this); } line_editor = getChild("object_name_editor"); if (line_editor) { line_editor->setCommitOnFocusLost(FALSE); - line_editor->setCommitCallback(onGetByObjectName); - line_editor->setCallbackUserData(this); + line_editor->setCommitCallback(onGetByObjectName, this); }*/ mCurrentMode = STAT_REPORT_TOP_SCRIPTS; @@ -132,19 +124,29 @@ BOOL LLFloaterTopObjects::postBuild() return TRUE; } +// static +void LLFloaterTopObjects::setMode(U32 mode) +{ + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; + instance->mCurrentMode = mode; +} +// static void LLFloaterTopObjects::handle_land_reply(LLMessageSystem* msg, void** data) { + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return; // Make sure dialog is on screen - show(); - sInstance->handleReply(msg, data); + LLFloaterReg::showInstance("top_objects"); + instance->handleReply(msg, data); //HACK: for some reason sometimes top scripts originally comes back //with no results even though they're there - if (!sInstance->mObjectListIDs.size() && !sInstance->mInitialized) + if (!instance->mObjectListIDs.size() && !instance->mInitialized) { - sInstance->onRefresh(NULL); - sInstance->mInitialized = TRUE; + instance->onRefresh(); + instance->mInitialized = TRUE; } } @@ -234,7 +236,7 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) if (total_count == 0 && list->getItemCount() == 0) { - list->addCommentText(getString("none_descriptor")); + list->setCommentText(getString("none_descriptor")); } else { @@ -263,12 +265,9 @@ void LLFloaterTopObjects::handleReply(LLMessageSystem *msg, void** data) } } -// static -void LLFloaterTopObjects::onCommitObjectsList(LLUICtrl* ctrl, void* data) +void LLFloaterTopObjects::onCommitObjectsList() { - LLFloaterTopObjects* self = (LLFloaterTopObjects*)data; - - self->updateSelectionInfo(); + updateSelectionInfo(); } void LLFloaterTopObjects::updateSelectionInfo() @@ -295,11 +294,9 @@ void LLFloaterTopObjects::onDoubleClickObjectsList(void* data) } // static -void LLFloaterTopObjects::onClickShowBeacon(void* data) +void LLFloaterTopObjects::onClickShowBeacon() { - LLFloaterTopObjects* self = (LLFloaterTopObjects*)data; - if (!self) return; - self->showBeacon(); + showBeacon(); } void LLFloaterTopObjects::doToObjects(int action, bool all) @@ -363,22 +360,24 @@ void LLFloaterTopObjects::doToObjects(int action, bool all) bool LLFloaterTopObjects::callbackReturnAll(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return false; if (option == 0) { - sInstance->doToObjects(ACTION_RETURN, true); + instance->doToObjects(ACTION_RETURN, true); } return false; } -void LLFloaterTopObjects::onReturnAll(void* data) +void LLFloaterTopObjects::onReturnAll() { LLNotifications::instance().add("ReturnAllTopObjects", LLSD(), LLSD(), &callbackReturnAll); } -void LLFloaterTopObjects::onReturnSelected(void* data) +void LLFloaterTopObjects::onReturnSelected() { - sInstance->doToObjects(ACTION_RETURN, false); + doToObjects(ACTION_RETURN, false); } @@ -386,52 +385,52 @@ void LLFloaterTopObjects::onReturnSelected(void* data) bool LLFloaterTopObjects::callbackDisableAll(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); + LLFloaterTopObjects* instance = LLFloaterReg::getTypedInstance("top_objects"); + if(!instance) return false; if (option == 0) { - sInstance->doToObjects(ACTION_DISABLE, true); + instance->doToObjects(ACTION_DISABLE, true); } return false; } -void LLFloaterTopObjects::onDisableAll(void* data) +void LLFloaterTopObjects::onDisableAll() { LLNotifications::instance().add("DisableAllTopObjects", LLSD(), LLSD(), callbackDisableAll); } -void LLFloaterTopObjects::onDisableSelected(void* data) +void LLFloaterTopObjects::onDisableSelected() { - sInstance->doToObjects(ACTION_DISABLE, false); + doToObjects(ACTION_DISABLE, false); } -//static + void LLFloaterTopObjects::clearList() { - LLCtrlListInterface *list = sInstance->childGetListInterface("objects_list"); + LLCtrlListInterface *list = childGetListInterface("objects_list"); if (list) { list->operateOnAll(LLCtrlListInterface::OP_DELETE); } - sInstance->mObjectListData.clear(); - sInstance->mObjectListIDs.clear(); - sInstance->mtotalScore = 0.f; + mObjectListData.clear(); + mObjectListIDs.clear(); + mtotalScore = 0.f; } -//static -void LLFloaterTopObjects::onRefresh(void* data) + +void LLFloaterTopObjects::onRefresh() { U32 mode = STAT_REPORT_TOP_SCRIPTS; U32 flags = 0; std::string filter = ""; - if (sInstance) - { - mode = sInstance->mCurrentMode; - flags = sInstance->mFlags; - filter = sInstance->mFilter; - sInstance->clearList(); - } + mode = mCurrentMode; + flags = mFlags; + filter = mFilter; + clearList(); + LLMessageSystem *msg = gMessageSystem; msg->newMessageFast(_PREHASH_LandStatRequest); @@ -446,31 +445,22 @@ void LLFloaterTopObjects::onRefresh(void* data) msg->sendReliable(gAgent.getRegionHost()); - if (sInstance) - { - sInstance->mFilter.clear(); - sInstance->mFlags = 0; - } + mFilter.clear(); + mFlags = 0; } -void LLFloaterTopObjects::onGetByObjectName(LLUICtrl* ctrl, void* data) +void LLFloaterTopObjects::onGetByObjectName() { - if (sInstance) - { - sInstance->mFlags = STAT_FILTER_BY_OBJECT; - sInstance->mFilter = sInstance->childGetText("object_name_editor"); - onRefresh(NULL); - } + mFlags = STAT_FILTER_BY_OBJECT; + mFilter = childGetText("object_name_editor"); + onRefresh(); } -void LLFloaterTopObjects::onGetByOwnerName(LLUICtrl* ctrl, void* data) +void LLFloaterTopObjects::onGetByOwnerName() { - if (sInstance) - { - sInstance->mFlags = STAT_FILTER_BY_OWNER; - sInstance->mFilter = sInstance->childGetText("owner_name_editor"); - onRefresh(NULL); - } + mFlags = STAT_FILTER_BY_OWNER; + mFilter = childGetText("owner_name_editor"); + onRefresh(); } void LLFloaterTopObjects::showBeacon() diff --git a/indra/newview/llfloatertopobjects.h b/indra/newview/llfloatertopobjects.h index 58cbf5d2ce..ee3c5d3cce 100644 --- a/indra/newview/llfloatertopobjects.h +++ b/indra/newview/llfloatertopobjects.h @@ -39,48 +39,49 @@ class LLUICtrl; class LLFloaterTopObjects : public LLFloater { + friend class LLFloaterReg; public: // Opens the floater on screen. - static void show(); +// static void show(); // Opens the floater if it's not on-screen. // Juggles the UI based on method = "scripts" or "colliders" static void handle_land_reply(LLMessageSystem* msg, void** data); void handleReply(LLMessageSystem* msg, void** data); - static void clearList(); + void clearList(); void updateSelectionInfo(); virtual BOOL postBuild(); - static void onRefresh(void* data); + void onRefresh(); - static void setMode(U32 mode) { if (sInstance) sInstance->mCurrentMode = mode; } + static void setMode(U32 mode); private: - LLFloaterTopObjects(); + LLFloaterTopObjects(const LLSD& key); ~LLFloaterTopObjects(); void initColumns(LLCtrlListInterface *list); - static void onCommitObjectsList(LLUICtrl* ctrl, void* data); + void onCommitObjectsList(); static void onDoubleClickObjectsList(void* data); - static void onClickShowBeacon(void* data); + void onClickShowBeacon(); void doToObjects(int action, bool all); - static void onReturnAll(void* data); - static void onReturnSelected(void* data); - static void onDisableAll(void* data); - static void onDisableSelected(void* data); + void onReturnAll(); + void onReturnSelected(); + void onDisableAll(); + void onDisableSelected(); static bool callbackReturnAll(const LLSD& notification, const LLSD& response); static bool callbackDisableAll(const LLSD& notification, const LLSD& response); - static void onGetByOwnerName(LLUICtrl* ctrl, void* data); - static void onGetByObjectName(LLUICtrl* ctrl, void* data); + void onGetByOwnerName(); + void onGetByObjectName(); - static void onGetByOwnerNameClicked(void* data) { onGetByOwnerName(NULL, data); }; - static void onGetByObjectNameClicked(void* data) { onGetByObjectName(NULL, data); }; +// static void onGetByOwnerNameClicked(void* data) { onGetByOwnerName(NULL, data); }; +// static void onGetByObjectNameClicked(void* data) { onGetByObjectName(NULL, data); }; void showBeacon(); diff --git a/indra/newview/llfloatertos.cpp b/indra/newview/llfloatertos.cpp index 6a392e03fb..1c3443ae80 100644 --- a/indra/newview/llfloatertos.cpp +++ b/indra/newview/llfloatertos.cpp @@ -35,11 +35,9 @@ #include "llfloatertos.h" // viewer includes -#include "llagent.h" #include "llappviewer.h" #include "llstartup.h" #include "llviewerstats.h" -#include "llviewertexteditor.h" #include "llviewerwindow.h" // linden library includes @@ -54,34 +52,9 @@ #include "message.h" -// static -LLFloaterTOS* LLFloaterTOS::sInstance = NULL; - -// static -LLFloaterTOS* LLFloaterTOS::show(ETOSType type, const std::string & message) -{ - if( !LLFloaterTOS::sInstance ) - { - LLFloaterTOS::sInstance = new LLFloaterTOS(type, message); - } - - if (type == TOS_TOS) - { - LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_tos.xml"); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(LLFloaterTOS::sInstance, "floater_critical.xml"); - } - - return LLFloaterTOS::sInstance; -} - - -LLFloaterTOS::LLFloaterTOS(ETOSType type, const std::string & message) -: LLModalDialog( std::string(" "), 100, 100 ), - mType(type), - mMessage(message), +LLFloaterTOS::LLFloaterTOS(const LLSD& message) +: LLModalDialog( message ), + mMessage(message.asString()), mWebBrowserWindowId( 0 ), mLoadCompleteCount( 0 ) { @@ -139,16 +112,14 @@ BOOL LLFloaterTOS::postBuild() childSetAction("Continue", onContinue, this); childSetAction("Cancel", onCancel, this); childSetCommitCallback("agree_chk", updateAgree, this); - - if ( mType != TOS_TOS ) + + if (hasChild("tos_text")) { // this displays the critical message - LLTextEditor *editor = getChild("tos_text"); - editor->setHandleEditKeysDirectly( TRUE ); - editor->setEnabled( FALSE ); - editor->setWordWrap(TRUE); - editor->setFocus(TRUE); - editor->setValue(LLSD(mMessage)); + LLUICtrl *tos_text = getChild("tos_text"); + tos_text->setEnabled( FALSE ); + tos_text->setFocus(TRUE); + tos_text->setValue(LLSD(mMessage)); return TRUE; } @@ -158,15 +129,13 @@ BOOL LLFloaterTOS::postBuild() tos_agreement->setEnabled( false ); // hide the SL text widget if we're displaying TOS with using a browser widget. - LLTextEditor *editor = getChild("tos_text"); + LLUICtrl *editor = getChild("tos_text"); editor->setVisible( FALSE ); - LLWebBrowserCtrl* web_browser = getChild("tos_html"); + LLMediaCtrl* web_browser = getChild("tos_html"); if ( web_browser ) { - // start to observe it so we see navigate complete events - web_browser->addObserver( this ); - + web_browser->addObserver(this); gResponsePtr = LLIamHere::build( this ); LLHTTPClient::get( getString( "real_url" ), gResponsePtr ); } @@ -177,17 +146,14 @@ BOOL LLFloaterTOS::postBuild() void LLFloaterTOS::setSiteIsAlive( bool alive ) { // only do this for TOS pages - if ( mType == TOS_TOS ) + if (hasChild("tos_html")) { - LLWebBrowserCtrl* web_browser = getChild("tos_html"); + LLMediaCtrl* web_browser = getChild("tos_html"); // if the contents of the site was retrieved if ( alive ) { - if ( web_browser ) - { - // navigate to the "real" page - web_browser->navigateTo( getString( "real_url" ) ); - }; + // navigate to the "real" page + web_browser->navigateTo( getString( "real_url" ) ); } else { @@ -195,24 +161,16 @@ void LLFloaterTOS::setSiteIsAlive( bool alive ) // but if the page is unavailable, we need to do this now LLCheckBoxCtrl* tos_agreement = getChild("agree_chk"); tos_agreement->setEnabled( true ); - }; - }; + } + } } LLFloaterTOS::~LLFloaterTOS() { - // stop obsaerving events - LLWebBrowserCtrl* web_browser = getChild("tos_html"); - if ( web_browser ) - { - web_browser->remObserver( this ); - }; // tell the responder we're not here anymore if ( gResponsePtr ) gResponsePtr->setParent( 0 ); - - LLFloaterTOS::sInstance = NULL; } // virtual @@ -235,7 +193,7 @@ void LLFloaterTOS::onContinue( void* userdata ) { LLFloaterTOS* self = (LLFloaterTOS*) userdata; llinfos << "User agrees with TOS." << llendl; - if (self->mType == TOS_TOS) + if (self->getInstanceName() == "message_tos") { gAcceptTOS = TRUE; } @@ -254,7 +212,7 @@ void LLFloaterTOS::onContinue( void* userdata ) #endif LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); // Go back and finish authentication - self->close(); // destroys this object + self->closeFloater(); // destroys this object } // static @@ -265,18 +223,21 @@ void LLFloaterTOS::onCancel( void* userdata ) LLNotifications::instance().add("MustAgreeToLogIn", LLSD(), LLSD(), login_alert_done); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); self->mLoadCompleteCount = 0; // reset counter for next time we come to TOS - self->close(); // destroys this object + self->closeFloater(); // destroys this object } //virtual -void LLFloaterTOS::onNavigateComplete( const EventType& eventIn ) +void LLFloaterTOS::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) { - // skip past the loading screen navigate complete - if ( ++mLoadCompleteCount == 2 ) + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) { - llinfos << "NAVIGATE COMPLETE" << llendl; - // enable Agree to TOS radio button now that page has loaded - LLCheckBoxCtrl * tos_agreement = getChild("agree_chk"); - tos_agreement->setEnabled( true ); - }; + // skip past the loading screen navigate complete + if ( ++mLoadCompleteCount == 2 ) + { + llinfos << "NAVIGATE COMPLETE" << llendl; + // enable Agree to TOS radio button now that page has loaded + LLCheckBoxCtrl * tos_agreement = getChild("agree_chk"); + tos_agreement->setEnabled( true ); + } + } } diff --git a/indra/newview/llfloatertos.h b/indra/newview/llfloatertos.h index dbec3ff8b6..49f982aa80 100644 --- a/indra/newview/llfloatertos.h +++ b/indra/newview/llfloatertos.h @@ -35,7 +35,7 @@ #include "llmodaldialog.h" #include "llassetstorage.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" class LLButton; class LLRadioGroup; @@ -45,21 +45,12 @@ class LLUUID; class LLFloaterTOS : public LLModalDialog, - public LLWebBrowserCtrlObserver + public LLViewerMediaObserver { public: + LLFloaterTOS(const LLSD& message); virtual ~LLFloaterTOS(); - // Types of dialog. - enum ETOSType - { - TOS_TOS = 0, - TOS_CRITICAL_MESSAGE = 1 - }; - - // Asset_id is overwritten with LLUUID::null when agree is clicked. - static LLFloaterTOS* show(ETOSType type, const std::string & message); - BOOL postBuild(); virtual void draw(); @@ -70,19 +61,13 @@ public: void setSiteIsAlive( bool alive ); - virtual void onNavigateComplete( const EventType& eventIn ); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); private: - // Asset_id is overwritten with LLUUID::null when agree is clicked. - LLFloaterTOS(ETOSType type, const std::string & message); - -private: - ETOSType mType; std::string mMessage; int mWebBrowserWindowId; int mLoadCompleteCount; - - static LLFloaterTOS* sInstance; }; #endif // LL_LLFLOATERTOS_H diff --git a/indra/newview/llfloateruipreview.cpp b/indra/newview/llfloateruipreview.cpp new file mode 100644 index 0000000000..2eb4e7580e --- /dev/null +++ b/indra/newview/llfloateruipreview.cpp @@ -0,0 +1,1642 @@ +/** + * @file llfloateruipreview.cpp + * @brief Tool for previewing and editing floaters, plus localization tool integration + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Tool for previewing floaters and panels for localization and UI design purposes. +// See: https://wiki.lindenlab.com/wiki/GUI_Preview_And_Localization_Tools +// See: https://jira.lindenlab.com/browse/DEV-16869 + +// *TODO: Translate error messgaes using notifications/alerts.xml + +#include "llviewerprecompiledheaders.h" // Precompiled headers + +#include "llfloateruipreview.h" // Own header + +// Internal utility +#include "llrender.h" +#include "llsdutil.h" +#include "llxmltree.h" +#include "llviewerwindow.h" +#include "lllivefile.h" + +// XUI +#include "lluictrlfactory.h" +#include "llcombobox.h" +#include "llresizebar.h" +#include "llscrolllistitem.h" +#include "llscrolllistctrl.h" +#include "llfilepicker.h" +#include "lldraghandle.h" +#include "lllayoutstack.h" +#include "llviewermenu.h" +#include "llrngwriter.h" + +// Boost (for linux/unix command-line execv) +#include +#include + +// External utility +#include + +#if LL_DARWIN +#include +#endif + +// Static initialization +static const S32 PRIMARY_FLOATER = 1; +static const S32 SECONDARY_FLOATER = 2; + +static LLDefaultChildRegistry::Register register_overlap_panel("overlap_panel"); + +static std::string get_xui_dir() +{ + std::string delim = gDirUtilp->getDirDelimiter(); + return gDirUtilp->getSkinBaseDir() + delim + "default" + delim + "xui" + delim; +} + +//---------------------------------------------------------------------------- +// Local class declarations +// Reset object to ensure that when we change the current language setting for preview purposes, +// it automatically is reset. Constructed on the stack at the start of the method; the reset +// occurs as it falls out of scope at the end of the method. See llfloateruipreview.cpp for usage. +class LLLocalizationResetForcer +{ +public: + LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID); + virtual ~LLLocalizationResetForcer(); + +private: + std::string mSavedLocalization; // the localization before we change it +}; + +// Implementation of live file +// When a floater is being previewed, any saved changes to its corresponding +// file cause the previewed floater to be reloaded +class LLGUIPreviewLiveFile : public LLLiveFile +{ +public: + LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent); + virtual ~LLGUIPreviewLiveFile(); + LLFloaterUIPreview* mParent; + LLFadeEventTimer* mFadeTimer; // timer for fade-to-yellow-and-back effect to warn that file has been reloaded + BOOL mFirstFade; // setting this avoids showing the fade reload warning on first load + std::string mFileName; +protected: + bool loadFile(); +}; + +// Implementation of graphical fade in/out (on timer) for when XUI files are updated +class LLFadeEventTimer : public LLEventTimer +{ +public: + LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent); + BOOL tick(); + LLGUIPreviewLiveFile* mParent; +private: + BOOL mFadingOut; // fades in then out; this is toggled in between + LLColor4 mOriginalColor; // original color; color is reset to this after fade is coimplete +}; + +// Implementation of previewed floater +// Used to override draw and mouse handler +class LLPreviewedFloater : public LLFloater +{ +public: + LLPreviewedFloater(LLFloaterUIPreview* floater) + : LLFloater(LLSD()), + mFloaterUIPreview(floater) + { + } + virtual void draw(); + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + BOOL selectElement(LLView* parent, int x, int y, int depth); // select element to display its overlappers + + LLFloaterUIPreview* mFloaterUIPreview; +}; + +//---------------------------------------------------------------------------- + +// Localization reset forcer -- ensures that when localization is temporarily changed for previewed floater, it is reset +// Changes are made here +LLLocalizationResetForcer::LLLocalizationResetForcer(LLFloaterUIPreview* floater, S32 ID) +{ + mSavedLocalization = LLUI::sSettingGroups["config"]->getString("Language"); // save current localization setting + LLUI::sSettingGroups["config"]->setString("Language", floater->getLocStr(ID));// hack language to be the one we want to preview floaters in + LLUI::setupPaths(); // forcibly reset XUI paths with this new language +} + +// Actually reset in destructor +// Changes are reversed here +LLLocalizationResetForcer::~LLLocalizationResetForcer() +{ + LLUI::sSettingGroups["config"]->setString("Language", mSavedLocalization); // reset language to what it was before we changed it + LLUI::setupPaths(); // forcibly reset XUI paths with this new language +} + +// Live file constructor +// Needs full path for LLLiveFile but needs just file name for this code, hence the reduntant arguments; easier than separating later +LLGUIPreviewLiveFile::LLGUIPreviewLiveFile(std::string path, std::string name, LLFloaterUIPreview* parent) + : mFileName(name), + mParent(parent), + mFirstFade(TRUE), + mFadeTimer(NULL), + LLLiveFile(path, 1.0) +{} + +LLGUIPreviewLiveFile::~LLGUIPreviewLiveFile() +{ + mParent->mLiveFile = NULL; + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + // deletes itself; see lltimer.cpp + } +} + +// Live file load +bool LLGUIPreviewLiveFile::loadFile() +{ + mParent->displayFloater(FALSE,1); // redisplay the floater + if(mFirstFade) // only fade if it wasn't just clicked on; can't use "clicked" BOOL below because of an oddity with setting LLLiveFile initial state + { + mFirstFade = FALSE; + } + else + { + if(mFadeTimer) + { + mFadeTimer->mParent = NULL; + } + mFadeTimer = new LLFadeEventTimer(0.05f,this); + } + return true; +} + +// Initialize fade event timer +LLFadeEventTimer::LLFadeEventTimer(F32 refresh, LLGUIPreviewLiveFile* parent) + : mParent(parent), + mFadingOut(TRUE), + LLEventTimer(refresh) +{ + mOriginalColor = mParent->mParent->mDisplayedFloater->getBackgroundColor(); +} + +// Single tick of fade event timer: increment the color +BOOL LLFadeEventTimer::tick() +{ + float diff = 0.04f; + if(TRUE == mFadingOut) // set fade for in/out color direction + { + diff = -diff; + } + + if(NULL == mParent) // no more need to tick, so suicide + { + delete this; + return FALSE; + } + + // Set up colors + LLColor4 bg_color = mParent->mParent->mDisplayedFloater->getBackgroundColor(); + LLSD colors = bg_color.getValue(); + LLSD colors_old = colors; + + // Tick colors + colors[0] = colors[0].asReal() - diff; if(colors[0].asReal() < mOriginalColor.getValue()[0].asReal()) { colors[0] = colors_old[0]; } + colors[1] = colors[1].asReal() - diff; if(colors[1].asReal() < mOriginalColor.getValue()[1].asReal()) { colors[1] = colors_old[1]; } + colors[2] = colors[2].asReal() + diff; if(colors[2].asReal() > mOriginalColor.getValue()[2].asReal()) { colors[2] = colors_old[2]; } + + // Clamp and set colors + bg_color.setValue(colors); + bg_color.clamp(); // make sure we didn't exceed [0,1] + mParent->mParent->mDisplayedFloater->setBackgroundColor(bg_color); + + if(bg_color[2] <= 0.0f) // end of fade out, start fading in + { + mFadingOut = FALSE; + } + + return FALSE; +} + +// Constructor +LLFloaterUIPreview::LLFloaterUIPreview(const LLSD& key) + : LLFloater(key), + mDisplayedFloater(NULL), + mDisplayedFloater_2(NULL), + mLiveFile(NULL), + // sHighlightingDiffs(FALSE), + mHighlightingOverlaps(FALSE), + mLastDisplayedX(0), + mLastDisplayedY(0) + +{ + // called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_ui_preview.xml"); +} + +// Destructor +LLFloaterUIPreview::~LLFloaterUIPreview() +{ + // spawned floaters are deleted automatically, so we don't need to delete them here + + // save contents of textfields so it can be restored later if the floater is created again this session + mSavedEditorPath = mEditorPathTextBox->getText(); + mSavedEditorArgs = mEditorArgsTextBox->getText(); + mSavedDiffPath = mDiffPathTextBox->getText(); + + // delete live file if it exists + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } +} + +// Perform post-build setup (defined in superclass) +BOOL LLFloaterUIPreview::postBuild() +{ + mCloseSignal.connect(boost::bind(&LLFloaterUIPreview::onClose, this, _2)); + + LLPanel* main_panel_tmp = getChild("main_panel"); // get a pointer to the main panel in order to... + mFileList = main_panel_tmp->getChild("name_list"); // save pointer to file list + // Double-click opens the floater, for convenience + mFileList->setDoubleClickCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + + // get pointers to buttons and link to callbacks + mLanguageSelection = main_panel_tmp->getChild("language_select_combo"); + mLanguageSelection->setSelectionCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + mLanguageSelection_2 = main_panel_tmp->getChild("language_select_combo_2"); + mLanguageSelection_2->setSelectionCallback(boost::bind(&LLFloaterUIPreview::onLanguageComboSelect, this, mLanguageSelection)); + LLPanel* editor_panel_tmp = main_panel_tmp->getChild("editor_panel"); + mDisplayFloaterBtn = main_panel_tmp->getChild("display_floater"); + mDisplayFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, PRIMARY_FLOATER)); + mDisplayFloaterBtn_2 = main_panel_tmp->getChild("display_floater_2"); + mDisplayFloaterBtn_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickDisplayFloater, this, SECONDARY_FLOATER)); + mToggleOverlapButton = main_panel_tmp->getChild("toggle_overlap_panel"); + mToggleOverlapButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleOverlapping, this)); + mCloseOtherButton = main_panel_tmp->getChild("close_displayed_floater"); + mCloseOtherButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, PRIMARY_FLOATER)); + mCloseOtherButton_2 = main_panel_tmp->getChild("close_displayed_floater_2"); + mCloseOtherButton_2->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickCloseDisplayedFloater, this, SECONDARY_FLOATER)); + mEditFloaterBtn = main_panel_tmp->getChild("edit_floater"); + mEditFloaterBtn->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickEditFloater, this)); + mExecutableBrowseButton = editor_panel_tmp->getChild("browse_for_executable"); + LLPanel* vlt_panel_tmp = main_panel_tmp->getChild("vlt_panel"); + mExecutableBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForEditor, this)); + mDiffBrowseButton = vlt_panel_tmp->getChild("browse_for_vlt_diffs"); + mDiffBrowseButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickBrowseForDiffs, this)); + mToggleHighlightButton = vlt_panel_tmp->getChild("toggle_vlt_diff_highlight"); + mToggleHighlightButton->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickToggleDiffHighlighting, this)); + main_panel_tmp->getChild("save_floater")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveFloater, this, PRIMARY_FLOATER)); + main_panel_tmp->getChild("save_all_floaters")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickSaveAll, this, PRIMARY_FLOATER)); + + getChild("export_schema")->setClickedCallback(boost::bind(&LLFloaterUIPreview::onClickExportSchema, this)); + + // get pointers to text fields + mEditorPathTextBox = editor_panel_tmp->getChild("executable_path_field"); + mEditorArgsTextBox = editor_panel_tmp->getChild("executable_args_field"); + mDiffPathTextBox = vlt_panel_tmp->getChild("vlt_diff_path_field"); + + // *HACK: restored saved editor path and args to textfields + mEditorPathTextBox->setText(mSavedEditorPath); + mEditorArgsTextBox->setText(mSavedEditorArgs); + mDiffPathTextBox->setText(mSavedDiffPath); + + // Set up overlap panel + mOverlapPanel = getChild("overlap_panel"); + + childSetVisible("overlap_scroll", mHighlightingOverlaps); + + mDelim = gDirUtilp->getDirDelimiter(); // initialize delimiter to dir sep slash + + // refresh list of available languages (EN will still be default) + BOOL found = TRUE; + BOOL found_en_us = FALSE; + std::string language_directory; + std::string xui_dir = get_xui_dir(); // directory containing localizations -- don't forget trailing delim + mLanguageSelection->removeall(); // clear out anything temporarily in list from XML + while(found) // for every directory + { + if((found = gDirUtilp->getNextFileInDir(xui_dir, "*", language_directory, FALSE))) // get next directory + { + std::string full_path = xui_dir + language_directory; + if(LLFile::isfile(full_path.c_str())) // if it's not a directory, skip it + { + continue; + } + + if(strncmp("template",language_directory.c_str(),8) && -1 == language_directory.find(".")) // if it's not the template directory or a hidden directory + { + if(!strncmp("en",language_directory.c_str(),5)) // remember if we've seen en, so we can make it default + { + found_en_us = TRUE; + } + else + { + mLanguageSelection->add(std::string(language_directory)); // add it to the language selection dropdown menu + mLanguageSelection_2->add(std::string(language_directory)); + } + } + } + } + if(found_en_us) + { + mLanguageSelection->add(std::string("en"),ADD_TOP); // make en first item if we found it + mLanguageSelection_2->add(std::string("en"),ADD_TOP); + } + else + { + std::string warning = std::string("No EN localization found; check your XUI directories!"); + popupAndPrintWarning(warning); + } + mLanguageSelection->selectFirstItem(); // select the first item + mLanguageSelection_2->selectFirstItem(); + + refreshList(); // refresh the list of available floaters + + return TRUE; +} + +// Callback for language combo box selection: refresh current floater when you change languages +void LLFloaterUIPreview::onLanguageComboSelect(LLUICtrl* ctrl) +{ + LLComboBox* caller = dynamic_cast(ctrl); + if (!caller) + return; + if(caller->getName() == std::string("language_select_combo")) + { + if(mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,1); + } + } + else + { + if(mDisplayedFloater_2) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + displayFloater(TRUE,2); // *TODO: make take an arg + } + } + +} + +void LLFloaterUIPreview::onClickExportSchema() +{ + gViewerWindow->setCursor(UI_CURSOR_WAIT); + std::string template_path = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "xui", "schema"); + + typedef LLWidgetTypeRegistry::Registrar::registry_map_t::const_iterator registry_it; + registry_it end_it = LLWidgetTypeRegistry::defaultRegistrar().endItems(); + for(registry_it it = LLWidgetTypeRegistry::defaultRegistrar().beginItems(); + it != end_it; + ++it) + { + std::string widget_name = it->first; + const LLInitParam::BaseBlock& block = + (*LLDefaultParamBlockRegistry::instance().getValue(*LLWidgetTypeRegistry::instance().getValue(widget_name)))(); + LLXMLNodePtr root_nodep = new LLXMLNode(); + LLRNGWriter().writeRNG(widget_name, root_nodep, block, "http://www.lindenlab.com/xui"); + + std::string file_name(template_path + gDirUtilp->getDirDelimiter() + widget_name + ".rng"); + + LLFILE* rng_file = LLFile::fopen(file_name.c_str(), "w"); + { + LLXMLNode::writeHeaderToFile(rng_file); + const bool use_type_decorations = false; + root_nodep->writeToFile(rng_file, std::string(), use_type_decorations); + } + fclose(rng_file); + } + gViewerWindow->setCursor(UI_CURSOR_ARROW); +} + + +// Close click handler -- delete my displayed floater if it exists +void LLFloaterUIPreview::onClose(const LLSD& app_quitting) +{ + if(!app_quitting.asBoolean() && mDisplayedFloater) + { + onClickCloseDisplayedFloater(PRIMARY_FLOATER); + onClickCloseDisplayedFloater(SECONDARY_FLOATER); + delete mDisplayedFloater; + mDisplayedFloater = NULL; + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } +} + +// Error handling (to avoid code repetition) +// *TODO: this is currently unlocalized. Add to alerts/notifications.xml, someday, maybe. +void LLFloaterUIPreview::popupAndPrintWarning(std::string& warning) +{ + llwarns << warning << llendl; + LLSD args; + args["MESSAGE"] = warning; + LLNotifications::instance().add("GenericAlert", args); +} + +// Get localization string from drop-down menu +std::string LLFloaterUIPreview::getLocStr(S32 ID) +{ + if(ID == 1) + { + return mLanguageSelection->getSelectedItemLabel(0); + } + else + { + return mLanguageSelection_2->getSelectedItemLabel(0); + } +} + +// Get localized directory (build path from data directory to XUI files, substituting localization string in for language) +std::string LLFloaterUIPreview::getLocalizedDirectory() +{ + return get_xui_dir() + (getLocStr(1)) + mDelim; // e.g. "C:/Code/guipreview/indra/newview/skins/xui/en/"; +} + +// Refresh the list of floaters by doing a directory traverse for XML XUI floater files +// Could be used to grab any specific language's list of compatible floaters, but currently it's just used to get all of them +void LLFloaterUIPreview::refreshList() +{ + // Note: the mask doesn't seem to accept regular expressions, so there need to be two directory searches here + mFileList->clearRows(); // empty list + std::string name; + BOOL found = TRUE; + while(found) // for every floater file that matches the pattern + { + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "floater_*.xml", name, FALSE))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + while(found) // for every menu file that matches the pattern + { + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "menu_*.xml", name, FALSE))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + found = TRUE; + while(found) // for every panel file that matches the pattern + { + if((found = gDirUtilp->getNextFileInDir(getLocalizedDirectory(), "panel_*.xml", name, FALSE))) // get next file matching pattern + { + addFloaterEntry(name.c_str()); // and add it to the list (file name only; localization code takes care of rest of path) + } + } + + if(!mFileList->isEmpty()) // if there were any matching files, just select the first one (so we don't have to worry about disabling buttons when no entry is selected) + { + mFileList->selectFirstItem(); + } +} + +// Add a single entry to the list of available floaters +// Note: no deduplification (shouldn't be necessary) +void LLFloaterUIPreview::addFloaterEntry(const std::string& path) +{ + LLUUID* entry_id = new LLUUID(); // create a new UUID + entry_id->generate(path); + const LLUUID& entry_id_ref = *entry_id; // get a reference to the UUID for the LLSD block + + // fill LLSD column entry: initialize row/col structure + LLSD row; + row["id"] = entry_id_ref; + LLSD& columns = row["columns"]; + + // Get name of floater: + LLXmlTree xml_tree; + std::string full_path = getLocalizedDirectory() + path; // get full path + BOOL success = xml_tree.parseFile(full_path.c_str(), TRUE); // parse xml + std::string entry_name; + std::string entry_title; + if(success) + { + // get root (or error handle) + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if (!root_floater) + { + std::string warning = std::string("No root node found in XUI file: ") + path; + popupAndPrintWarning(warning); + return; + } + + // get name + root_floater->getAttributeString("name",entry_name); + if(std::string("") == entry_name) + { + entry_name = "Error: unable to load " + std::string(path); // set to error state if load fails + } + + // get title + root_floater->getAttributeString("title",entry_title); // some don't have a title, and some have title = "(unknown)", so just leave it blank if it fails + } + else + { + std::string warning = std::string("Unable to parse XUI file: ") + path; // error handling + popupAndPrintWarning(warning); + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + return; + } + + // Fill floater title column + columns[0]["column"] = "title_column"; + columns[0]["type"] = "text"; + columns[0]["value"] = entry_title; + + // Fill floater path column + columns[1]["column"] = "file_column"; + columns[1]["type"] = "text"; + columns[1]["value"] = std::string(path); + + // Fill floater name column + columns[2]["column"] = "top_level_node_column"; + columns[2]["type"] = "text"; + columns[2]["value"] = entry_name; + + mFileList->addElement(row); // actually add to list +} + +// Respond to button click to display/refresh currently-selected floater +void LLFloaterUIPreview::onClickDisplayFloater(S32 caller_id) +{ + displayFloater(TRUE, caller_id); + if(caller_id == PRIMARY_FLOATER) + { + mDisplayedFloater->center(); // move displayed floater to the center of the screen + } +} + +// Saves the current floater/panel +void LLFloaterUIPreview::onClickSaveFloater(S32 caller_id) +{ + displayFloater(TRUE, caller_id, true); + if(caller_id == PRIMARY_FLOATER) + { + mDisplayedFloater->center(); // move displayed floater to the center of the screen + } +} + +// Saves all floater/panels +void LLFloaterUIPreview::onClickSaveAll(S32 caller_id) +{ + int listSize = mFileList->getItemCount(); + + for (int index = 0; index < listSize; index++) + { + mFileList->selectNthItem(index); + displayFloater(TRUE, caller_id, true); + } +} + +// Given path to floater or panel XML file "filename.xml", +// returns "filename_new.xml" +static std::string append_new_to_xml_filename(const std::string& path) +{ + std::string full_filename = gDirUtilp->findSkinnedFilename(LLUI::getLocalizedSkinPath(), path); + std::string::size_type extension_pos = full_filename.rfind(".xml"); + full_filename.resize(extension_pos); + full_filename += "_new.xml"; + return full_filename; +} + +// Actually display the floater +// Only set up a new live file if this came from a click (at which point there should be no existing live file), rather than from the live file's update itself; +// otherwise, we get an infinite loop as the live file keeps recreating itself. That means this function is generally called twice. +void LLFloaterUIPreview::displayFloater(BOOL click, S32 ID, bool save) +{ + // Convince UI that we're in a different language (the one selected on the drop-down menu) + LLLocalizationResetForcer reset_forcer(this, ID); // save old language in reset forcer object (to be reset upon destruction when it falls out of scope) + + LLPreviewedFloater** floaterp = (ID == 1 ? &(mDisplayedFloater) : &(mDisplayedFloater_2)); + if(ID == 1) + { + BOOL floater_already_open = mDisplayedFloater != NULL; + if(floater_already_open) // if we are already displaying a floater + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; // save floater's last known position to put the new one there + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; // delete it (this closes it too) + mDisplayedFloater = NULL; // and reset the pointer + } + } + else + { + if(mDisplayedFloater_2 != NULL) + { + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } + } + + std::string path = mFileList->getSelectedItemLabel(1); // get the path of the currently-selected floater + if(std::string("") == path) // if no item is selected + { + return; // ignore click (this can only happen with empty list; otherwise an item is always selected) + } + + *floaterp = new LLPreviewedFloater(this); + + if(!strncmp(path.c_str(),"floater_",8)) // if it's a floater + { + if (save) + { + LLXMLNodePtr floater_write = new LLXMLNode(); + LLUICtrlFactory::getInstance()->buildFloater(*floaterp, path, floater_write); // just build it + + if (!floater_write->isNull()) + { + std::string full_filename = append_new_to_xml_filename(path); + LLFILE* floater_temp = LLFile::fopen(full_filename.c_str(), "w"); + LLXMLNode::writeHeaderToFile(floater_temp); + const bool use_type_decorations = false; + floater_write->writeToFile(floater_temp, std::string(), use_type_decorations); + fclose(floater_temp); + } + } + else + { + LLUICtrlFactory::getInstance()->buildFloater(*floaterp, path, NULL); // just build it + (*floaterp)->openFloater((*floaterp)->getKey()); + } + + } + else if (!strncmp(path.c_str(),"menu_",5)) // if it's a menu + { + if (save) + { + LLXMLNodePtr menu_write = new LLXMLNode(); + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile(path, gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance(), menu_write); + + if (!menu_write->isNull()) + { + std::string full_filename = append_new_to_xml_filename(path); + LLFILE* menu_temp = LLFile::fopen(full_filename.c_str(), "w"); + LLXMLNode::writeHeaderToFile(menu_temp); + const bool use_type_decorations = false; + menu_write->writeToFile(menu_temp, std::string(), use_type_decorations); + fclose(menu_temp); + } + + delete menu; + } + } + else // if it is a panel... + { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); + + LLPanel::Params panel_params; + LLPanel* panel = LLUICtrlFactory::create(panel_params); // create a new panel + + if (save) + { + LLXMLNodePtr panel_write = new LLXMLNode(); + LLUICtrlFactory::getInstance()->buildPanel(panel, path, panel_write); // build it + + if (!panel_write->isNull()) + { + std::string full_filename = append_new_to_xml_filename(path); + LLFILE* panel_temp = LLFile::fopen(full_filename.c_str(), "w"); + LLXMLNode::writeHeaderToFile(panel_temp); + const bool use_type_decorations = false; + panel_write->writeToFile(panel_temp, std::string(), use_type_decorations); + fclose(panel_temp); + } + } + else + { + LLUICtrlFactory::getInstance()->buildPanel(panel, path); // build it + LLRect new_size = panel->getRect(); // get its rectangle + panel->setOrigin(0,0); // reset its origin point so it's not offset by -left or other XUI attributes + (*floaterp)->setTitle(path); // use the file name as its title, since panels have no guaranteed meaningful name attribute + panel->setUseBoundingRect(TRUE); // enable the use of its outer bounding rect (normally disabled because it's O(n) on the number of sub-elements) + panel->updateBoundingRect(); // update bounding rect + LLRect bounding_rect = panel->getBoundingRect(); // get the bounding rect + LLRect new_rect = panel->getRect(); // get the panel's rect + new_rect.unionWith(bounding_rect); // union them to make sure we get the biggest one possible + (*floaterp)->reshape(new_rect.getWidth(), new_rect.getHeight() + floater_header_size); // reshape floater to match the union rect's dimensions + panel->reshape(new_rect.getWidth(), new_rect.getHeight()); // reshape panel to match the union rect's dimensions as well (both are needed) + (*floaterp)->addChild(panel); // add panel as child + (*floaterp)->openFloater(); // open floater (needed?) + } + } + + if(ID == 1) + { + (*floaterp)->setOrigin(mLastDisplayedX, mLastDisplayedY); + } + + // *HACK: Remove ability to close it; if you close it, its destructor gets called, but we don't know it's null and try to delete it again, + // resulting in a double free + (*floaterp)->setCanClose(FALSE); + + if(ID == 1) + { + mCloseOtherButton->setEnabled(TRUE); // enable my floater's close button + } + else + { + mCloseOtherButton_2->setEnabled(TRUE); + } + + // *TODO: Make the secondary floater pop up next to the primary one. Doesn't seem to always work if secondary was up first... + if((mDisplayedFloater && ID == 2) || (mDisplayedFloater_2 && ID == 1)) + { + mDisplayedFloater_2->setSnapTarget(mDisplayedFloater->getHandle()); + mDisplayedFloater->addDependentFloater(mDisplayedFloater_2); + } + + // Add localization to title so user knows whether it's localized or defaulted to en + std::string full_path = getLocalizedDirectory() + path; + std::string floater_lang = "EN"; + llstat dummy; + if(!LLFile::stat(full_path.c_str(), &dummy)) // if the file does not exist + { + floater_lang = getLocStr(ID); + } + std::string new_title = (*floaterp)->getTitle() + std::string(" [") + floater_lang + + (ID == 1 ? " - Primary" : " - Secondary") + std::string("]"); + (*floaterp)->setTitle(new_title); + + if(click && ID == 1 && !save) + { + // set up live file to track it + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + mLiveFile = new LLGUIPreviewLiveFile(std::string(full_path.c_str()),std::string(path.c_str()),this); + mLiveFile->checkAndReload(); + mLiveFile->addToEventTimer(); + } + + if(ID == 1) + { + mToggleOverlapButton->setEnabled(TRUE); + } + + if(LLView::sHighlightingDiffs && click && ID == 1) + { + highlightChangedElements(); + } + + if(ID == 1) + { + mOverlapPanel->mOverlapMap.clear(); + LLView::sPreviewClickedElement = NULL; // stop overlapping elements from drawing + mOverlapPanel->mLastClickedElement = NULL; + findOverlapsInChildren((LLView*)mDisplayedFloater); + + // highlight and enable them + if(mHighlightingOverlaps) + { + for(LLOverlapPanel::OverlapMap::iterator iter = mOverlapPanel->mOverlapMap.begin(); iter != mOverlapPanel->mOverlapMap.end(); ++iter) + { + LLView* viewp = iter->first; + LLView::sPreviewHighlightedElements.insert(viewp); + } + } + else if(LLView::sHighlightingDiffs) + { + highlightChangedElements(); + } + } + + // NOTE: language is reset here automatically when the reset forcer object falls out of scope (see header for details) +} + +// Respond to button click to edit currently-selected floater +void LLFloaterUIPreview::onClickEditFloater() +{ + std::string file_name = mFileList->getSelectedItemLabel(1); // get the file name of the currently-selected floater + if(std::string("") == file_name) // if no item is selected + { + return; // ignore click + } + std::string path = getLocalizedDirectory() + file_name; + + // stat file to see if it exists (some localized versions may not have it there are no diffs, and then we try to open an nonexistent file) + llstat dummy; + if(LLFile::stat(path.c_str(), &dummy)) // if the file does not exist + { + std::string warning = "No file for this floater exists in the selected localization. Opening the EN version instead."; + popupAndPrintWarning(warning); + + path = get_xui_dir() + mDelim + "en" + mDelim + file_name; // open the en version instead, by default + } + + // get executable path + const char* exe_path_char; + std::string path_in_textfield = mEditorPathTextBox->getText(); + if(std::string("") != path_in_textfield) // if the text field is not emtpy, use its path + { + exe_path_char = path_in_textfield.c_str(); + } + else if (!LLUI::sSettingGroups["config"]->getString("XUIEditor").empty()) + { + exe_path_char = LLUI::sSettingGroups["config"]->getString("XUIEditor").c_str(); + } + else // otherwise use the path specified by the environment variable + { + exe_path_char = getenv("LL_XUI_EDITOR"); + } + + // error check executable path + if(NULL == exe_path_char) + { + std::string warning = "Select an editor by setting the environment variable LL_XUI_EDITOR or specifying its path in the \"Editor Path\" field."; + popupAndPrintWarning(warning); + return; + } + std::string exe_path = exe_path_char; // do this after error check, otherwise internal strlen call fails on bad char* + + // remove any quotes; they're added back in later where necessary + int found_at; + while((found_at = exe_path.find("\"")) != -1 || (found_at = exe_path.find("'")) != -1) + { + exe_path.erase(found_at,1); + } + + llstat s; + if(!LLFile::stat(exe_path.c_str(), &s)) // If the executable exists + { + // build paths and arguments + std::string args; + std::string custom_args = mEditorArgsTextBox->getText(); + int position_of_file = custom_args.find(std::string("%FILE%"), 0); // prepare to replace %FILE% with actual file path + std::string first_part_of_args = ""; + std::string second_part_of_args = ""; + if(-1 == position_of_file) // default: Executable.exe File.xml + { + args = std::string("\"") + path + std::string("\""); // execute the command Program.exe "File.xml" + } + else // use advanced command-line arguments, e.g. "Program.exe -safe File.xml" -windowed for "-safe %FILE% -windowed" + { + first_part_of_args = custom_args.substr(0,position_of_file); // get part of args before file name + second_part_of_args = custom_args.substr(position_of_file+6,custom_args.length()); // get part of args after file name + custom_args = first_part_of_args + std::string("\"") + path + std::string("\"") + second_part_of_args; // replace %FILE% with "" and put back together + args = custom_args; // and save in the variable that is actually used + } + + // find directory in which executable resides by taking everything after last slash + int last_slash_position = exe_path.find_last_of(mDelim); + if(-1 == last_slash_position) + { + std::string warning = std::string("Unable to find a valid path to the specified executable for XUI XML editing: ") + exe_path; + popupAndPrintWarning(warning); + return; + } + std::string exe_dir = exe_path.substr(0,last_slash_position); // strip executable off, e.g. get "C:\Program Files\TextPad 5" (with or without trailing slash) + +#if LL_WINDOWS + PROCESS_INFORMATION pinfo; + STARTUPINFOA sinfo; + memset(&sinfo, 0, sizeof(sinfo)); + memset(&pinfo, 0, sizeof(pinfo)); + + std::string exe_name = exe_path.substr(last_slash_position+1); + args = exe_name + std::string(" ") + args; // and prepend the executable name, so we get 'Program.exe "Arg1"' + + char *args2 = new char[args.size() + 1]; // Windows requires that the second parameter to CreateProcessA be a writable (non-const) string... + strcpy(args2, args.c_str()); + + if(!CreateProcessA(exe_path.c_str(), args2, NULL, NULL, FALSE, 0, NULL, exe_dir.c_str(), &sinfo, &pinfo)) + { + // DWORD dwErr = GetLastError(); + std::string warning = "Creating editor process failed!"; + popupAndPrintWarning(warning); + } + else + { + // foo = pinfo.dwProcessId; // get your pid here if you want to use it later on + // sGatewayHandle = pinfo.hProcess; + CloseHandle(pinfo.hThread); // stops leaks - nothing else + } + + delete[] args2; +#else // if !LL_WINDOWS + // This code was copied from the code to run SLVoice, with some modification; should work in UNIX (Mac/Darwin or Linux) + { + std::vector arglist; + arglist.push_back(exe_path.c_str()); + + // Split the argument string into separate strings for each argument + typedef boost::tokenizer< boost::char_separator > tokenizer; + boost::char_separator sep("","\" ", boost::drop_empty_tokens); + + tokenizer tokens(args, sep); + tokenizer::iterator token_iter; + BOOL inside_quotes = FALSE; + BOOL last_was_space = FALSE; + for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + if(!strncmp("\"",(*token_iter).c_str(),2)) + { + inside_quotes = !inside_quotes; + } + else if(!strncmp(" ",(*token_iter).c_str(),2)) + { + if(inside_quotes) + { + arglist.back().append(std::string(" ")); + last_was_space = TRUE; + } + } + else + { + std::string to_push = *token_iter; + if(last_was_space) + { + arglist.back().append(to_push); + last_was_space = FALSE; + } + else + { + arglist.push_back(to_push); + } + } + } + + // create an argv vector for the child process + char **fakeargv = new char*[arglist.size() + 1]; + int i; + for(i=0; i < arglist.size(); i++) + fakeargv[i] = const_cast(arglist[i].c_str()); + + fakeargv[i] = NULL; + + fflush(NULL); // flush all buffers before the child inherits them + pid_t id = vfork(); + if(id == 0) + { + // child + execv(exe_path.c_str(), fakeargv); + + // If we reach this point, the exec failed. + // Use _exit() instead of exit() per the vfork man page. + std::string warning = "Creating editor process failed (vfork/execv)!"; + popupAndPrintWarning(warning); + _exit(0); + } + + // parent + delete[] fakeargv; + // sGatewayPID = id; + } +#endif // LL_WINDOWS + } + else + { + std::string warning = "Unable to find path to external XML editor for XUI preview tool"; + popupAndPrintWarning(warning); + } +} + +// Respond to button click to browse for an executable with which to edit XML files +void LLFloaterUIPreview::onClickBrowseForEditor() +{ + // create load dialog box + LLFilePicker::ELoadFilter type = (LLFilePicker::ELoadFilter)((intptr_t)((void*)LLFilePicker::FFLOAD_ALL)); // nothing for *.exe so just use all + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(type)) // user cancelled -- do nothing + { + return; + } + + // put the selected path into text field + const std::string chosen_path = picker.getFirstFile(); + std::string executable_path = chosen_path; +#if LL_DARWIN + // on Mac, if it's an application bundle, figure out the actual path from the Info.plist file + CFStringRef path_cfstr = CFStringCreateWithCString(kCFAllocatorDefault, chosen_path.c_str(), kCFStringEncodingMacRoman); // get path as a CFStringRef + CFURLRef path_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_cfstr, kCFURLPOSIXPathStyle, TRUE); // turn it into a CFURLRef + CFBundleRef chosen_bundle = CFBundleCreate(kCFAllocatorDefault, path_url); // get a handle for the bundle + if(NULL != chosen_bundle) + { + CFDictionaryRef bundleInfoDict = CFBundleGetInfoDictionary(chosen_bundle); // get the bundle's dictionary + if(NULL != bundleInfoDict) + { + CFStringRef executable_cfstr = (CFStringRef)CFDictionaryGetValue(bundleInfoDict, CFSTR("CFBundleExecutable")); // get the name of the actual executable (e.g. TextEdit or firefox-bin) + int max_file_length = 256; // (max file name length is 255 in OSX) + char executable_buf[max_file_length]; + if(CFStringGetCString(executable_cfstr, executable_buf, max_file_length, kCFStringEncodingMacRoman)) // convert CFStringRef to char* + { + executable_path += std::string("/Contents/MacOS/") + std::string(executable_buf); // append path to executable directory and then executable name to exec path + } + else + { + std::string warning = "Unable to get CString from CFString for executable path"; + popupAndPrintWarning(warning); + } + } + else + { + std::string warning = "Unable to get bundle info dictionary from application bundle"; + popupAndPrintWarning(warning); + } + } + else + { + if(-1 != executable_path.find(".app")) // only warn if this path actually had ".app" in it, i.e. it probably just wasn'nt an app bundle and that's okay + { + std::string warning = std::string("Unable to get bundle from path \"") + chosen_path + std::string("\""); + popupAndPrintWarning(warning); + } + } + +#endif + mEditorPathTextBox->setText(std::string(executable_path)); // copy the path to the executable to the textfield for display and later fetching +} + +// Respond to button click to browse for a VLT-generated diffs file +void LLFloaterUIPreview::onClickBrowseForDiffs() +{ + // create load dialog box + LLFilePicker::ELoadFilter type = (LLFilePicker::ELoadFilter)((intptr_t)((void*)LLFilePicker::FFLOAD_XML)); // nothing for *.exe so just use all + LLFilePicker& picker = LLFilePicker::instance(); + if (!picker.getOpenFile(type)) // user cancelled -- do nothing + { + return; + } + + // put the selected path into text field + const std::string chosen_path = picker.getFirstFile(); + mDiffPathTextBox->setText(std::string(chosen_path)); // copy the path to the executable to the textfield for display and later fetching + if(LLView::sHighlightingDiffs) // if we're already highlighting, toggle off and then on so we get the data from the new file + { + onClickToggleDiffHighlighting(); + onClickToggleDiffHighlighting(); + } +} + +void LLFloaterUIPreview::onClickToggleDiffHighlighting() +{ + if(mHighlightingOverlaps) + { + onClickToggleOverlapping(); + mToggleOverlapButton->toggleState(); + } + + LLView::sPreviewHighlightedElements.clear(); // clear lists first + mDiffsMap.clear(); + mFileList->clearHighlightedItems(); + + if(LLView::sHighlightingDiffs) // Turning highlighting off + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + return; + } + else // Turning highlighting on + { + // Get the file and make sure it exists + std::string path_in_textfield = mDiffPathTextBox->getText(); // get file path + BOOL error = FALSE; + + if(std::string("") == path_in_textfield) // check for blank file + { + std::string warning = "Unable to highlight differences because no file was provided; fill in the relevant text field"; + popupAndPrintWarning(warning); + error = TRUE; + } + + llstat dummy; + if(LLFile::stat(path_in_textfield.c_str(), &dummy) && !error) // check if the file exists (empty check is reduntant but useful for the informative error message) + { + std::string warning = std::string("Unable to highlight differences because an invalid path to a difference file was provided:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + // Build a list of changed elements as given by the XML + std::list changed_element_names; + LLXmlTree xml_tree; + BOOL success = xml_tree.parseFile(path_in_textfield.c_str(), TRUE); + + if(success && !error) + { + LLXmlTreeNode* root_floater = xml_tree.getRoot(); + if(!strncmp("XuiDelta",root_floater->getName().c_str(),9)) + { + for (LLXmlTreeNode* child = root_floater->getFirstChild(); // get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + child != NULL; + child = root_floater->getNextChild()) // get child for next iteration + { + if(!strncmp("file",child->getName().c_str(),5)) + { + scanDiffFile(child); + } + else if(!strncmp("error",child->getName().c_str(),6)) + { + std::string error_file, error_message; + child->getAttributeString("filename",error_file); + child->getAttributeString("message",error_message); + if(mDiffsMap.find(error_file) != mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(error_file,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[error_file].second->push_back(error_message); + } + else + { + std::string warning = std::string("Child was neither a file or an error, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + error = TRUE; + break; + } + } + } + else + { + std::string warning = std::string("Root node not named XuiDelta:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + } + else if(!error) + { + std::string warning = std::string("Unable to create tree from XML:\"") + path_in_textfield + "\""; + popupAndPrintWarning(warning); + error = TRUE; + } + + if(error) // if we encountered an error, reset the button to off + { + mToggleHighlightButton->setToggleState(FALSE); + } + else // only toggle if we didn't encounter an error + { + LLView::sHighlightingDiffs = !sHighlightingDiffs; + highlightChangedElements(); // *TODO: this is extraneous, right? + highlightChangedFiles(); // *TODO: this is extraneous, right? + } + } +} + +void LLFloaterUIPreview::scanDiffFile(LLXmlTreeNode* file_node) +{ + // Get file name + std::string file_name; + file_node->getAttributeString("name",file_name); + if(std::string("") == file_name) + { + std::string warning = std::string("Empty file name encountered in differences:\"") + file_name + "\""; + popupAndPrintWarning(warning); + return; + } + + // Get a list of changed elements + // Get the first child first, then below get the next one; otherwise the iterator is invalid (bug or feature in XML code?) + for (LLXmlTreeNode* child = file_node->getFirstChild(); child != NULL; child = file_node->getNextChild()) + { + if(!strncmp("delta",child->getName().c_str(),6)) + { + std::string id; + child->getAttributeString("id",id); + if(mDiffsMap.find(file_name) == mDiffsMap.end()) + { + mDiffsMap.insert(std::make_pair(file_name,std::make_pair(StringListPtr(new StringList), StringListPtr(new StringList)))); + } + mDiffsMap[file_name].first->push_back(std::string(id.c_str())); + } + else + { + std::string warning = std::string("Child of file was not a delta, but rather the following:\"") + std::string(child->getName()) + "\""; + popupAndPrintWarning(warning); + return; + } + } +} + +void LLFloaterUIPreview::highlightChangedElements() +{ + if(NULL == mLiveFile) + { + return; + } + + // Process differences first (we want their warnings to be shown underneath other warnings) + StringListPtr changed_element_paths; + DiffMap::iterator iterExists = mDiffsMap.find(mLiveFile->mFileName); + if(iterExists != mDiffsMap.end()) + { + changed_element_paths = mDiffsMap[mLiveFile->mFileName].first; // retrieve list of changed element paths from map + } + + for(std::list::iterator iter = changed_element_paths->begin(); iter != changed_element_paths->end(); ++iter) // for every changed element path + { + LLView* element = mDisplayedFloater; + if(!strncmp(iter->c_str(),".",1)) // if it's the root floater itself + { + continue; + } + + // Split element hierarchy path on period (*HACK: it's possible that the element name will have a period in it, in which case this won't work. See https://wiki.lindenlab.com/wiki/Viewer_Localization_Tool_Documentation.) + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("."); + tokenizer tokens(*iter, sep); + tokenizer::iterator token_iter; + BOOL failed = FALSE; + for(token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + element = element->findChild(*token_iter,FALSE); // try to find element: don't recur, and don't create if missing + + // if we still didn't find it... + if(NULL == element) + { + llinfos << "Unable to find element in XuiDelta file named \"" << *iter << "\" in file \"" << mLiveFile->mFileName << + "\". The element may no longer exist, the path may be incorrect, or it may not be a non-displayable element (not an LLView) such as a \"string\" type." << llendl; + failed = TRUE; + break; + } + } + + if(!failed) + { + // Now that we have a pointer to the actual element, add it to the list of elements to be highlighted + std::set::iterator iter2 = std::find(LLView::sPreviewHighlightedElements.begin(), LLView::sPreviewHighlightedElements.end(), element); + if(iter2 == LLView::sPreviewHighlightedElements.end()) + { + LLView::sPreviewHighlightedElements.insert(element); + } + } + } + + // Process errors second, so their warnings show up on top of other warnings + StringListPtr error_list; + if(iterExists != mDiffsMap.end()) + { + error_list = mDiffsMap[mLiveFile->mFileName].second; + } + for(std::list::iterator iter = error_list->begin(); iter != error_list->end(); ++iter) // for every changed element path + { + std::string warning = std::string("Error listed among differences. Filename: \"") + mLiveFile->mFileName + "\". Message: \"" + *iter + "\""; + popupAndPrintWarning(warning); + } +} + +void LLFloaterUIPreview::highlightChangedFiles() +{ + for(DiffMap::iterator iter = mDiffsMap.begin(); iter != mDiffsMap.end(); ++iter) // for every file listed in diffs + { + LLScrollListItem* item = mFileList->getItemByLabel(std::string(iter->first), FALSE, 1); + if(item) + { + item->setHighlighted(TRUE); + } + } +} + +// Respond to button click to browse for an executable with which to edit XML files +void LLFloaterUIPreview::onClickCloseDisplayedFloater(S32 caller_id) +{ + if(caller_id == PRIMARY_FLOATER) + { + mCloseOtherButton->setEnabled(FALSE); + mToggleOverlapButton->setEnabled(FALSE); + + if(mDisplayedFloater) + { + mLastDisplayedX = mDisplayedFloater->calcScreenRect().mLeft; + mLastDisplayedY = mDisplayedFloater->calcScreenRect().mBottom; + delete mDisplayedFloater; + mDisplayedFloater = NULL; + } + + if(mLiveFile) + { + delete mLiveFile; + mLiveFile = NULL; + } + + if(mToggleOverlapButton->getToggleState()) + { + mToggleOverlapButton->toggleState(); + onClickToggleOverlapping(); + } + + LLView::sPreviewClickedElement = NULL; // stop overlapping elements panel from drawing + mOverlapPanel->mLastClickedElement = NULL; + } + else + { + mCloseOtherButton_2->setEnabled(FALSE); + delete mDisplayedFloater_2; + mDisplayedFloater_2 = NULL; + } + +} + +BOOL LLPreviewedFloater::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + selectElement(this,x,y,0); + return TRUE; +} + +// *NOTE: In order to hide all of the overlapping elements of the selected element so as to see it in context, here is what you would need to do: +// -This selectElement call fills the overlap panel as normal. The element which is "selected" here is actually just an intermediate selection step; +// what you've really selected is a list of elements: the one you clicked on and everything that overlaps it. +// -The user then selects one of the elements from this list the overlap panel (click handling to the overlap panel would have to be added). +// This becomes the final selection (as opposed to the intermediate selection that was just made). +// -Everything else that is currently displayed on the overlap panel should be hidden from view in the previewed floater itself (setVisible(FALSE)). +// -Subsequent clicks on other elements in the overlap panel (they should still be there) should make other elements the final selection. +// -On close or on the click of a new button, everything should be shown again and all selection state should be cleared. +// ~Jacob, 8/08 +BOOL LLPreviewedFloater::selectElement(LLView* parent, int x, int y, int depth) +{ + if(getVisible()) + { + BOOL handled = FALSE; + if(LLFloaterUIPreview::containerType(parent)) + { + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + S32 local_x = x - child->getRect().mLeft; + S32 local_y = y - child->getRect().mBottom; + if (child->pointInView(local_x, local_y) && + child->getVisible() && + selectElement(child, x, y, ++depth)) + { + handled = TRUE; + break; + } + } + } + + if(!handled) + { + LLView::sPreviewClickedElement = parent; + } + return TRUE; + } + else + { + return FALSE; + } +} + +void LLPreviewedFloater::draw() +{ + if(NULL != mFloaterUIPreview) + { + // Set and unset sDrawPreviewHighlights flag so as to avoid using two flags + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = TRUE; + } + LLFloater::draw(); + if(mFloaterUIPreview->mHighlightingOverlaps) + { + LLView::sDrawPreviewHighlights = FALSE; + } + } +} + +void LLFloaterUIPreview::onClickToggleOverlapping() +{ + if(LLView::sHighlightingDiffs) + { + onClickToggleDiffHighlighting(); + mToggleHighlightButton->toggleState(); + } + LLView::sPreviewHighlightedElements.clear(); // clear lists first + + S32 width, height; + getResizeLimits(&width, &height); // illegal call of non-static member function + if(mHighlightingOverlaps) + { + mHighlightingOverlaps = !mHighlightingOverlaps; + // reset list of preview highlighted elements + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight - mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width - mOverlapPanel->getRect().getWidth(), height); + } + else + { + mHighlightingOverlaps = !mHighlightingOverlaps; + displayFloater(FALSE,1); + setRect(LLRect(getRect().mLeft,getRect().mTop,getRect().mRight + mOverlapPanel->getRect().getWidth(),getRect().mBottom)); + setResizeLimits(width + mOverlapPanel->getRect().getWidth(), height); + } + childSetVisible("overlap_scroll", mHighlightingOverlaps); +} + +void LLFloaterUIPreview::findOverlapsInChildren(LLView* parent) +{ + if(parent->getChildCount() == 0 || !containerType(parent)) // if it has no children or isn't a container type, skip it + { + return; + } + + // for every child of the parent + for(child_list_const_iter_t child_it = parent->getChildList()->begin(); child_it != parent->getChildList()->end(); ++child_it) + { + LLView* child = *child_it; + if(overlapIgnorable(child)) + { + continue; + } + + // for every sibling + for(child_list_const_iter_t sibling_it = parent->getChildList()->begin(); sibling_it != parent->getChildList()->end(); ++sibling_it) // for each sibling + { + LLView* sibling = *sibling_it; + if(overlapIgnorable(sibling)) + { + continue; + } + + // if they overlap... (we don't care if they're visible or enabled -- we want to check those anyway, i.e. hidden tabs that can be later shown) + if(sibling != child && elementOverlap(child, sibling)) + { + mOverlapPanel->mOverlapMap[child].push_back(sibling); // add to the map + } + } + findOverlapsInChildren(child); // recur + } +} + +// *HACK: don't overlap with the drag handle and various other elements +// This is using dynamic casts because there is no object-oriented way to tell which elements contain localizable text. These are a few that are ignorable. +// *NOTE: If a list of elements which have localizable content were created, this function should return false if viewp's class is in that list. +BOOL LLFloaterUIPreview::overlapIgnorable(LLView* viewp) +{ + return NULL != dynamic_cast(viewp) || + NULL != dynamic_cast(viewp) || + NULL != dynamic_cast(viewp); +} + +// *HACK: these are the only two container types as of 8/08, per Richard +// This is using dynamic casts because there is no object-oriented way to tell which elements are containers. +BOOL LLFloaterUIPreview::containerType(LLView* viewp) +{ + return NULL != dynamic_cast(viewp) || NULL != dynamic_cast(viewp); +} + +// Check if two llview's rectangles overlap, with some tolerance +BOOL LLFloaterUIPreview::elementOverlap(LLView* view1, LLView* view2) +{ + LLSD rec1 = view1->getRect().getValue(); + LLSD rec2 = view2->getRect().getValue(); + int tolerance = 2; + return (int)rec1[0] <= (int)rec2[2] - tolerance && + (int)rec2[0] <= (int)rec1[2] - tolerance && + (int)rec1[3] <= (int)rec2[1] - tolerance && + (int)rec2[3] <= (int)rec1[1] - tolerance; +} + +void LLOverlapPanel::draw() +{ + static const std::string current_selection_text("Current selection: "); + static const std::string overlapper_text("Overlapper: "); + LLColor4 text_color = LLColor4::grey; + gGL.color4fv(text_color.mV); + + if(!LLView::sPreviewClickedElement) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); + } + else + { + OverlapMap::iterator iterExists = mOverlapMap.find(LLView::sPreviewClickedElement); + if(iterExists == mOverlapMap.end()) + { + return; + } + + std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + if(overlappers.size() == 0) + { + LLUI::translate(5,getRect().getHeight()-20); // translate to top-5,left-5 + LLView::sDrawPreviewHighlights = FALSE; + std::string current_selection = std::string(current_selection_text + LLView::sPreviewClickedElement->getName() + " (no elements overlap)"); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(current_selection) + 10; + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection, 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); + // widen panel enough to fit this text + LLRect rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + return; + } + + // recalculate required with and height; otherwise use cached + BOOL need_to_recalculate_bounds = FALSE; + if(mLastClickedElement == NULL) + { + need_to_recalculate_bounds = TRUE; + } + + if(NULL == mLastClickedElement) + { + mLastClickedElement = LLView::sPreviewClickedElement; + } + + // recalculate bounds for scroll panel + if(need_to_recalculate_bounds || LLView::sPreviewClickedElement->getName() != mLastClickedElement->getName()) + { + // reset panel's rectangle to its default width and height (300x600) + LLRect panel_rect = getRect(); + setRect(LLRect(panel_rect.mLeft,panel_rect.mTop,panel_rect.mLeft+getRect().getWidth(),panel_rect.mTop-getRect().getHeight())); + + LLRect rect; + + // change bounds for selected element + int height_sum = mLastClickedElement->getRect().getHeight() + mSpacing + 80; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > mLastClickedElement->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + mLastClickedElement->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = current_selection_text + LLView::sPreviewClickedElement->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + + std::list overlappers = mOverlapMap[LLView::sPreviewClickedElement]; + for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + height_sum += viewp->getRect().getHeight() + mSpacing*3; + + // widen panel's rectangle to accommodate widest overlapping element of this floater + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() > viewp->getRect().getWidth() + 5 ? rect.mRight : rect.mLeft + viewp->getRect().getWidth() + 5, rect.mBottom)); + + // and widen to accomodate text if that's wider + std::string display_text = overlapper_text + viewp->getName(); + S32 text_width = LLFontGL::getFontSansSerifSmall()->getWidth(display_text) + 10; + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.getWidth() < text_width ? rect.mLeft + text_width : rect.mRight,rect.mTop)); + } + // change panel's height to accommodate all element heights plus spacing between them + rect = getRect(); + setRect(LLRect(rect.mLeft,rect.mTop,rect.mRight,rect.mTop-height_sum)); + } + + LLUI::translate(5,getRect().getHeight()-10); // translate to top left + LLView::sDrawPreviewHighlights = FALSE; + + // draw currently-selected element at top of overlappers + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(current_selection_text + LLView::sPreviewClickedElement->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); + LLUI::translate(0,-mSpacing-LLView::sPreviewClickedElement->getRect().getHeight()); // skip spacing distance + height + LLView::sPreviewClickedElement->draw(); + + for(std::list::iterator overlap_it = overlappers.begin(); overlap_it != overlappers.end(); ++overlap_it) + { + LLView* viewp = *overlap_it; + + // draw separating line + LLUI::translate(0,-mSpacing); + gl_line_2d(0,0,getRect().getWidth()-10,0,LLColor4(192.0f/255.0f,192.0f/255.0f,192.0f/255.0f)); + + // draw name + LLUI::translate(0,-mSpacing); + LLFontGL::getFontSansSerifSmall()->renderUTF8(overlapper_text + viewp->getName(), 0, 0, 0, text_color, + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); + + // draw element + LLUI::translate(0,-mSpacing-viewp->getRect().getHeight()); // skip spacing distance + height + viewp->draw(); + } + mLastClickedElement = LLView::sPreviewClickedElement; + } +} diff --git a/indra/newview/llfloateruipreview.h b/indra/newview/llfloateruipreview.h new file mode 100644 index 0000000000..b8c378e2e9 --- /dev/null +++ b/indra/newview/llfloateruipreview.h @@ -0,0 +1,174 @@ +/** + * @file llfloateruipreview.h + * @brief Tool for previewing and editing floaters + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// Tool for previewing floaters and panels for localization and UI design purposes. +// See: https://wiki.lindenlab.com/wiki/GUI_Preview_And_Localization_Tools +// See: https://jira.lindenlab.com/browse/DEV-16869 + +#ifndef LL_LLUIPREVIEW_H +#define LL_LLUIPREVIEW_H + +#include "llfloater.h" // superclass +#include "llscrollcontainer.h" // scroll container for overlapping elements +#include "lllivefile.h" // live file poll/stat/reload +#include +#include + +// Forward declarations to avoid header dependencies +class LLEventTimer; +class LLColor; +class LLScrollListCtrl; +class LLComboBox; +class LLButton; +class LLLineEditor; +class LLXmlTreeNode; +class LLFloaterUIPreview; +class LLFadeEventTimer; + +class LLLocalizationResetForcer; +class LLGUIPreviewLiveFile; +class LLFadeEventTimer; +class LLPreviewedFloater; + +// Implementation of custom overlapping element display panel +class LLOverlapPanel : public LLPanel +{ +public: + struct Params : public LLInitParam::Block + { + Params() {} + }; + LLOverlapPanel(Params p = Params()) : LLPanel(p), + mSpacing(10), + // mClickedElement(NULL), + mLastClickedElement(NULL) + { + mOriginalWidth = getRect().getWidth(); + mOriginalHeight = getRect().getHeight(); + } + virtual void draw(); + + typedef std::map > OverlapMap; + OverlapMap mOverlapMap; // map, of XUI element to a list of XUI elements it overlaps + + // LLView *mClickedElement; + LLView *mLastClickedElement; + int mOriginalWidth, mOriginalHeight, mSpacing; +}; + + +class LLFloaterUIPreview : public LLFloater +{ +public: + // Setup + LLFloaterUIPreview(const LLSD& key); + virtual ~LLFloaterUIPreview(); + + std::string getLocStr(S32 ID); // fetches the localization string based on what is selected in the drop-down menu + void displayFloater(BOOL click, S32 ID, bool save = false); // needs to be public so live file can call it when it finds an update + + BOOL postBuild(); // post-build setup (called by superclass' constructor) + void refreshList(); // refresh list (empty it out and fill it up from scratch) + void addFloaterEntry(const std::string& path); // add a single file's entry to the list of floaters + + static BOOL containerType(LLView* viewp); // check if the element is a container type and tree traverses need to look at its children + +public: + LLPreviewedFloater* mDisplayedFloater; // the floater which is currently being displayed + LLPreviewedFloater* mDisplayedFloater_2; // the floater which is currently being displayed + LLGUIPreviewLiveFile* mLiveFile; // live file for checking for updates to the currently-displayed XML file + LLOverlapPanel* mOverlapPanel; // custom overlapping elements panel + // BOOL mHighlightingDiffs; // bool for whether localization diffs are being highlighted or not + BOOL mHighlightingOverlaps; // bool for whether overlapping elements are being highlighted + + // typedef std::map,std::list > > DiffMap; // this version copies the lists etc., and thus is bad memory-wise + typedef std::list StringList; + typedef boost::shared_ptr StringListPtr; + typedef std::map > DiffMap; + DiffMap mDiffsMap; // map, of filename to pair of list of changed element paths and list of errors + +protected: + void onClose(const LLSD& app_quitting); + +private: + // XUI elements for this floater + LLScrollListCtrl* mFileList; // scroll list control for file list + LLLineEditor* mEditorPathTextBox; // text field for path to editor executable + LLLineEditor* mEditorArgsTextBox; // text field for arguments to editor executable + LLLineEditor* mDiffPathTextBox; // text field for path to diff file + LLButton* mDisplayFloaterBtn; // button to display primary floater + LLButton* mDisplayFloaterBtn_2; // button to display secondary floater + LLButton* mEditFloaterBtn; // button to edit floater + LLButton* mExecutableBrowseButton; // button to browse for executable + LLButton* mCloseOtherButton; // button to close primary displayed floater + LLButton* mCloseOtherButton_2; // button to close secondary displayed floater + LLButton* mDiffBrowseButton; // button to browse for diff file + LLButton* mToggleHighlightButton; // button to toggle highlight of files/elements with diffs + LLButton* mToggleOverlapButton; // button to togle overlap panel/highlighting + LLComboBox* mLanguageSelection; // combo box for primary language selection + LLComboBox* mLanguageSelection_2; // combo box for secondary language selection + LLScrollContainer* mOverlapScrollView; // overlapping elements scroll container + S32 mLastDisplayedX, mLastDisplayedY; // stored position of last floater so the new one opens up in the same place + std::string mDelim; // the OS-specific delimiter character (/ or \) (*TODO: this shouldn't be needed, right?) + + std::string mSavedEditorPath; // stored editor path so closing this floater doesn't reset it + std::string mSavedEditorArgs; // stored editor args so closing this floater doesn't reset it + std::string mSavedDiffPath; // stored diff file path so closing this floater doesn't reset it + + // Internal functionality + static void popupAndPrintWarning(std::string& warning); // pop up a warning + std::string getLocalizedDirectory(); // build and return the path to the XUI directory for the currently-selected localization + void scanDiffFile(LLXmlTreeNode* file_node); // scan a given XML node for diff entries and highlight them in its associated file + void highlightChangedElements(); // look up the list of elements to highlight and highlight them in the current floater + void highlightChangedFiles(); // look up the list of changed files to highlight and highlight them in the scroll list + void findOverlapsInChildren(LLView* parent); // fill the map below with element overlap information + static BOOL overlapIgnorable(LLView* viewp); // check it the element can be ignored for overlap/localization purposes + + // check if two elements overlap using their rectangles + // used instead of llrect functions because by adding a few pixels of leeway I can cut down drastically on the number of overlaps + BOOL elementOverlap(LLView* view1, LLView* view2); + + // Button/drop-down action listeners (self explanatory) + void onClickDisplayFloater(S32 id); + void onClickSaveFloater(S32 id); + void onClickSaveAll(S32 id); + void onClickEditFloater(); + void onClickBrowseForEditor(); + void onClickBrowseForDiffs(); + void onClickToggleDiffHighlighting(); + void onClickToggleOverlapping(); + void onClickCloseDisplayedFloater(S32 id); + void onLanguageComboSelect(LLUICtrl* ctrl); + void onClickExportSchema(); +}; +#endif // LL_LLUIPREVIEW_H + diff --git a/indra/newview/llfloaterurldisplay.cpp b/indra/newview/llfloaterurldisplay.cpp index c265c6169a..3b9321a876 100644 --- a/indra/newview/llfloaterurldisplay.cpp +++ b/indra/newview/llfloaterurldisplay.cpp @@ -45,10 +45,10 @@ LLFloaterURLDisplay::LLFloaterURLDisplay(const LLSD& sd) + : LLFloater(sd) { mFactoryMap["place_details_panel"] = LLCallbackMap(LLFloaterURLDisplay::createPlaceDetail, this); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_url.xml", &getFactoryMap()); - this->setVisible(false); +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_url.xml"); // If positioned at 0,0 the teleport button is behind the toolbar. LLRect r = getRect(); diff --git a/indra/newview/llfloaterurldisplay.h b/indra/newview/llfloaterurldisplay.h index 91c544ae86..22f5a95ad0 100644 --- a/indra/newview/llfloaterurldisplay.h +++ b/indra/newview/llfloaterurldisplay.h @@ -40,11 +40,10 @@ class LLPanelPlace; class LLSD; class LLUUID; -class LLFloaterURLDisplay : public LLFloater, public LLFloaterSingleton +class LLFloaterURLDisplay : public LLFloater { + friend class LLFloaterReg; public: - LLFloaterURLDisplay(const LLSD& sd); - virtual ~LLFloaterURLDisplay(); void displayParcelInfo(U64 region_handle, const LLVector3& pos); void setSnapshotDisplay(const LLUUID& snapshot_id); @@ -54,6 +53,9 @@ public: static void* createPlaceDetail(void* userdata); private: + LLFloaterURLDisplay(const LLSD& sd); + virtual ~LLFloaterURLDisplay(); + LLVector3 mRegionPosition; U64 mRegionHandle; LLPanelPlace* mPlacePanel; diff --git a/indra/newview/llfloaterurlentry.cpp b/indra/newview/llfloaterurlentry.cpp index 9d91aa9868..1e975cd447 100644 --- a/indra/newview/llfloaterurlentry.cpp +++ b/indra/newview/llfloaterurlentry.cpp @@ -86,12 +86,22 @@ public: // LLFloaterURLEntry() //----------------------------------------------------------------------------- LLFloaterURLEntry::LLFloaterURLEntry(LLHandle parent) - : - LLFloater(), - mPanelLandMediaHandle(parent) + : LLFloater(LLSD()), + mPanelLandMediaHandle(parent) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_url_entry.xml"); + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_url_entry.xml", NULL); +} +//----------------------------------------------------------------------------- +// ~LLFloaterURLEntry() +//----------------------------------------------------------------------------- +LLFloaterURLEntry::~LLFloaterURLEntry() +{ + sInstance = NULL; +} + +BOOL LLFloaterURLEntry::postBuild() +{ mMediaURLEdit = getChild("media_entry"); // Cancel button @@ -99,7 +109,6 @@ LLFloaterURLEntry::LLFloaterURLEntry(LLHandle parent) // Cancel button childSetAction("clear_btn", onBtnClear, this); - // clear media list button LLSD parcel_history = LLURLHistory::getURLHistory("parcel"); bool enable_clear_button = parcel_history.size() > 0 ? true : false; @@ -111,17 +120,8 @@ LLFloaterURLEntry::LLFloaterURLEntry(LLHandle parent) setDefaultBtn("ok_btn"); buildURLHistory(); - sInstance = this; + return TRUE; } - -//----------------------------------------------------------------------------- -// ~LLFloaterURLEntry() -//----------------------------------------------------------------------------- -LLFloaterURLEntry::~LLFloaterURLEntry() -{ - sInstance = NULL; -} - void LLFloaterURLEntry::buildURLHistory() { LLCtrlListInterface* url_list = childGetListInterface("media_entry"); @@ -155,7 +155,7 @@ void LLFloaterURLEntry::headerFetchComplete(U32 status, const std::string& mime_ // Decrement the cursor getWindow()->decBusyCount(); childSetVisible("loading_label", false); - close(); + closeFloater(); } // static @@ -163,7 +163,7 @@ LLHandle LLFloaterURLEntry::show(LLHandle parent) { if (sInstance) { - sInstance->open(); + sInstance->openFloater(); } else { @@ -227,7 +227,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) } // Discover the MIME type only for "http" scheme. - if(scheme == "http") + if(scheme == "http" || scheme == "https") { LLHTTPClient::getHeaderOnly( media_url, new LLMediaTypeResponder(self->getHandle())); @@ -254,7 +254,7 @@ void LLFloaterURLEntry::onBtnOK( void* userdata ) void LLFloaterURLEntry::onBtnCancel( void* userdata ) { LLFloaterURLEntry *self =(LLFloaterURLEntry *)userdata; - self->close(); + self->closeFloater(); } // static diff --git a/indra/newview/llfloaterurlentry.h b/indra/newview/llfloaterurlentry.h index 6d04326cf8..0aeca823b8 100644 --- a/indra/newview/llfloaterurlentry.h +++ b/indra/newview/llfloaterurlentry.h @@ -1,6 +1,6 @@ /** - * @file llfloaternamedesc.h - * @brief LLFloaterNameDesc class definition + * @file llfloaterurlentry.h + * @brief LLFloaterURLEntry class definition * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -45,7 +45,7 @@ public: // Can only be shown by LLPanelLandMedia, and pushes data back into // that panel via the handle. static LLHandle show(LLHandle panel_land_media_handle); - + /*virtual*/ BOOL postBuild(); void updateFromLandMediaPanel(); void headerFetchComplete(U32 status, const std::string& mime_type); diff --git a/indra/newview/llfloatervoicedevicesettings.cpp b/indra/newview/llfloatervoicedevicesettings.cpp index 2922628786..a7658d90e9 100644 --- a/indra/newview/llfloatervoicedevicesettings.cpp +++ b/indra/newview/llfloatervoicedevicesettings.cpp @@ -36,12 +36,10 @@ #include "llfloatervoicedevicesettings.h" // Viewer includes -#include "llagent.h" #include "llbutton.h" #include "llcombobox.h" #include "llfocusmgr.h" #include "lliconctrl.h" -#include "llprefsvoice.h" #include "llsliderctrl.h" #include "llviewercontrol.h" #include "llvoiceclient.h" @@ -52,6 +50,7 @@ LLPanelVoiceDeviceSettings::LLPanelVoiceDeviceSettings() + : LLPanel() { mCtrlInputDevices = NULL; mCtrlOutputDevices = NULL; @@ -113,7 +112,7 @@ void LLPanelVoiceDeviceSettings::draw() { if (power_bar_idx < discrete_power) { - LLColor4 color = (power_bar_idx >= 3) ? gSavedSettings.getColor4("OverdrivenColor") : gSavedSettings.getColor4("SpeakingColor"); + LLColor4 color = (power_bar_idx >= 3) ? LLUIColorTable::instance().getColor("OverdrivenColor") : LLUIColorTable::instance().getColor("SpeakingColor"); gl_rect_2d(bar_view->getRect(), color, TRUE); } gl_rect_2d(bar_view->getRect(), LLColor4::grey, FALSE); @@ -240,7 +239,7 @@ void LLPanelVoiceDeviceSettings::refresh() } } -void LLPanelVoiceDeviceSettings::onOpen() +void LLPanelVoiceDeviceSettings::initialize() { mInputDevice = gSavedSettings.getString("VoiceInputAudioDevice"); mOutputDevice = gSavedSettings.getString("VoiceOutputAudioDevice"); @@ -255,7 +254,7 @@ void LLPanelVoiceDeviceSettings::onOpen() LLVoiceChannel::suspend(); } -void LLPanelVoiceDeviceSettings::onClose(bool app_quitting) +void LLPanelVoiceDeviceSettings::cleanup() { gVoiceClient->tuningStop(); LLVoiceChannel::resume(); @@ -284,34 +283,36 @@ void LLPanelVoiceDeviceSettings::onCommitOutputDevice(LLUICtrl* ctrl, void* user // LLFloaterVoiceDeviceSettings::LLFloaterVoiceDeviceSettings(const LLSD& seed) - : LLFloater(std::string("floater_device_settings")), + : LLFloater(seed), mDevicePanel(NULL) { mFactoryMap["device_settings"] = LLCallbackMap(createPanelVoiceDeviceSettings, this); // do not automatically open singleton floaters (as result of getInstance()) - BOOL no_open = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_device_settings.xml", &mFactoryMap, no_open); +// BOOL no_open = FALSE; +// Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_device_settings.xml", no_open); +} +BOOL LLFloaterVoiceDeviceSettings::postBuild() +{ + mCloseSignal.connect(boost::bind(&LLFloaterVoiceDeviceSettings::onClose, this)); + center(); + return TRUE; } - -void LLFloaterVoiceDeviceSettings::onOpen() +void LLFloaterVoiceDeviceSettings::onOpen(const LLSD& key) { if(mDevicePanel) { - mDevicePanel->onOpen(); + mDevicePanel->initialize(); } - - LLFloater::onOpen(); } -void LLFloaterVoiceDeviceSettings::onClose(bool app_quitting) +void LLFloaterVoiceDeviceSettings::onClose() { if(mDevicePanel) { - mDevicePanel->onClose(app_quitting); + mDevicePanel->apply(); + mDevicePanel->cleanup(); } - - setVisible(FALSE); } void LLFloaterVoiceDeviceSettings::apply() diff --git a/indra/newview/llfloatervoicedevicesettings.h b/indra/newview/llfloatervoicedevicesettings.h index d30a57f161..2565bfad2b 100644 --- a/indra/newview/llfloatervoicedevicesettings.h +++ b/indra/newview/llfloatervoicedevicesettings.h @@ -36,8 +36,6 @@ #include "llfloater.h" -class LLPrefsVoiceLogic; - class LLPanelVoiceDeviceSettings : public LLPanel { public: @@ -49,8 +47,8 @@ public: void apply(); void cancel(); void refresh(); - void onOpen(); - void onClose(bool app_quitting); + void initialize(); + void cleanup(); protected: static void onCommitInputDevice(LLUICtrl* ctrl, void* user_data); @@ -64,19 +62,26 @@ protected: BOOL mDevicesUpdated; }; -class LLFloaterVoiceDeviceSettings : public LLFloater, public LLFloaterSingleton +class LLFloaterVoiceDeviceSettings : public LLFloater { + friend class LLFloaterReg; + public: - LLFloaterVoiceDeviceSettings(const LLSD& seed); - /*virtual*/ void onOpen(); - /*virtual*/ void onClose(bool app_quitting); + + virtual BOOL postBuild(); + /*virtual*/ void onOpen(const LLSD& key); /*virtual*/ void draw(); void apply(); void cancel(); - +private: + LLFloaterVoiceDeviceSettings(const LLSD& seed); + protected: static void* createPanelVoiceDeviceSettings(void* user_data); - + + void onClose(); + +protected: LLPanelVoiceDeviceSettings* mDevicePanel; }; diff --git a/indra/newview/llfloaterwater.cpp b/indra/newview/llfloaterwater.cpp index 730c1393ca..72c82c178b 100644 --- a/indra/newview/llfloaterwater.cpp +++ b/indra/newview/llfloaterwater.cpp @@ -37,6 +37,7 @@ #include "pipeline.h" #include "llsky.h" +#include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcolorswatch.h" @@ -62,29 +63,19 @@ #undef max -LLFloaterWater* LLFloaterWater::sWaterMenu = NULL; - std::set LLFloaterWater::sDefaultPresets; -LLFloaterWater::LLFloaterWater() : LLFloater(std::string("water floater")) +LLFloaterWater::LLFloaterWater(const LLSD& key) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_water.xml"); - - // add the combo boxes - LLComboBox* comboBox = getChild("WaterPresetsCombo"); + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_water.xml"); +} - if(comboBox != NULL) { - - std::map::iterator mIt = - LLWaterParamManager::instance()->mParamList.begin(); - for(; mIt != LLWaterParamManager::instance()->mParamList.end(); mIt++) - { - comboBox->add(mIt->first); - } - - // set defaults on combo boxes - comboBox->selectByValue(LLSD("Default")); - } +LLFloaterWater::~LLFloaterWater() +{ +} +BOOL LLFloaterWater::postBuild() +{ std::string def_water = getString("WLDefaultWaterNames"); @@ -96,15 +87,27 @@ LLFloaterWater::LLFloaterWater() : LLFloater(std::string("water floater")) std::string tok(*token_iter); sDefaultPresets.insert(tok); } + + // add the combo boxes + LLComboBox* comboBox = getChild("WaterPresetsCombo"); + if(comboBox != NULL) { + + std::map::iterator mIt = + LLWaterParamManager::instance()->mParamList.begin(); + for(; mIt != LLWaterParamManager::instance()->mParamList.end(); mIt++) + { + comboBox->add(mIt->first); + } + + // set defaults on combo boxes + comboBox->selectByValue(LLSD("Default")); + } // load it up initCallbacks(); + syncMenu(); + return TRUE; } - -LLFloaterWater::~LLFloaterWater() -{ -} - void LLFloaterWater::initCallbacks(void) { // help buttons @@ -126,63 +129,58 @@ void LLFloaterWater::initCallbacks(void) { LLWaterParamManager * param_mgr = LLWaterParamManager::instance(); - childSetCommitCallback("WaterFogColor", onWaterFogColorMoved, ¶m_mgr->mFogColor); + getChild("WaterFogColor")->setCommitCallback(boost::bind(&LLFloaterWater::onWaterFogColorMoved, this, _1, ¶m_mgr->mFogColor)); // - childSetCommitCallback("WaterGlow", onColorControlAMoved, ¶m_mgr->mFogColor); + getChild("WaterGlow")->setCommitCallback(boost::bind(&LLFloaterWater::onColorControlAMoved, this, _1, ¶m_mgr->mFogColor)); // fog density - childSetCommitCallback("WaterFogDensity", onExpFloatControlMoved, ¶m_mgr->mFogDensity); - childSetCommitCallback("WaterUnderWaterFogMod", onFloatControlMoved, ¶m_mgr->mUnderWaterFogMod); + getChild("WaterFogDensity")->setCommitCallback(boost::bind(&LLFloaterWater::onExpFloatControlMoved, this, _1, ¶m_mgr->mFogDensity)); + getChild("WaterUnderWaterFogMod")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mUnderWaterFogMod)); // blue density - childSetCommitCallback("WaterNormalScaleX", onVector3ControlXMoved, ¶m_mgr->mNormalScale); - childSetCommitCallback("WaterNormalScaleY", onVector3ControlYMoved, ¶m_mgr->mNormalScale); - childSetCommitCallback("WaterNormalScaleZ", onVector3ControlZMoved, ¶m_mgr->mNormalScale); + getChild("WaterNormalScaleX")->setCommitCallback(boost::bind(&LLFloaterWater::onVector3ControlXMoved, this, _1, ¶m_mgr->mNormalScale)); + getChild("WaterNormalScaleY")->setCommitCallback(boost::bind(&LLFloaterWater::onVector3ControlYMoved, this, _1, ¶m_mgr->mNormalScale)); + getChild("WaterNormalScaleZ")->setCommitCallback(boost::bind(&LLFloaterWater::onVector3ControlZMoved, this, _1, ¶m_mgr->mNormalScale)); // fresnel - childSetCommitCallback("WaterFresnelScale", onFloatControlMoved, ¶m_mgr->mFresnelScale); - childSetCommitCallback("WaterFresnelOffset", onFloatControlMoved, ¶m_mgr->mFresnelOffset); + getChild("WaterFresnelScale")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mFresnelScale)); + getChild("WaterFresnelOffset")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mFresnelOffset)); // scale above/below - childSetCommitCallback("WaterScaleAbove", onFloatControlMoved, ¶m_mgr->mScaleAbove); - childSetCommitCallback("WaterScaleBelow", onFloatControlMoved, ¶m_mgr->mScaleBelow); + getChild("WaterScaleAbove")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mScaleAbove)); + getChild("WaterScaleBelow")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mScaleBelow)); // blur mult - childSetCommitCallback("WaterBlurMult", onFloatControlMoved, ¶m_mgr->mBlurMultiplier); + getChild("WaterBlurMult")->setCommitCallback(boost::bind(&LLFloaterWater::onFloatControlMoved, this, _1, ¶m_mgr->mBlurMultiplier)); // Load/save - LLComboBox* comboBox = getChild("WaterPresetsCombo"); - - //childSetAction("WaterLoadPreset", onLoadPreset, comboBox); - childSetAction("WaterNewPreset", onNewPreset, comboBox); - childSetAction("WaterSavePreset", onSavePreset, comboBox); - childSetAction("WaterDeletePreset", onDeletePreset, comboBox); +// getChild("WaterLoadPreset")->setCommitCallback(boost::bind(&LLFloaterWater::onLoadPreset, this)); + getChild("WaterNewPreset")->setCommitCallback(boost::bind(&LLFloaterWater::onNewPreset, this)); + getChild("WaterSavePreset")->setCommitCallback(boost::bind(&LLFloaterWater::onSavePreset, this)); + getChild("WaterDeletePreset")->setCommitCallback(boost::bind(&LLFloaterWater::onDeletePreset, this)); // wave direction - childSetCommitCallback("WaterWave1DirX", onVector2ControlXMoved, ¶m_mgr->mWave1Dir); - childSetCommitCallback("WaterWave1DirY", onVector2ControlYMoved, ¶m_mgr->mWave1Dir); - childSetCommitCallback("WaterWave2DirX", onVector2ControlXMoved, ¶m_mgr->mWave2Dir); - childSetCommitCallback("WaterWave2DirY", onVector2ControlYMoved, ¶m_mgr->mWave2Dir); + getChild("WaterWave1DirX")->setCommitCallback(boost::bind(&LLFloaterWater::onVector2ControlXMoved, this, _1, ¶m_mgr->mWave1Dir)); + getChild("WaterWave1DirY")->setCommitCallback(boost::bind(&LLFloaterWater::onVector2ControlYMoved, this, _1, ¶m_mgr->mWave1Dir)); + getChild("WaterWave2DirX")->setCommitCallback(boost::bind(&LLFloaterWater::onVector2ControlXMoved, this, _1, ¶m_mgr->mWave2Dir)); + getChild("WaterWave2DirY")->setCommitCallback(boost::bind(&LLFloaterWater::onVector2ControlYMoved, this, _1, ¶m_mgr->mWave2Dir)); - comboBox->setCommitCallback(onChangePresetName); + getChild("WaterPresetsCombo")->setCommitCallback(boost::bind(&LLFloaterWater::onChangePresetName, this, _1)); LLTextureCtrl* textCtrl = getChild("WaterNormalMap"); textCtrl->setDefaultImageAssetID(DEFAULT_WATER_NORMAL); - childSetCommitCallback("WaterNormalMap", onNormalMapPicked, NULL); + getChild("WaterNormalMap")->setCommitCallback(boost::bind(&LLFloaterWater::onNormalMapPicked, this, _1)); } -void LLFloaterWater::onClickHelp(void* data) +void LLFloaterWater::onClickHelp(std::string xml_alert) { - LLFloaterWater* self = LLFloaterWater::instance(); - - const std::string* xml_alert = (std::string*)data; - LLNotifications::instance().add(self->contextualNotification(*xml_alert)); + LLNotifications::instance().add(contextualNotification(xml_alert)); } void LLFloaterWater::initHelpBtn(const std::string& name, const std::string& xml_alert) { - childSetAction(name, onClickHelp, new std::string(xml_alert)); + getChild(name)->setClickedCallback(boost::bind(&LLFloaterWater::onClickHelp, this, xml_alert)); } bool LLFloaterWater::newPromptCallback(const LLSD& notification, const LLSD& response) @@ -196,7 +194,7 @@ bool LLFloaterWater::newPromptCallback(const LLSD& notification, const LLSD& res } if(option == 0) { - LLComboBox* comboBox = sWaterMenu->getChild( "WaterPresetsCombo"); + LLComboBox* comboBox = getChild( "WaterPresetsCombo"); LLWaterParamManager * param_mgr = LLWaterParamManager::instance(); @@ -240,7 +238,7 @@ void LLFloaterWater::syncMenu() LLColor4 col = param_mgr->getFogColor(); childSetValue("WaterGlow", col.mV[3]); col.mV[3] = 1.0f; - LLColorSwatchCtrl* colCtrl = sWaterMenu->getChild("WaterFogColor"); + LLColorSwatchCtrl* colCtrl = getChild("WaterFogColor"); colCtrl->set(col); @@ -285,56 +283,15 @@ void LLFloaterWater::syncMenu() childSetValue("WaterWave2DirX", param_mgr->mWave2Dir.mX); childSetValue("WaterWave2DirY", param_mgr->mWave2Dir.mY); - LLTextureCtrl* textCtrl = sWaterMenu->getChild("WaterNormalMap"); + LLTextureCtrl* textCtrl = getChild("WaterNormalMap"); textCtrl->setImageAssetID(param_mgr->getNormalMapID()); } -// static -LLFloaterWater* LLFloaterWater::instance() -{ - if (!sWaterMenu) - { - sWaterMenu = new LLFloaterWater(); - sWaterMenu->open(); - sWaterMenu->setFocus(TRUE); - } - return sWaterMenu; -} -void LLFloaterWater::show() -{ - LLFloaterWater* water = instance(); - water->syncMenu(); - - // comment in if you want the menu to rebuild each time - //LLUICtrlFactory::getInstance()->buildFloater(water, "floater_water.xml"); - //water->initCallbacks(); - - water->open(); -} - -bool LLFloaterWater::isOpen() -{ - if (sWaterMenu != NULL) { - return true; - } - return false; -} - -// virtual -void LLFloaterWater::onClose(bool app_quitting) -{ - if (sWaterMenu) - { - sWaterMenu->setVisible(FALSE); - } -} - // vector control callbacks -void LLFloaterWater::onVector3ControlXMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onVector3ControlXMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterVector3Control * vectorControl = static_cast(userData); vectorControl->mX = sldrCtrl->getValueF32(); @@ -344,10 +301,9 @@ void LLFloaterWater::onVector3ControlXMoved(LLUICtrl* ctrl, void* userData) } // vector control callbacks -void LLFloaterWater::onVector3ControlYMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onVector3ControlYMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterVector3Control * vectorControl = static_cast(userData); vectorControl->mY = sldrCtrl->getValueF32(); @@ -357,10 +313,9 @@ void LLFloaterWater::onVector3ControlYMoved(LLUICtrl* ctrl, void* userData) } // vector control callbacks -void LLFloaterWater::onVector3ControlZMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onVector3ControlZMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterVector3Control * vectorControl = static_cast(userData); vectorControl->mZ = sldrCtrl->getValueF32(); @@ -371,10 +326,9 @@ void LLFloaterWater::onVector3ControlZMoved(LLUICtrl* ctrl, void* userData) // vector control callbacks -void LLFloaterWater::onVector2ControlXMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onVector2ControlXMoved(LLUICtrl* ctrl, WaterVector2Control* vectorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterVector2Control * vectorControl = static_cast(userData); vectorControl->mX = sldrCtrl->getValueF32(); @@ -384,10 +338,9 @@ void LLFloaterWater::onVector2ControlXMoved(LLUICtrl* ctrl, void* userData) } // vector control callbacks -void LLFloaterWater::onVector2ControlYMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onVector2ControlYMoved(LLUICtrl* ctrl, WaterVector2Control* vectorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterVector2Control * vectorControl = static_cast(userData); vectorControl->mY = sldrCtrl->getValueF32(); @@ -397,10 +350,9 @@ void LLFloaterWater::onVector2ControlYMoved(LLUICtrl* ctrl, void* userData) } // color control callbacks -void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); colorControl->mR = sldrCtrl->getValueF32(); @@ -413,7 +365,7 @@ void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, void* userData) std::string name = colorControl->mSliderName; name.append("I"); - sWaterMenu->childSetValue(name, colorControl->mR); + childSetValue(name, colorControl->mR); } colorControl->update(LLWaterParamManager::instance()->mCurParams); @@ -421,10 +373,9 @@ void LLFloaterWater::onColorControlRMoved(LLUICtrl* ctrl, void* userData) LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); colorControl->mG = sldrCtrl->getValueF32(); @@ -437,7 +388,7 @@ void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, void* userData) std::string name = colorControl->mSliderName; name.append("I"); - sWaterMenu->childSetValue(name, colorControl->mG); + childSetValue(name, colorControl->mG); } @@ -446,10 +397,9 @@ void LLFloaterWater::onColorControlGMoved(LLUICtrl* ctrl, void* userData) LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); colorControl->mB = sldrCtrl->getValueF32(); @@ -462,7 +412,7 @@ void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, void* userData) std::string name = colorControl->mSliderName; name.append("I"); - sWaterMenu->childSetValue(name, colorControl->mB); + childSetValue(name, colorControl->mB); } colorControl->update(LLWaterParamManager::instance()->mCurParams); @@ -470,10 +420,9 @@ void LLFloaterWater::onColorControlBMoved(LLUICtrl* ctrl, void* userData) LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); colorControl->mA = sldrCtrl->getValueF32(); @@ -483,10 +432,9 @@ void LLFloaterWater::onColorControlAMoved(LLUICtrl* ctrl, void* userData) } -void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); colorControl->mI = sldrCtrl->getValueF32(); @@ -533,9 +481,9 @@ void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, void* userData) } // set the sliders to the new vals - sWaterMenu->childSetValue(rName, colorControl->mR); - sWaterMenu->childSetValue(gName, colorControl->mG); - sWaterMenu->childSetValue(bName, colorControl->mB); + childSetValue(rName, colorControl->mR); + childSetValue(gName, colorControl->mG); + childSetValue(bName, colorControl->mB); } // now update the current parameters and send them to shaders @@ -543,10 +491,9 @@ void LLFloaterWater::onColorControlIMoved(LLUICtrl* ctrl, void* userData) LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterExpFloatControl * expFloatControl = static_cast(userData); F32 val = sldrCtrl->getValueF32(); expFloatControl->mExp = val; @@ -556,50 +503,40 @@ void LLFloaterWater::onExpFloatControlMoved(LLUICtrl* ctrl, void* userData) LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onFloatControlMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floatControl) { LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WaterFloatControl * floatControl = static_cast(userData); floatControl->mX = sldrCtrl->getValueF32() / floatControl->mMult; floatControl->update(LLWaterParamManager::instance()->mCurParams); LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onWaterFogColorMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onWaterFogColorMoved(LLUICtrl* ctrl, WaterColorControl* colorControl) { LLColorSwatchCtrl* swatch = static_cast(ctrl); - WaterColorControl * colorControl = static_cast(userData); *colorControl = swatch->get(); colorControl->update(LLWaterParamManager::instance()->mCurParams); LLWaterParamManager::instance()->propagateParameters(); } -void LLFloaterWater::onBoolToggle(LLUICtrl* ctrl, void* userData) -{ - LLCheckBoxCtrl* cbCtrl = static_cast(ctrl); - - bool value = cbCtrl->get(); - (*(static_cast(userData))) = value; -} - -void LLFloaterWater::onNormalMapPicked(LLUICtrl* ctrl, void* userData) +void LLFloaterWater::onNormalMapPicked(LLUICtrl* ctrl) { LLTextureCtrl* textCtrl = static_cast(ctrl); LLUUID textID = textCtrl->getImageAssetID(); LLWaterParamManager::instance()->setNormalMapID(textID); } -void LLFloaterWater::onNewPreset(void* userData) +void LLFloaterWater::onNewPreset() { - LLNotifications::instance().add("NewWaterPreset", LLSD(), LLSD(), newPromptCallback); + LLNotifications::instance().add("NewWaterPreset", LLSD(), LLSD(), boost::bind(&LLFloaterWater::newPromptCallback, this, _1, _2)); } -void LLFloaterWater::onSavePreset(void* userData) +void LLFloaterWater::onSavePreset() { // get the name - LLComboBox* comboBox = sWaterMenu->getChild("WaterPresetsCombo"); + LLComboBox* comboBox = getChild("WaterPresetsCombo"); // don't save the empty name if(comboBox->getSelectedItemLabel() == "") @@ -619,7 +556,7 @@ void LLFloaterWater::onSavePreset(void* userData) return; } - LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), saveAlertCallback); + LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterWater::saveAlertCallback, this, _1, _2)); } bool LLFloaterWater::saveAlertCallback(const LLSD& notification, const LLSD& response) @@ -640,9 +577,9 @@ bool LLFloaterWater::saveAlertCallback(const LLSD& notification, const LLSD& res return false; } -void LLFloaterWater::onDeletePreset(void* userData) +void LLFloaterWater::onDeletePreset() { - LLComboBox* combo_box = sWaterMenu->getChild("WaterPresetsCombo"); + LLComboBox* combo_box = getChild("WaterPresetsCombo"); if(combo_box->getSelectedValue().asString() == "") { @@ -651,7 +588,7 @@ void LLFloaterWater::onDeletePreset(void* userData) LLSD args; args["SKY"] = combo_box->getSelectedValue().asString(); - LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), deleteAlertCallback); + LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), boost::bind(&LLFloaterWater::deleteAlertCallback, this, _1, _2)); } bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& response) @@ -660,14 +597,13 @@ bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& r // if they choose delete, do it. Otherwise, don't do anything if(option == 0) { - LLComboBox* combo_box = sWaterMenu->getChild("WaterPresetsCombo"); - LLFloaterDayCycle* day_cycle = NULL; + LLComboBox* combo_box = getChild("WaterPresetsCombo"); + LLFloaterDayCycle* day_cycle = LLFloaterReg::findTypedInstance("env_day_cycle"); LLComboBox* key_combo = NULL; LLMultiSliderCtrl* mult_sldr = NULL; - if(LLFloaterDayCycle::isOpen()) + if (day_cycle) { - day_cycle = LLFloaterDayCycle::instance(); key_combo = day_cycle->getChild("WaterKeyPresets"); mult_sldr = day_cycle->getChild("WaterDayCycleKeys"); } @@ -712,17 +648,13 @@ bool LLFloaterWater::deleteAlertCallback(const LLSD& notification, const LLSD& r } -void LLFloaterWater::onChangePresetName(LLUICtrl* ctrl, void * userData) +void LLFloaterWater::onChangePresetName(LLUICtrl* ctrl) { - LLComboBox * combo_box = static_cast(ctrl); - - if(combo_box->getSimple() == "") + std::string data = ctrl->getValue().asString(); + if(!data.empty()) { - return; + LLWaterParamManager::instance()->loadPreset(data); + syncMenu(); } - - LLWaterParamManager::instance()->loadPreset( - combo_box->getSelectedValue().asString()); - sWaterMenu->syncMenu(); } diff --git a/indra/newview/llfloaterwater.h b/indra/newview/llfloaterwater.h index 774d5c5a75..08c630c69e 100644 --- a/indra/newview/llfloaterwater.h +++ b/indra/newview/llfloaterwater.h @@ -42,91 +42,74 @@ #include #include "llwlparamset.h" +struct WaterVector2Control; +struct WaterVector3Control; struct WaterColorControl; -struct WaterloatControl; - +struct WaterFloatControl; +struct WaterExpFloatControl; /// Menuing system for all of windlight's functionality class LLFloaterWater : public LLFloater { public: - LLFloaterWater(); + LLFloaterWater(const LLSD& key); virtual ~LLFloaterWater(); - + /*virtual*/ BOOL postBuild(); /// initialize all void initCallbacks(void); - /// one and one instance only - static LLFloaterWater* instance(); - // help button stuff - static void onClickHelp(void* data); + void onClickHelp(std::string xml_alert); void initHelpBtn(const std::string& name, const std::string& xml_alert); - static bool newPromptCallback(const LLSD& notification, const LLSD& response); + bool newPromptCallback(const LLSD& notification, const LLSD& response); /// general purpose callbacks for dealing with color controllers - static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlGMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlBMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlAMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlIMoved(LLUICtrl* ctrl, void* userData); + void onColorControlRMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); + void onColorControlGMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); + void onColorControlBMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); + void onColorControlAMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); + void onColorControlIMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); - static void onVector3ControlXMoved(LLUICtrl* ctrl, void* userData); - static void onVector3ControlYMoved(LLUICtrl* ctrl, void* userData); - static void onVector3ControlZMoved(LLUICtrl* ctrl, void* userData); + void onVector3ControlXMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl); + void onVector3ControlYMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl); + void onVector3ControlZMoved(LLUICtrl* ctrl, WaterVector3Control* vectorControl); - static void onVector2ControlXMoved(LLUICtrl* ctrl, void* userData); - static void onVector2ControlYMoved(LLUICtrl* ctrl, void* userData); + void onVector2ControlXMoved(LLUICtrl* ctrl, WaterVector2Control* vectorControl); + void onVector2ControlYMoved(LLUICtrl* ctrl, WaterVector2Control* vectorControl); + + void onFloatControlMoved(LLUICtrl* ctrl, WaterFloatControl* floatControl); - static void onFloatControlMoved(LLUICtrl* ctrl, void* userData); + void onExpFloatControlMoved(LLUICtrl* ctrl, WaterExpFloatControl* expFloatControl); - static void onExpFloatControlMoved(LLUICtrl* ctrl, void* userData); - - static void onWaterFogColorMoved(LLUICtrl* ctrl, void* userData); - - static void onBoolToggle(LLUICtrl* ctrl, void* userData); + void onWaterFogColorMoved(LLUICtrl* ctrl, WaterColorControl* colorControl); /// handle if they choose a new normal map - static void onNormalMapPicked(LLUICtrl* ctrl, void* userData); + void onNormalMapPicked(LLUICtrl* ctrl); /// when user hits the load preset button - static void onNewPreset(void* userData); + void onNewPreset(); /// when user hits the save preset button - static void onSavePreset(void* userData); + void onSavePreset(); /// prompts a user when overwriting a preset - static bool saveAlertCallback(const LLSD& notification, const LLSD& response); + bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// when user hits the save preset button - static void onDeletePreset(void* userData); + void onDeletePreset(); /// prompts a user when overwriting a preset - static bool deleteAlertCallback(const LLSD& notification, const LLSD& response); + bool deleteAlertCallback(const LLSD& notification, const LLSD& response); /// what to do when you change the preset name - static void onChangePresetName(LLUICtrl* ctrl, void* userData); - - //// menu management - - /// show off our menu - static void show(); - - /// return if the menu exists or not - static bool isOpen(); - - /// stuff to do on exit - virtual void onClose(bool app_quitting); + void onChangePresetName(LLUICtrl* ctrl); /// sync up sliders with parameters void syncMenu(); private: - // one instance on the inside - static LLFloaterWater* sWaterMenu; - static std::set sDefaultPresets; }; diff --git a/indra/newview/llfloaterwindlight.cpp b/indra/newview/llfloaterwindlight.cpp index 98b315795a..18745284cb 100644 --- a/indra/newview/llfloaterwindlight.cpp +++ b/indra/newview/llfloaterwindlight.cpp @@ -37,6 +37,7 @@ #include "pipeline.h" #include "llsky.h" +#include "llfloaterreg.h" #include "llsliderctrl.h" #include "llmultislider.h" #include "llmultisliderctrl.h" @@ -61,21 +62,39 @@ #undef max -LLFloaterWindLight* LLFloaterWindLight::sWindLight = NULL; - std::set LLFloaterWindLight::sDefaultPresets; static const F32 WL_SUN_AMBIENT_SLIDER_SCALE = 3.0f; -LLFloaterWindLight::LLFloaterWindLight() : LLFloater(std::string("windlight floater")) +LLFloaterWindLight::LLFloaterWindLight(const LLSD& key) + : LLFloater(key) { - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_windlight_options.xml"); - + //LLUICtrlFactory::getInstance()->buildFloater(this, "floater_windlight_options.xml"); +} + +LLFloaterWindLight::~LLFloaterWindLight() +{ +} + +BOOL LLFloaterWindLight::postBuild() +{ + // add the list of presets + std::string def_days = getString("WLDefaultSkyNames"); + + // no editing or deleting of the blank string + sDefaultPresets.insert(""); + boost_tokenizer tokens(def_days, boost::char_separator(":")); + for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + std::string tok(*token_iter); + sDefaultPresets.insert(tok); + } + // add the combo boxes LLComboBox* comboBox = getChild("WLPresetsCombo"); if(comboBox != NULL) { - + std::map::iterator mIt = LLWLParamManager::instance()->mParamList.begin(); for(; mIt != LLWLParamManager::instance()->mParamList.end(); mIt++) @@ -89,27 +108,13 @@ LLFloaterWindLight::LLFloaterWindLight() : LLFloater(std::string("windlight floa // set defaults on combo boxes comboBox->selectByValue(LLSD("Default")); } - - // add the list of presets - std::string def_days = getString("WLDefaultSkyNames"); - - // no editing or deleting of the blank string - sDefaultPresets.insert(""); - boost_tokenizer tokens(def_days, boost::char_separator(":")); - for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - std::string tok(*token_iter); - sDefaultPresets.insert(tok); - } - // load it up initCallbacks(); -} -LLFloaterWindLight::~LLFloaterWindLight() -{ + syncMenu(); + + return TRUE; } - void LLFloaterWindLight::initCallbacks(void) { // help buttons @@ -145,102 +150,99 @@ void LLFloaterWindLight::initCallbacks(void) { LLWLParamManager * param_mgr = LLWLParamManager::instance(); // blue horizon - childSetCommitCallback("WLBlueHorizonR", onColorControlRMoved, ¶m_mgr->mBlueHorizon); - childSetCommitCallback("WLBlueHorizonG", onColorControlGMoved, ¶m_mgr->mBlueHorizon); - childSetCommitCallback("WLBlueHorizonB", onColorControlBMoved, ¶m_mgr->mBlueHorizon); - childSetCommitCallback("WLBlueHorizonI", onColorControlIMoved, ¶m_mgr->mBlueHorizon); + getChild("WLBlueHorizonR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mBlueHorizon)); + getChild("WLBlueHorizonG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mBlueHorizon)); + getChild("WLBlueHorizonB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mBlueHorizon)); + getChild("WLBlueHorizonI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, ¶m_mgr->mBlueHorizon)); // haze density, horizon, mult, and altitude - childSetCommitCallback("WLHazeDensity", onColorControlRMoved, ¶m_mgr->mHazeDensity); - childSetCommitCallback("WLHazeHorizon", onColorControlRMoved, ¶m_mgr->mHazeHorizon); - childSetCommitCallback("WLDensityMult", onFloatControlMoved, ¶m_mgr->mDensityMult); - childSetCommitCallback("WLMaxAltitude", onFloatControlMoved, ¶m_mgr->mMaxAlt); + getChild("WLHazeDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mHazeDensity)); + getChild("WLHazeHorizon")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mHazeHorizon)); + getChild("WLDensityMult")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mDensityMult)); + getChild("WLMaxAltitude")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mMaxAlt)); // blue density - childSetCommitCallback("WLBlueDensityR", onColorControlRMoved, ¶m_mgr->mBlueDensity); - childSetCommitCallback("WLBlueDensityG", onColorControlGMoved, ¶m_mgr->mBlueDensity); - childSetCommitCallback("WLBlueDensityB", onColorControlBMoved, ¶m_mgr->mBlueDensity); - childSetCommitCallback("WLBlueDensityI", onColorControlIMoved, ¶m_mgr->mBlueDensity); + getChild("WLBlueDensityR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mBlueDensity)); + getChild("WLBlueDensityG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mBlueDensity)); + getChild("WLBlueDensityB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mBlueDensity)); + getChild("WLBlueDensityI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, ¶m_mgr->mBlueDensity)); // Lighting // sunlight - childSetCommitCallback("WLSunlightR", onColorControlRMoved, ¶m_mgr->mSunlight); - childSetCommitCallback("WLSunlightG", onColorControlGMoved, ¶m_mgr->mSunlight); - childSetCommitCallback("WLSunlightB", onColorControlBMoved, ¶m_mgr->mSunlight); - childSetCommitCallback("WLSunlightI", onColorControlIMoved, ¶m_mgr->mSunlight); + getChild("WLSunlightR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mSunlight)); + getChild("WLSunlightG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mSunlight)); + getChild("WLSunlightB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mSunlight)); + getChild("WLSunlightI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, ¶m_mgr->mSunlight)); // glow - childSetCommitCallback("WLGlowR", onGlowRMoved, ¶m_mgr->mGlow); - childSetCommitCallback("WLGlowB", onGlowBMoved, ¶m_mgr->mGlow); + getChild("WLGlowR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onGlowRMoved, this, _1, ¶m_mgr->mGlow)); + getChild("WLGlowB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onGlowBMoved, this, _1, ¶m_mgr->mGlow)); // ambient - childSetCommitCallback("WLAmbientR", onColorControlRMoved, ¶m_mgr->mAmbient); - childSetCommitCallback("WLAmbientG", onColorControlGMoved, ¶m_mgr->mAmbient); - childSetCommitCallback("WLAmbientB", onColorControlBMoved, ¶m_mgr->mAmbient); - childSetCommitCallback("WLAmbientI", onColorControlIMoved, ¶m_mgr->mAmbient); + getChild("WLAmbientR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mAmbient)); + getChild("WLAmbientG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mAmbient)); + getChild("WLAmbientB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mAmbient)); + getChild("WLAmbientI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, ¶m_mgr->mAmbient)); // time of day - childSetCommitCallback("WLSunAngle", onSunMoved, ¶m_mgr->mLightnorm); - childSetCommitCallback("WLEastAngle", onSunMoved, ¶m_mgr->mLightnorm); + getChild("WLSunAngle")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSunMoved, this, _1, ¶m_mgr->mLightnorm)); + getChild("WLEastAngle")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSunMoved, this, _1, ¶m_mgr->mLightnorm)); // Clouds // Cloud Color - childSetCommitCallback("WLCloudColorR", onColorControlRMoved, ¶m_mgr->mCloudColor); - childSetCommitCallback("WLCloudColorG", onColorControlGMoved, ¶m_mgr->mCloudColor); - childSetCommitCallback("WLCloudColorB", onColorControlBMoved, ¶m_mgr->mCloudColor); - childSetCommitCallback("WLCloudColorI", onColorControlIMoved, ¶m_mgr->mCloudColor); + getChild("WLCloudColorR")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mCloudColor)); + getChild("WLCloudColorG")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mCloudColor)); + getChild("WLCloudColorB")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mCloudColor)); + getChild("WLCloudColorI")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlIMoved, this, _1, ¶m_mgr->mCloudColor)); // Cloud - childSetCommitCallback("WLCloudX", onColorControlRMoved, ¶m_mgr->mCloudMain); - childSetCommitCallback("WLCloudY", onColorControlGMoved, ¶m_mgr->mCloudMain); - childSetCommitCallback("WLCloudDensity", onColorControlBMoved, ¶m_mgr->mCloudMain); + getChild("WLCloudX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mCloudMain)); + getChild("WLCloudY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mCloudMain)); + getChild("WLCloudDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mCloudMain)); // Cloud Detail - childSetCommitCallback("WLCloudDetailX", onColorControlRMoved, ¶m_mgr->mCloudDetail); - childSetCommitCallback("WLCloudDetailY", onColorControlGMoved, ¶m_mgr->mCloudDetail); - childSetCommitCallback("WLCloudDetailDensity", onColorControlBMoved, ¶m_mgr->mCloudDetail); + getChild("WLCloudDetailX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlRMoved, this, _1, ¶m_mgr->mCloudDetail)); + getChild("WLCloudDetailY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlGMoved, this, _1, ¶m_mgr->mCloudDetail)); + getChild("WLCloudDetailDensity")->setCommitCallback(boost::bind(&LLFloaterWindLight::onColorControlBMoved, this, _1, ¶m_mgr->mCloudDetail)); // Cloud extras - childSetCommitCallback("WLCloudCoverage", onFloatControlMoved, ¶m_mgr->mCloudCoverage); - childSetCommitCallback("WLCloudScale", onFloatControlMoved, ¶m_mgr->mCloudScale); - childSetCommitCallback("WLCloudLockX", onCloudScrollXToggled, NULL); - childSetCommitCallback("WLCloudLockY", onCloudScrollYToggled, NULL); - childSetCommitCallback("WLCloudScrollX", onCloudScrollXMoved, NULL); - childSetCommitCallback("WLCloudScrollY", onCloudScrollYMoved, NULL); - childSetCommitCallback("WLDistanceMult", onFloatControlMoved, ¶m_mgr->mDistanceMult); - childSetCommitCallback("DrawClassicClouds", LLSavedSettingsGlue::setBOOL, (void*)"SkyUseClassicClouds"); + getChild("WLCloudCoverage")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mCloudCoverage)); + getChild("WLCloudScale")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mCloudScale)); + getChild("WLCloudLockX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollXToggled, this, _1)); + getChild("WLCloudLockY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollYToggled, this, _1)); + getChild("WLCloudScrollX")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollXMoved, this, _1)); + getChild("WLCloudScrollY")->setCommitCallback(boost::bind(&LLFloaterWindLight::onCloudScrollYMoved, this, _1)); + getChild("WLDistanceMult")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mDistanceMult)); + getChild("DrawClassicClouds")->setCommitCallback(boost::bind(LLSavedSettingsGlue::setBOOL, _1, "SkyUseClassicClouds")); // WL Top - childSetAction("WLDayCycleMenuButton", onOpenDayCycle, NULL); + getChild("WLDayCycleMenuButton")->setCommitCallback(boost::bind(&LLFloaterWindLight::onOpenDayCycle, this)); // Load/save LLComboBox* comboBox = getChild("WLPresetsCombo"); //childSetAction("WLLoadPreset", onLoadPreset, comboBox); - childSetAction("WLNewPreset", onNewPreset, comboBox); - childSetAction("WLSavePreset", onSavePreset, comboBox); - childSetAction("WLDeletePreset", onDeletePreset, comboBox); + getChild("WLNewPreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onNewPreset, this)); + getChild("WLSavePreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onSavePreset, this)); + getChild("WLDeletePreset")->setCommitCallback(boost::bind(&LLFloaterWindLight::onDeletePreset, this)); - comboBox->setCommitCallback(onChangePresetName); + comboBox->setCommitCallback(boost::bind(&LLFloaterWindLight::onChangePresetName, this, _1)); // Dome - childSetCommitCallback("WLGamma", onFloatControlMoved, ¶m_mgr->mWLGamma); - childSetCommitCallback("WLStarAlpha", onStarAlphaMoved, NULL); + getChild("WLGamma")->setCommitCallback(boost::bind(&LLFloaterWindLight::onFloatControlMoved, this, _1, ¶m_mgr->mWLGamma)); + getChild("WLStarAlpha")->setCommitCallback(boost::bind(&LLFloaterWindLight::onStarAlphaMoved, this, _1)); } -void LLFloaterWindLight::onClickHelp(void* data) +void LLFloaterWindLight::onClickHelp(std::string xml_alert) { - LLFloaterWindLight* self = LLFloaterWindLight::instance(); - - const std::string xml_alert = *(std::string*)data; - LLNotifications::instance().add(self->contextualNotification(xml_alert)); + LLNotifications::instance().add(contextualNotification(xml_alert)); } void LLFloaterWindLight::initHelpBtn(const std::string& name, const std::string& xml_alert) { - childSetAction(name, onClickHelp, new std::string(xml_alert)); + getChild(name)->setClickedCallback(boost::bind(&LLFloaterWindLight::onClickHelp, this, xml_alert)); } bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD& response) @@ -254,16 +256,13 @@ bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD& } if(option == 0) { - LLComboBox* comboBox = sWindLight->getChild( - "WLPresetsCombo"); + LLComboBox* comboBox = getChild("WLPresetsCombo"); - LLFloaterDayCycle* sDayCycle = NULL; + LLFloaterDayCycle* day_cycle = LLFloaterReg::findTypedInstance("env_day_cycle"); LLComboBox* keyCombo = NULL; - if(LLFloaterDayCycle::isOpen()) + if(day_cycle) { - sDayCycle = LLFloaterDayCycle::instance(); - keyCombo = sDayCycle->getChild( - "WLKeyPresets"); + keyCombo = day_cycle->getChild("WLKeyPresets"); } // add the current parameters to the list @@ -288,7 +287,7 @@ bool LLFloaterWindLight::newPromptCallback(const LLSD& notification, const LLSD& comboBox->add(LLStringUtil::null); comboBox->setSelectedByValue(text, true); - if(LLFloaterDayCycle::isOpen()) + if(keyCombo) { keyCombo->add(text); keyCombo->sortByName(); @@ -438,53 +437,12 @@ void LLFloaterWindLight::syncMenu() } -// static -LLFloaterWindLight* LLFloaterWindLight::instance() -{ - if (!sWindLight) - { - sWindLight = new LLFloaterWindLight(); - sWindLight->open(); - sWindLight->setFocus(TRUE); - } - return sWindLight; -} -void LLFloaterWindLight::show() -{ - LLFloaterWindLight* windLight = instance(); - windLight->syncMenu(); - - // comment in if you want the menu to rebuild each time - //LLUICtrlFactory::getInstance()->buildFloater(windLight, "floater_windlight_options.xml"); - //windLight->initCallbacks(); - - windLight->open(); -} - -bool LLFloaterWindLight::isOpen() -{ - if (sWindLight != NULL) { - return true; - } - return false; -} - -// virtual -void LLFloaterWindLight::onClose(bool app_quitting) -{ - if (sWindLight) - { - sWindLight->setVisible(FALSE); - } -} - // color control callbacks -void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); colorControl->r = sldrCtrl->getValueF32(); if(colorControl->isSunOrAmbientColor) { @@ -502,11 +460,11 @@ void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userData) name.append("I"); if(colorControl->isSunOrAmbientColor) { - sWindLight->childSetValue(name, colorControl->r / 3); + childSetValue(name, colorControl->r / 3); } else if(colorControl->isBlueHorizonOrDensity) { - sWindLight->childSetValue(name, colorControl->r / 2); + childSetValue(name, colorControl->r / 2); } else { - sWindLight->childSetValue(name, colorControl->r); + childSetValue(name, colorControl->r); } } @@ -515,12 +473,11 @@ void LLFloaterWindLight::onColorControlRMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->propagateParameters(); } -void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); colorControl->g = sldrCtrl->getValueF32(); if(colorControl->isSunOrAmbientColor) { @@ -538,11 +495,11 @@ void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, void* userData) name.append("I"); if(colorControl->isSunOrAmbientColor) { - sWindLight->childSetValue(name, colorControl->g / 3); + childSetValue(name, colorControl->g / 3); } else if(colorControl->isBlueHorizonOrDensity) { - sWindLight->childSetValue(name, colorControl->g / 2); + childSetValue(name, colorControl->g / 2); } else { - sWindLight->childSetValue(name, colorControl->g); + childSetValue(name, colorControl->g); } } @@ -551,12 +508,11 @@ void LLFloaterWindLight::onColorControlGMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->propagateParameters(); } -void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); colorControl->b = sldrCtrl->getValueF32(); if(colorControl->isSunOrAmbientColor) { @@ -574,11 +530,11 @@ void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, void* userData) name.append("I"); if(colorControl->isSunOrAmbientColor) { - sWindLight->childSetValue(name, colorControl->b / 3); + childSetValue(name, colorControl->b / 3); } else if(colorControl->isBlueHorizonOrDensity) { - sWindLight->childSetValue(name, colorControl->b / 2); + childSetValue(name, colorControl->b / 2); } else { - sWindLight->childSetValue(name, colorControl->b); + childSetValue(name, colorControl->b); } } @@ -587,12 +543,11 @@ void LLFloaterWindLight::onColorControlBMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->propagateParameters(); } -void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); colorControl->i = sldrCtrl->getValueF32(); @@ -649,24 +604,24 @@ void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, void* userData) // divide sun color vals by three if(colorControl->isSunOrAmbientColor) { - sWindLight->childSetValue(rName, colorControl->r/3); - sWindLight->childSetValue(gName, colorControl->g/3); - sWindLight->childSetValue(bName, colorControl->b/3); + childSetValue(rName, colorControl->r/3); + childSetValue(gName, colorControl->g/3); + childSetValue(bName, colorControl->b/3); } else if(colorControl->isBlueHorizonOrDensity) { - sWindLight->childSetValue(rName, colorControl->r/2); - sWindLight->childSetValue(gName, colorControl->g/2); - sWindLight->childSetValue(bName, colorControl->b/2); + childSetValue(rName, colorControl->r/2); + childSetValue(gName, colorControl->g/2); + childSetValue(bName, colorControl->b/2); } else { // set the sliders to the new vals - sWindLight->childSetValue(rName, colorControl->r); - sWindLight->childSetValue(gName, colorControl->g); - sWindLight->childSetValue(bName, colorControl->b); + childSetValue(rName, colorControl->r); + childSetValue(gName, colorControl->g); + childSetValue(bName, colorControl->b); } } @@ -676,12 +631,11 @@ void LLFloaterWindLight::onColorControlIMoved(LLUICtrl* ctrl, void* userData) } /// GLOW SPECIFIC CODE -void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); // scaled by 20 colorControl->r = (2 - sldrCtrl->getValueF32()) * 20; @@ -691,12 +645,11 @@ void LLFloaterWindLight::onGlowRMoved(LLUICtrl* ctrl, void* userData) } /// \NOTE that we want NEGATIVE (-) B -void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLColorControl * colorControl = static_cast(userData); /// \NOTE that we want NEGATIVE (-) B and NOT by 20 as 20 is too big colorControl->b = -sldrCtrl->getValueF32() * 5; @@ -705,12 +658,11 @@ void LLFloaterWindLight::onGlowBMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->propagateParameters(); } -void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, WLFloatControl* floatControl) { deactivateAnimator(); LLSliderCtrl* sldrCtrl = static_cast(ctrl); - WLFloatControl * floatControl = static_cast(userData); floatControl->x = sldrCtrl->getValueF32() / floatControl->mult; @@ -718,29 +670,16 @@ void LLFloaterWindLight::onFloatControlMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->propagateParameters(); } -void LLFloaterWindLight::onBoolToggle(LLUICtrl* ctrl, void* userData) -{ - deactivateAnimator(); - - LLCheckBoxCtrl* cbCtrl = static_cast(ctrl); - - bool value = cbCtrl->get(); - (*(static_cast(userData))) = value; -} - - // Lighting callbacks // time of day -void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, WLColorControl* colorControl) { deactivateAnimator(); - LLSliderCtrl* sunSldr = sWindLight->getChild("WLSunAngle"); - LLSliderCtrl* eastSldr = sWindLight->getChild("WLEastAngle"); + LLSliderCtrl* sunSldr = getChild("WLSunAngle"); + LLSliderCtrl* eastSldr = getChild("WLEastAngle"); - WLColorControl * colorControl = static_cast(userData); - // get the two angles LLWLParamManager * param_mgr = LLWLParamManager::instance(); @@ -759,18 +698,7 @@ void LLFloaterWindLight::onSunMoved(LLUICtrl* ctrl, void* userData) param_mgr->propagateParameters(); } -void LLFloaterWindLight::onFloatTweakMoved(LLUICtrl* ctrl, void* userData) -{ - deactivateAnimator(); - - LLSliderCtrl* sldrCtrl = static_cast(ctrl); - F32 * tweak = static_cast(userData); - - (*tweak) = sldrCtrl->getValueF32(); - LLWLParamManager::instance()->propagateParameters(); -} - -void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl) { deactivateAnimator(); @@ -779,15 +707,15 @@ void LLFloaterWindLight::onStarAlphaMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams.setStarBrightness(sldrCtrl->getValueF32()); } -void LLFloaterWindLight::onNewPreset(void* userData) +void LLFloaterWindLight::onNewPreset() { - LLNotifications::instance().add("NewSkyPreset", LLSD(), LLSD(), newPromptCallback); + LLNotifications::instance().add("NewSkyPreset", LLSD(), LLSD(), boost::bind(&LLFloaterWindLight::newPromptCallback, this, _1, _2)); } -void LLFloaterWindLight::onSavePreset(void* userData) +void LLFloaterWindLight::onSavePreset() { // get the name - LLComboBox* comboBox = sWindLight->getChild( + LLComboBox* comboBox = getChild( "WLPresetsCombo"); // don't save the empty name @@ -808,7 +736,7 @@ void LLFloaterWindLight::onSavePreset(void* userData) LLWLParamManager::instance()->mCurParams.mName = comboBox->getSelectedItemLabel(); - LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), saveAlertCallback); + LLNotifications::instance().add("WLSavePresetAlert", LLSD(), LLSD(), boost::bind(&LLFloaterWindLight::saveAlertCallback, this, _1, _2)); } bool LLFloaterWindLight::saveAlertCallback(const LLSD& notification, const LLSD& response) @@ -827,9 +755,9 @@ bool LLFloaterWindLight::saveAlertCallback(const LLSD& notification, const LLSD& return false; } -void LLFloaterWindLight::onDeletePreset(void* userData) +void LLFloaterWindLight::onDeletePreset() { - LLComboBox* combo_box = sWindLight->getChild( + LLComboBox* combo_box = getChild( "WLPresetsCombo"); if(combo_box->getSelectedValue().asString() == "") @@ -840,7 +768,7 @@ void LLFloaterWindLight::onDeletePreset(void* userData) LLSD args; args["SKY"] = combo_box->getSelectedValue().asString(); LLNotifications::instance().add("WLDeletePresetAlert", args, LLSD(), - boost::bind(&LLFloaterWindLight::deleteAlertCallback, sWindLight, _1, _2)); + boost::bind(&LLFloaterWindLight::deleteAlertCallback, this, _1, _2)); } bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLSD& response) @@ -850,17 +778,14 @@ bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLS // if they choose delete, do it. Otherwise, don't do anything if(option == 0) { - LLComboBox* combo_box = getChild( - "WLPresetsCombo"); - LLFloaterDayCycle* day_cycle = NULL; + LLComboBox* combo_box = getChild("WLPresetsCombo"); + LLFloaterDayCycle* day_cycle = LLFloaterReg::findTypedInstance("env_day_cycle"); LLComboBox* key_combo = NULL; LLMultiSliderCtrl* mult_sldr = NULL; - if(LLFloaterDayCycle::isOpen()) + if (day_cycle) { - day_cycle = LLFloaterDayCycle::instance(); - key_combo = day_cycle->getChild( - "WLKeyPresets"); + key_combo = day_cycle->getChild("WLKeyPresets"); mult_sldr = day_cycle->getChild("WLDayCycleKeys"); } @@ -903,29 +828,25 @@ bool LLFloaterWindLight::deleteAlertCallback(const LLSD& notification, const LLS } -void LLFloaterWindLight::onChangePresetName(LLUICtrl* ctrl, void * userData) +void LLFloaterWindLight::onChangePresetName(LLUICtrl* ctrl) { deactivateAnimator(); - LLComboBox * combo_box = static_cast(ctrl); - - if(combo_box->getSimple() == "") + std::string data = ctrl->getValue().asString(); + if(!data.empty()) { - return; + LLWLParamManager::instance()->loadPreset( data); + syncMenu(); } - - LLWLParamManager::instance()->loadPreset( - combo_box->getSelectedValue().asString()); - sWindLight->syncMenu(); } -void LLFloaterWindLight::onOpenDayCycle(void* userData) +void LLFloaterWindLight::onOpenDayCycle() { - LLFloaterDayCycle::show(); + LLFloaterReg::showInstance("env_day_cycle"); } // Clouds -void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl) { deactivateAnimator(); @@ -934,7 +855,7 @@ void LLFloaterWindLight::onCloudScrollXMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams.setCloudScrollX(sldrCtrl->getValueF32() + 10.0f); } -void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl) { deactivateAnimator(); @@ -944,7 +865,7 @@ void LLFloaterWindLight::onCloudScrollYMoved(LLUICtrl* ctrl, void* userData) LLWLParamManager::instance()->mCurParams.setCloudScrollY(sldrCtrl->getValueF32() + 10.0f); } -void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl) { deactivateAnimator(); @@ -953,7 +874,7 @@ void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData) bool lock = cbCtrl->get(); LLWLParamManager::instance()->mCurParams.setEnableCloudScrollX(!lock); - LLSliderCtrl* sldr = sWindLight->getChild( + LLSliderCtrl* sldr = getChild( "WLCloudScrollX"); if(cbCtrl->get()) @@ -967,7 +888,7 @@ void LLFloaterWindLight::onCloudScrollXToggled(LLUICtrl* ctrl, void* userData) } -void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl, void* userData) +void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl) { deactivateAnimator(); @@ -975,7 +896,7 @@ void LLFloaterWindLight::onCloudScrollYToggled(LLUICtrl* ctrl, void* userData) bool lock = cbCtrl->get(); LLWLParamManager::instance()->mCurParams.setEnableCloudScrollY(!lock); - LLSliderCtrl* sldr = sWindLight->getChild( + LLSliderCtrl* sldr = getChild( "WLCloudScrollY"); if(cbCtrl->get()) diff --git a/indra/newview/llfloaterwindlight.h b/indra/newview/llfloaterwindlight.h index 3447caa923..56c2c6623b 100644 --- a/indra/newview/llfloaterwindlight.h +++ b/indra/newview/llfloaterwindlight.h @@ -51,80 +51,62 @@ class LLFloaterWindLight : public LLFloater { public: - LLFloaterWindLight(); + LLFloaterWindLight(const LLSD& key); virtual ~LLFloaterWindLight(); - + /*virtual*/ BOOL postBuild(); /// initialize all void initCallbacks(void); - /// one and one instance only - static LLFloaterWindLight* instance(); - // help button stuff - static void onClickHelp(void* data); + void onClickHelp(std::string alert); void initHelpBtn(const std::string& name, const std::string& xml_alert); - static bool newPromptCallback(const LLSD& notification, const LLSD& response); + bool newPromptCallback(const LLSD& notification, const LLSD& response); /// general purpose callbacks for dealing with color controllers - static void onColorControlRMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlGMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlBMoved(LLUICtrl* ctrl, void* userData); - static void onColorControlIMoved(LLUICtrl* ctrl, void* userData); - static void onFloatControlMoved(LLUICtrl* ctrl, void* userData); - static void onBoolToggle(LLUICtrl* ctrl, void* userData); + void onColorControlRMoved(LLUICtrl* ctrl, WLColorControl* userData); + void onColorControlGMoved(LLUICtrl* ctrl, WLColorControl* userData); + void onColorControlBMoved(LLUICtrl* ctrl, WLColorControl* userData); + void onColorControlIMoved(LLUICtrl* ctrl, WLColorControl* userData); + void onFloatControlMoved(LLUICtrl* ctrl, WLFloatControl* userData); /// lighting callbacks for glow - static void onGlowRMoved(LLUICtrl* ctrl, void* userData); + void onGlowRMoved(LLUICtrl* ctrl, WLColorControl* userData); //static void onGlowGMoved(LLUICtrl* ctrl, void* userData); - static void onGlowBMoved(LLUICtrl* ctrl, void* userData); + void onGlowBMoved(LLUICtrl* ctrl, WLColorControl* userData); /// lighting callbacks for sun - static void onSunMoved(LLUICtrl* ctrl, void* userData); - - /// handle if float is changed - static void onFloatTweakMoved(LLUICtrl* ctrl, void* userData); + void onSunMoved(LLUICtrl* ctrl, WLColorControl* userData); /// for handling when the star slider is moved to adjust the alpha - static void onStarAlphaMoved(LLUICtrl* ctrl, void* userData); + void onStarAlphaMoved(LLUICtrl* ctrl); /// when user hits the load preset button - static void onNewPreset(void* userData); + void onNewPreset(); /// when user hits the save preset button - static void onSavePreset(void* userData); + void onSavePreset(); /// prompts a user when overwriting a preset - static bool saveAlertCallback(const LLSD& notification, const LLSD& response); + bool saveAlertCallback(const LLSD& notification, const LLSD& response); /// when user hits the save preset button - static void onDeletePreset(void* userData); + void onDeletePreset(); /// prompts a user when overwriting a preset bool deleteAlertCallback(const LLSD& notification, const LLSD& response); /// what to do when you change the preset name - static void onChangePresetName(LLUICtrl* ctrl, void* userData); + void onChangePresetName(LLUICtrl* ctrl); /// when user hits the save preset button - static void onOpenDayCycle(void* userData); + void onOpenDayCycle(); /// handle cloud scrolling - static void onCloudScrollXMoved(LLUICtrl* ctrl, void* userData); - static void onCloudScrollYMoved(LLUICtrl* ctrl, void* userData); - static void onCloudScrollXToggled(LLUICtrl* ctrl, void* userData); - static void onCloudScrollYToggled(LLUICtrl* ctrl, void* userData); - - //// menu management - - /// show off our menu - static void show(); - - /// return if the menu exists or not - static bool isOpen(); - - /// stuff to do on exit - virtual void onClose(bool app_quitting); + void onCloudScrollXMoved(LLUICtrl* ctrl); + void onCloudScrollYMoved(LLUICtrl* ctrl); + void onCloudScrollXToggled(LLUICtrl* ctrl); + void onCloudScrollYToggled(LLUICtrl* ctrl); /// sync up sliders with parameters void syncMenu(); @@ -133,9 +115,6 @@ public: static void deactivateAnimator(); private: - // one instance on the inside - static LLFloaterWindLight* sWindLight; - static std::set sDefaultPresets; }; diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index 8326557cf8..098a5197df 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -41,23 +41,24 @@ #include "llfloaterworldmap.h" #include "llagent.h" -#include "llviewerwindow.h" #include "llbutton.h" #include "llcallingcard.h" -#include "llcolorscheme.h" #include "llcombobox.h" #include "llviewercontrol.h" #include "lldraghandle.h" #include "llfirstuse.h" +#include "llfloaterreg.h" // getTypedInstance() #include "llfocusmgr.h" #include "lllandmarklist.h" #include "lllineeditor.h" -#include "llpreviewlandmark.h" #include "llregionhandle.h" #include "llscrolllistctrl.h" +#include "llslurl.h" +#include "lltabcontainer.h" #include "lltextbox.h" #include "lltracker.h" -#include "llurldispatcher.h" +#include "llinventorymodel.h" +#include "llviewerinventory.h" // LLViewerInventoryItem #include "llviewermenu.h" #include "llviewerregion.h" #include "llviewerstats.h" @@ -67,8 +68,10 @@ #include "llappviewer.h" #include "llmapimagetype.h" #include "llweb.h" +#include "llslider.h" #include "llglheaders.h" +#include "llwindow.h" // copyTextToClipboard() //--------------------------------------------------------------------------- // Constants @@ -84,17 +87,10 @@ enum EPanDirection }; // Values in pixels per region -static const F32 ZOOM_MIN = -8.f; // initial value, updated by adjustZoomSlider -static const F32 ZOOM_MAX = 0.f; -static const F32 ZOOM_INC = 0.2f; +static const F32 ZOOM_MAX = 128.f; -static const F32 SIM_COORD_MIN = 0.f; -static const F32 SIM_COORD_MAX = 255.f; static const F32 SIM_COORD_DEFAULT = 128.f; -static const F64 MAX_FLY_DISTANCE = 363.f; // Diagonal size of one sim. -static const F64 MAX_FLY_DISTANCE_SQUARED = MAX_FLY_DISTANCE * MAX_FLY_DISTANCE; - //--------------------------------------------------------------------------- // Globals //--------------------------------------------------------------------------- @@ -148,8 +144,8 @@ const LLUUID LLFloaterWorldMap::sHomeID( "10000000-0000-0000-0000-000000000001" //--------------------------------------------------------------------------- -LLFloaterWorldMap::LLFloaterWorldMap() -: LLFloater(std::string("worldmap")), +LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key) +: LLFloater(key), mInventory(NULL), mInventoryObserver(NULL), mFriendObserver(NULL), @@ -161,90 +157,72 @@ LLFloaterWorldMap::LLFloaterWorldMap() mTrackedLocation(0,0,0), mTrackedStatus(LLTracker::TRACKING_NOTHING) { - LLCallbackMap::map_t factory_map; - factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL); - factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL); - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", &factory_map); + gFloaterWorldMap = this; + + mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL); + mFactoryMap["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL); + + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", FALSE); + mCommitCallbackRegistrar.add("WMap.Location", boost::bind(&LLFloaterWorldMap::onLocationCommit, this)); + mCommitCallbackRegistrar.add("WMap.AvatarCombo", boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this)); + mCommitCallbackRegistrar.add("WMap.SearchResult", boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this)); + mCommitCallbackRegistrar.add("WMap.CommitLocation", boost::bind(&LLFloaterWorldMap::onCommitLocation, this)); + mCommitCallbackRegistrar.add("WMap.GoHome", boost::bind(&LLFloaterWorldMap::onGoHome, this)); + mCommitCallbackRegistrar.add("WMap.Teleport", boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); + mCommitCallbackRegistrar.add("WMap.ShowTarget", boost::bind(&LLFloaterWorldMap::onShowTargetBtn, this)); + mCommitCallbackRegistrar.add("WMap.ShowAgent", boost::bind(&LLFloaterWorldMap::onShowAgentBtn, this)); + mCommitCallbackRegistrar.add("WMap.Clear", boost::bind(&LLFloaterWorldMap::onClearBtn, this)); + mCommitCallbackRegistrar.add("WMap.CopySLURL", boost::bind(&LLFloaterWorldMap::onCopySLURL, this)); } // static void* LLFloaterWorldMap::createWorldMapView(void* data) { - return new LLWorldMapView(std::string("mapview"), LLRect(0,300,400,0)); + return new LLWorldMapView(); } BOOL LLFloaterWorldMap::postBuild() { + mCloseSignal.connect(boost::bind(&LLFloaterWorldMap::onClose, this)); + mTabs = getChild("maptab"); if (!mTabs) return FALSE; - LLPanel *panel; - - panel = mTabs->getChild("objects_mapview"); - if (panel) - { - mTabs->setTabChangeCallback(panel, onCommitBackground); - mTabs->setTabUserData(panel, this); - } - panel = mTabs->getChild("terrain_mapview"); - if (panel) - { - mTabs->setTabChangeCallback(panel, onCommitBackground); - mTabs->setTabUserData(panel, this); - } + mTabs->setCommitCallback(boost::bind(&LLFloaterWorldMap::onCommitBackground, this)); // The following callback syncs the worlmap tabs with the images. // Commented out since it was crashing when LLWorldMap became a singleton. // We should be fine without it but override the onOpen method and put it // there if it turns out to be needed. -MG // - //onCommitBackground((void*)this, false); - - childSetCommitCallback("friend combo", onAvatarComboCommit, this); + //onCommitBackground(); LLComboBox *avatar_combo = getChild("friend combo"); if (avatar_combo) { avatar_combo->selectFirstItem(); - avatar_combo->setPrearrangeCallback( onAvatarComboPrearrange ); - avatar_combo->setTextEntryCallback( onComboTextEntry ); + avatar_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onAvatarComboPrearrange, this) ); + avatar_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); } - childSetAction("DoSearch", onLocationCommit, this); - - childSetFocusChangedCallback("location", onLocationFocusChanged, this); + getChild("location")->setFocusChangedCallback(boost::bind(&LLFloaterWorldMap::onLocationFocusChanged, this, _1)); LLLineEditor *location_editor = getChild("location"); if (location_editor) { - location_editor->setKeystrokeCallback( onSearchTextEntry ); + location_editor->setKeystrokeCallback( boost::bind(&LLFloaterWorldMap::onSearchTextEntry, this, _1), NULL ); } - childSetCommitCallback("search_results", onCommitSearchResult, this); - childSetDoubleClickCallback("search_results", onClickTeleportBtn); - childSetCommitCallback("spin x", onCommitLocation, this); - childSetCommitCallback("spin y", onCommitLocation, this); - childSetCommitCallback("spin z", onCommitLocation, this); - - childSetCommitCallback("landmark combo", onLandmarkComboCommit, this); + getChild("search_results")->setDoubleClickCallback( boost::bind(&LLFloaterWorldMap::onClickTeleportBtn, this)); LLComboBox *landmark_combo = getChild( "landmark combo"); if (landmark_combo) { landmark_combo->selectFirstItem(); - landmark_combo->setPrearrangeCallback( onLandmarkComboPrearrange ); - landmark_combo->setTextEntryCallback( onComboTextEntry ); + landmark_combo->setPrearrangeCallback( boost::bind(&LLFloaterWorldMap::onLandmarkComboPrearrange, this) ); + landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) ); } - childSetAction("Go Home", onGoHome, this); - - childSetAction("Teleport", onClickTeleportBtn, this); - - childSetAction("Show Destination", onShowTargetBtn, this); - childSetAction("Show My Location", onShowAgentBtn, this); - childSetAction("Clear", onClearBtn, this); - childSetAction("copy_slurl", onCopySLURL, this); - mCurZoomVal = log(gMapScale)/log(2.f); childSetValue("zoom slider", gMapScale); @@ -267,28 +245,33 @@ LLFloaterWorldMap::~LLFloaterWorldMap() // avatar tracker will delete this for us. mFriendObserver = NULL; + + gFloaterWorldMap = NULL; } +//static +LLFloaterWorldMap* LLFloaterWorldMap::getInstance() +{ + return LLFloaterReg::getTypedInstance("world_map"); +} + +void LLFloaterWorldMap::onClose() +{ + // While we're not visible, discard the overlay images we're using + LLWorldMap::getInstance()->clearImageRefs(); +} // virtual -void LLFloaterWorldMap::onClose(bool app_quitting) +void LLFloaterWorldMap::onOpen(const LLSD& key) { - setVisible(FALSE); -} + bool center_on_target = (key.asString() == "center"); -// static -void LLFloaterWorldMap::show(void*, BOOL center_on_target) -{ - BOOL was_visible = gFloaterWorldMap->getVisible(); - - gFloaterWorldMap->mIsClosing = FALSE; - gFloaterWorldMap->open(); /* Flawfinder: ignore */ + mIsClosing = FALSE; LLWorldMapView* map_panel; - map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel(); + map_panel = (LLWorldMapView*)mTabs->getCurrentPanel(); map_panel->clearLastClick(); - if (!was_visible) { // reset pan on show, so it centers on you again if (!center_on_target) @@ -303,13 +286,13 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) // Reload any maps that may have changed LLWorldMap::getInstance()->clearSimFlags(); - const S32 panel_num = gFloaterWorldMap->mTabs->getCurrentPanelIndex(); + const S32 panel_num = mTabs->getCurrentPanelIndex(); const bool request_from_sim = true; LLWorldMap::getInstance()->setCurrentLayer(panel_num, request_from_sim); // We may already have a bounding box for the regions of the world, // so use that to adjust the view. - gFloaterWorldMap->adjustZoomSliderBounds(); + adjustZoomSliderBounds(); // Could be first show LLFirstUse::useMap(); @@ -318,19 +301,19 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) LLUUID landmark_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); gInventory.startBackgroundFetch(landmark_folder_id); - gFloaterWorldMap->childSetFocus("location", TRUE); + childSetFocus("location", TRUE); gFocusMgr.triggerFocusFlash(); - gFloaterWorldMap->buildAvatarIDList(); - gFloaterWorldMap->buildLandmarkIDLists(); + buildAvatarIDList(); + buildLandmarkIDLists(); // If nothing is being tracked, set flag so the user position will be found - gFloaterWorldMap->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); } if (center_on_target) { - gFloaterWorldMap->centerOnTarget(FALSE); + centerOnTarget(FALSE); } } @@ -345,46 +328,6 @@ void LLFloaterWorldMap::reloadIcons(void*) } -// static -void LLFloaterWorldMap::toggle(void*) -{ - BOOL visible = gFloaterWorldMap->getVisible(); - - if (!visible) - { - show(NULL, FALSE); - } - else - { - gFloaterWorldMap->mIsClosing = TRUE; - gFloaterWorldMap->close(); - } -} - - -// static -void LLFloaterWorldMap::hide(void*) -{ - gFloaterWorldMap->mIsClosing = TRUE; - gFloaterWorldMap->close(); -} - - -// virtual -void LLFloaterWorldMap::setVisible( BOOL visible ) -{ - LLFloater::setVisible( visible ); - - gSavedSettings.setBOOL( "ShowWorldMap", visible ); - - if( !visible ) - { - // While we're not visible, discard the overlay images we're using - LLWorldMap::getInstance()->clearImageRefs(); - } -} - - // virtual BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask) { @@ -428,6 +371,9 @@ void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent // virtual void LLFloaterWorldMap::draw() { + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white); + // Hide/Show Mature Events controls childSetVisible("events_mature_icon", gAgent.canAccessMature()); childSetVisible("events_mature_label", gAgent.canAccessMature()); @@ -456,25 +402,25 @@ void LLFloaterWorldMap::draw() LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); if (LLTracker::TRACKING_AVATAR == tracking_status) { - childSetColor("avatar_icon", gTrackColor); + childSetColor("avatar_icon", map_track_color); } else { - childSetColor("avatar_icon", gDisabledTrackColor); + childSetColor("avatar_icon", map_track_disabled_color); } if (LLTracker::TRACKING_LANDMARK == tracking_status) { - childSetColor("landmark_icon", gTrackColor); + childSetColor("landmark_icon", map_track_color); } else { - childSetColor("landmark_icon", gDisabledTrackColor); + childSetColor("landmark_icon", map_track_disabled_color); } if (LLTracker::TRACKING_LOCATION == tracking_status) { - childSetColor("location_icon", gTrackColor); + childSetColor("location_icon", map_track_color); } else { @@ -488,7 +434,7 @@ void LLFloaterWorldMap::draw() } else { - childSetColor("location_icon", gDisabledTrackColor); + childSetColor("location_icon", map_track_disabled_color); } } @@ -703,7 +649,7 @@ void LLFloaterWorldMap::updateLocation() childSetValue("spin z", LLSD(agent_z) ); // Set the current SLURL - mSLURL = LLURLDispatcher::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z); + mSLURL = LLSLURL::buildSLURL(agent_sim_name, agent_x, agent_y, agent_z); } } @@ -740,7 +686,7 @@ void LLFloaterWorldMap::updateLocation() // simNameFromPosGlobal can fail, so don't give the user an invalid SLURL if ( gotSimName ) { - mSLURL = LLURLDispatcher::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ])); + mSLURL = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)pos_global.mdV[VZ])); } else { // Empty SLURL will disable the "Copy SLURL to clipboard" button @@ -901,7 +847,7 @@ void LLFloaterWorldMap::buildLandmarkIDLists() LLInventoryModel::cat_array_t cats; LLInventoryModel::item_array_t items; LLIsType is_landmark(LLAssetType::AT_LANDMARK); - gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items, LLInventoryModel::EXCLUDE_TRASH, @@ -1024,10 +970,11 @@ void LLFloaterWorldMap::adjustZoomSliderBounds() // Make sure the zoom slider can be moved at least a little bit. // Likewise, less than the increment pixels per region is just silly. - pixels_per_region = llclamp(pixels_per_region, 1.f, (F32)(pow(2.f, ZOOM_MAX) * 128.f)); + pixels_per_region = llclamp(pixels_per_region, 1.f, ZOOM_MAX); F32 min_power = log(pixels_per_region/256.f)/log(2.f); - childSetMinValue("zoom slider", min_power); + + getChild("zoom slider")->setMinValue(min_power); } @@ -1035,52 +982,26 @@ void LLFloaterWorldMap::adjustZoomSliderBounds() // User interface widget callbacks //------------------------------------------------------------------------- -// static -void LLFloaterWorldMap::onPanBtn( void* userdata ) -{ - if( !gFloaterWorldMap ) return; - - EPanDirection direction = (EPanDirection)(intptr_t)userdata; - - S32 pan_x = 0; - S32 pan_y = 0; - switch( direction ) - { - case PAN_UP: pan_y = -1; break; - case PAN_DOWN: pan_y = 1; break; - case PAN_LEFT: pan_x = 1; break; - case PAN_RIGHT: pan_x = -1; break; - default: llassert(0); return; - } - - LLWorldMapView* map_panel; - map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel(); - map_panel->translatePan( pan_x, pan_y ); -} - -// static -void LLFloaterWorldMap::onGoHome(void*) +void LLFloaterWorldMap::onGoHome() { gAgent.teleportHome(); - gFloaterWorldMap->close(); + closeFloater(); } -// static -void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdata ) +void LLFloaterWorldMap::onLandmarkComboPrearrange( ) { - LLFloaterWorldMap* self = gFloaterWorldMap; - if( !self || self->mIsClosing ) + if( mIsClosing ) { return; } - LLCtrlListInterface *list = self->childGetListInterface("landmark combo"); + LLCtrlListInterface *list = childGetListInterface("landmark combo"); if (!list) return; LLUUID current_choice = list->getCurrentID(); - gFloaterWorldMap->buildLandmarkIDLists(); + buildLandmarkIDLists(); if( current_choice.isNull() || !list->setCurrentByID( current_choice ) ) { @@ -1089,7 +1010,7 @@ void LLFloaterWorldMap::onLandmarkComboPrearrange( LLUICtrl* ctrl, void* userdat } -void LLFloaterWorldMap::onComboTextEntry( LLLineEditor* ctrl, void* userdata ) +void LLFloaterWorldMap::onComboTextEntry() { // Reset the tracking whenever we start typing into any of the search fields, // so that hitting does an auto-complete versus teleporting us to the @@ -1097,24 +1018,21 @@ void LLFloaterWorldMap::onComboTextEntry( LLLineEditor* ctrl, void* userdata ) LLTracker::clearFocus(); } -// static -void LLFloaterWorldMap::onSearchTextEntry( LLLineEditor* ctrl, void* userdata ) +void LLFloaterWorldMap::onSearchTextEntry( LLLineEditor* ctrl ) { - onComboTextEntry(ctrl, userdata); - updateSearchEnabled(ctrl, userdata); + onComboTextEntry(); + updateSearchEnabled(); } -// static -void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata ) -{ - LLFloaterWorldMap* self = gFloaterWorldMap; - if( !self || self->mIsClosing ) +void LLFloaterWorldMap::onLandmarkComboCommit() +{ + if( mIsClosing ) { return; } - LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("landmark combo"); + LLCtrlListInterface *list = childGetListInterface("landmark combo"); if (!list) return; LLUUID asset_id; @@ -1146,23 +1064,22 @@ void LLFloaterWorldMap::onLandmarkComboCommit( LLUICtrl* ctrl, void* userdata ) } } - self->trackLandmark( item_id); - onShowTargetBtn(self); + trackLandmark( item_id); + onShowTargetBtn(); // Reset to user postion if nothing is tracked - self->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); } // static -void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata ) +void LLFloaterWorldMap::onAvatarComboPrearrange( ) { - LLFloaterWorldMap* self = gFloaterWorldMap; - if( !self || self->mIsClosing ) + if( mIsClosing ) { return; } - LLCtrlListInterface *list = self->childGetListInterface("friend combo"); + LLCtrlListInterface *list = childGetListInterface("friend combo"); if (!list) return; LLUUID current_choice; @@ -1172,7 +1089,7 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata current_choice = LLAvatarTracker::instance().getAvatarID(); } - self->buildAvatarIDList(); + buildAvatarIDList(); if( !list->setCurrentByID( current_choice ) || current_choice.isNull() ) { @@ -1180,82 +1097,74 @@ void LLFloaterWorldMap::onAvatarComboPrearrange( LLUICtrl* ctrl, void* userdata } } - -// static -void LLFloaterWorldMap::onAvatarComboCommit( LLUICtrl* ctrl, void* userdata ) +void LLFloaterWorldMap::onAvatarComboCommit() { - LLFloaterWorldMap* self = gFloaterWorldMap; - if( !self || self->mIsClosing ) + if( mIsClosing ) { return; } - LLCtrlListInterface *list = gFloaterWorldMap->childGetListInterface("friend combo"); + LLCtrlListInterface *list = childGetListInterface("friend combo"); if (!list) return; const LLUUID& new_avatar_id = list->getCurrentID(); if (new_avatar_id.notNull()) { std::string name; - LLComboBox* combo = gFloaterWorldMap->getChild("friend combo"); + LLComboBox* combo = getChild("friend combo"); if (combo) name = combo->getSimple(); - self->trackAvatar(new_avatar_id, name); - onShowTargetBtn(self); + trackAvatar(new_avatar_id, name); + onShowTargetBtn(); } else { // Reset to user postion if nothing is tracked - self->mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); + mSetToUserPosition = ( LLTracker::getTrackingStatus() == LLTracker::TRACKING_NOTHING ); } } -//static -void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus, void* userdata ) +void LLFloaterWorldMap::onLocationFocusChanged( LLFocusableElement* focus ) { - updateSearchEnabled((LLUICtrl*)focus, userdata); + updateSearchEnabled(); } -// static -void LLFloaterWorldMap::updateSearchEnabled( LLUICtrl* ctrl, void* userdata ) +void LLFloaterWorldMap::updateSearchEnabled() { - LLFloaterWorldMap *self = gFloaterWorldMap; - if (self->childHasKeyboardFocus("location") && - self->childGetValue("location").asString().length() > 0) + if (childHasKeyboardFocus("location") && + childGetValue("location").asString().length() > 0) { - self->setDefaultBtn("DoSearch"); + setDefaultBtn("DoSearch"); } else { - self->setDefaultBtn(NULL); + setDefaultBtn(NULL); } } -// static -void LLFloaterWorldMap::onLocationCommit( void* userdata ) +void LLFloaterWorldMap::onLocationCommit() { - LLFloaterWorldMap *self = gFloaterWorldMap; - if( !self || self->mIsClosing ) + if( mIsClosing ) { return; } - self->clearLocationSelection(FALSE); - self->mCompletingRegionName = ""; - self->mLastRegionName = ""; + clearLocationSelection(FALSE); + mCompletingRegionName = ""; + mLastRegionName = ""; - std::string str = self->childGetValue("location").asString(); + std::string str = childGetValue("location").asString(); // Trim any leading and trailing spaces in the search target std::string saved_str = str; LLStringUtil::trim( str ); if ( str != saved_str ) { // Set the value in the UI if any spaces were removed - self->childSetValue("location", str); + childSetValue("location", str); } LLStringUtil::toLower(str); - gFloaterWorldMap->mCompletingRegionName = str; + mCompletingRegionName = str; LLWorldMap::getInstance()->mIsTrackingCommit = TRUE; - self->mExactMatch = FALSE; + mExactMatch = FALSE; if (str.length() >= 3) { LLWorldMap::getInstance()->sendNamedRegionRequest(str); @@ -1267,67 +1176,42 @@ void LLFloaterWorldMap::onLocationCommit( void* userdata ) } } - -// static -void LLFloaterWorldMap::onClearBtn(void* data) +void LLFloaterWorldMap::onClearBtn() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - self->mTrackedStatus = LLTracker::TRACKING_NOTHING; + mTrackedStatus = LLTracker::TRACKING_NOTHING; LLTracker::stopTracking((void *)(intptr_t)TRUE); LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE; - self->mSLURL = ""; // Clear the SLURL since it's invalid - self->mSetToUserPosition = TRUE; // Revert back to the current user position + mSLURL = ""; // Clear the SLURL since it's invalid + mSetToUserPosition = TRUE; // Revert back to the current user position } -// static -void LLFloaterWorldMap::onFlyBtn(void* data) +void LLFloaterWorldMap::onShowTargetBtn() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - self->fly(); + centerOnTarget(TRUE); } -void LLFloaterWorldMap::onShowTargetBtn(void* data) -{ - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - self->centerOnTarget(TRUE); -} - -void LLFloaterWorldMap::onShowAgentBtn(void* data) +void LLFloaterWorldMap::onShowAgentBtn() { LLWorldMapView::setPan( 0, 0, FALSE); // FALSE == animate - // Set flag so user's location will be displayed if not tracking anything else - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - self->mSetToUserPosition = TRUE; + mSetToUserPosition = TRUE; } -// static -void LLFloaterWorldMap::onClickTeleportBtn(void* data) +void LLFloaterWorldMap::onClickTeleportBtn() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - self->teleport(); + teleport(); } -// static -void LLFloaterWorldMap::onCopySLURL(void* data) +void LLFloaterWorldMap::onCopySLURL() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - gViewerWindow->mWindow->copyTextToClipboard(utf8str_to_wstring(self->mSLURL)); + getWindow()->copyTextToClipboard(utf8str_to_wstring(mSLURL)); LLSD args; - args["SLURL"] = self->mSLURL; + args["SLURL"] = mSLURL; LLNotifications::instance().add("CopySLURL", args); } -void LLFloaterWorldMap::onCheckEvents(LLUICtrl*, void* data) -{ - LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; - if(!self) return; - self->childSetEnabled("event_mature_chk", self->childGetValue("event_chk")); - self->childSetEnabled("event_adult_chk", self->childGetValue("event_chk")); -} - // protected void LLFloaterWorldMap::centerOnTarget(BOOL animate) { @@ -1375,7 +1259,7 @@ void LLFloaterWorldMap::fly() if (!pos_global.isExactlyZero()) { gAgent.startAutoPilotGlobal( pos_global ); - close(); + closeFloater(); } else { @@ -1447,24 +1331,6 @@ void LLFloaterWorldMap::teleport() } } -// static -void LLFloaterWorldMap::onGoToLandmarkDialog( S32 option, void* userdata ) -{ - LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata; - switch( option ) - { - case 0: - self->teleportToLandmark(); - break; - case 1: - self->flyToLandmark(); - break; - default: - // nothing - break; - } -} - void LLFloaterWorldMap::flyToLandmark() { LLVector3d destination_pos_global; @@ -1536,14 +1402,10 @@ void LLFloaterWorldMap::flyToAvatar() } } -// static -void LLFloaterWorldMap::onCommitBackground(void* userdata, bool from_click) +void LLFloaterWorldMap::onCommitBackground() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata; - // Find my index - S32 index = self->mTabs->getCurrentPanelIndex(); - + S32 index = mTabs->getCurrentPanelIndex(); LLWorldMap::getInstance()->setCurrentLayer(index); } @@ -1602,45 +1464,40 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) { mExactMatch = TRUE; childSetFocus("search_results"); - onCommitSearchResult(NULL, this); + onCommitSearchResult(); } else if (!mExactMatch && num_results > 0) { list->selectFirstItem(); // select first item by default childSetFocus("search_results"); - onCommitSearchResult(NULL, this); + onCommitSearchResult(); } else if (num_results == 0) { - list->addCommentText(std::string("None found.")); + list->setCommentText(std::string("None found.")); list->operateOnAll(LLCtrlListInterface::OP_DESELECT); } } -// static -void LLFloaterWorldMap::onCommitLocation(LLUICtrl* ctrl, void* userdata) +void LLFloaterWorldMap::onCommitLocation() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata; LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); if ( LLTracker::TRACKING_LOCATION == tracking_status) { LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); - F64 local_x = self->childGetValue("spin x"); - F64 local_y = self->childGetValue("spin y"); - F64 local_z = self->childGetValue("spin z"); + F64 local_x = childGetValue("spin x"); + F64 local_y = childGetValue("spin y"); + F64 local_z = childGetValue("spin z"); pos_global.mdV[VX] += -fmod(pos_global.mdV[VX], 256.0) + local_x; pos_global.mdV[VY] += -fmod(pos_global.mdV[VY], 256.0) + local_y; pos_global.mdV[VZ] = local_z; - self->trackLocation(pos_global); + trackLocation(pos_global); } } -// static -void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata) +void LLFloaterWorldMap::onCommitSearchResult() { - LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata; - - LLCtrlListInterface *list = self->childGetListInterface("search_results"); + LLCtrlListInterface *list = childGetListInterface("search_results"); if (!list) return; LLSD selected_value = list->getSelectedValue(); @@ -1661,19 +1518,19 @@ void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata) if (sim_name == info_sim_name) { LLVector3d pos_global = from_region_handle( info->mHandle ); - F64 local_x = self->childGetValue("spin x"); - F64 local_y = self->childGetValue("spin y"); - F64 local_z = self->childGetValue("spin z"); + F64 local_x = childGetValue("spin x"); + F64 local_y = childGetValue("spin y"); + F64 local_z = childGetValue("spin z"); pos_global.mdV[VX] += local_x; pos_global.mdV[VY] += local_y; pos_global.mdV[VZ] = local_z; - self->childSetValue("location", sim_name); - self->trackLocation(pos_global); - self->setDefaultBtn("Teleport"); + childSetValue("location", sim_name); + trackLocation(pos_global); + setDefaultBtn("Teleport"); break; } } - onShowTargetBtn(self); + onShowTargetBtn(); } diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index b0e72f298a..f117ea05af 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -49,29 +49,28 @@ class LLFriendObserver; class LLInventoryModel; class LLInventoryObserver; class LLItemInfo; +class LLLineEditor; class LLTabContainer; -class LLWorldMapView; class LLFloaterWorldMap : public LLFloater { public: - LLFloaterWorldMap(); + LLFloaterWorldMap(const LLSD& key); virtual ~LLFloaterWorldMap(); + // Prefer this to gFloaterWorldMap + static LLFloaterWorldMap* getInstance(); + static void *createWorldMapView(void* data); BOOL postBuild(); - /*virtual*/ void onClose(bool app_quitting); + /*virtual*/ void onOpen(const LLSD& key); - static void show(void*, BOOL center_on_target ); static void reloadIcons(void*); - static void toggle(void*); - static void hide(void*); /*virtual*/ void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE ); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - /*virtual*/ void setVisible(BOOL visible); /*virtual*/ void draw(); // methods for dealing with inventory. The observe() method is @@ -113,29 +112,26 @@ public: void teleport(); protected: - static void onPanBtn( void* userdata ); + void onClose(); + + void onGoHome(); - static void onGoHome(void* data); + void onLandmarkComboPrearrange(); + void onLandmarkComboCommit(); - static void onLandmarkComboPrearrange( LLUICtrl* ctrl, void* data ); - static void onLandmarkComboCommit( LLUICtrl* ctrl, void* data ); + void onAvatarComboPrearrange(); + void onAvatarComboCommit(); - static void onAvatarComboPrearrange( LLUICtrl* ctrl, void* data ); - static void onAvatarComboCommit( LLUICtrl* ctrl, void* data ); + void onCommitBackground(); - static void onCommitBackground(void* data, bool from_click); + void onComboTextEntry( ); + void onSearchTextEntry( LLLineEditor* ctrl ); - static void onComboTextEntry( LLLineEditor* ctrl, void* data ); - static void onSearchTextEntry( LLLineEditor* ctrl, void* data ); - - static void onClearBtn(void*); - static void onFlyBtn(void*); - static void onClickTeleportBtn(void*); - static void onShowTargetBtn(void*); - static void onShowAgentBtn(void*); - static void onCopySLURL(void*); - - static void onCheckEvents(LLUICtrl* ctrl, void*); + void onClearBtn(); + void onClickTeleportBtn(); + void onShowTargetBtn(); + void onShowAgentBtn(); + void onCopySLURL(); void centerOnTarget(BOOL animate); void updateLocation(); @@ -144,7 +140,6 @@ protected: void fly(); void buildLandmarkIDLists(); - static void onGoToLandmarkDialog(S32 option,void* userdata); void flyToLandmark(); void teleportToLandmark(); void setLandmarkVisited(); @@ -153,11 +148,11 @@ protected: void flyToAvatar(); void teleportToAvatar(); - static void updateSearchEnabled( LLUICtrl* ctrl, void* userdata ); - static void onLocationFocusChanged( LLFocusableElement* ctrl, void* userdata ); - static void onLocationCommit( void* userdata ); - static void onCommitLocation( LLUICtrl* ctrl, void* userdata ); - static void onCommitSearchResult( LLUICtrl* ctrl, void* userdata ); + void updateSearchEnabled(); + void onLocationFocusChanged( LLFocusableElement* ctrl ); + void onLocationCommit(); + void onCommitLocation(); + void onCommitSearchResult(); void cacheLandmarkPosition(); @@ -170,7 +165,6 @@ protected: LLDynamicArray mLandmarkAssetIDList; LLDynamicArray mLandmarkItemIDList; - BOOL mHasLandmarkPosition; static const LLUUID sHomeID; diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp index 97a3bd7c50..2a29566120 100644 --- a/indra/newview/llfolderview.cpp +++ b/indra/newview/llfolderview.cpp @@ -34,9 +34,31 @@ #include "llfolderview.h" -#include - +#include "llcallbacklist.h" +#include "llinventorybridge.h" +#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. +#include "llinventoryfilter.h" +#include "llfoldertype.h" +#include "llfloaterinventory.h"// hacked in for the bonus context menu items. +#include "llkeyboard.h" +#include "lllineeditor.h" +#include "llmenugl.h" +#include "llpreview.h" +#include "llscrollcontainer.h" // hack to allow scrolling +#include "lltooldraganddrop.h" +#include "lltrans.h" +#include "llui.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" +#include "llviewerjointattachment.h" +#include "llviewermenu.h" +#include "lluictrlfactory.h" #include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llfloaterproperties.h" + +// Linden library includes #include "lldbstrings.h" #include "llfocusmgr.h" #include "llfontgl.h" @@ -44,50 +66,22 @@ #include "llrender.h" #include "llinventory.h" -#include "llcallbacklist.h" -#include "llinventoryclipboard.h" // *TODO: remove this once hack below gone. -#include "llinventoryview.h"// hacked in for the bonus context menu items. -#include "llkeyboard.h" -#include "lllineeditor.h" -#include "llmenugl.h" -#include "llresmgr.h" -#include "llpreview.h" -#include "llscrollcontainer.h" // hack to allow scrolling -#include "lltooldraganddrop.h" -#include "llui.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" -#include "llviewerjointattachment.h" -#include "llviewermenu.h" -#include "lluictrlfactory.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llfloaterproperties.h" - -// RN: HACK -// We need these because some of the code below relies on things like -// gAgent root folder. Remove them once the abstraction leak is fixed. -#include "llagent.h" -#include "llappviewer.h" +// Third-party library includes +#include ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs ///---------------------------------------------------------------------------- -const S32 LEFT_PAD = 5; -const S32 LEFT_INDENTATION = 13; -const S32 ICON_PAD = 2; -const S32 ICON_WIDTH = 16; -const S32 TEXT_PAD = 1; -const S32 ARROW_SIZE = 12; const S32 RENAME_WIDTH_PAD = 4; -const S32 RENAME_HEIGHT_PAD = 6; +const S32 RENAME_HEIGHT_PAD = 2; const S32 AUTO_OPEN_STACK_DEPTH = 16; -const S32 MIN_ITEM_WIDTH_VISIBLE = ICON_WIDTH + ICON_PAD + ARROW_SIZE + TEXT_PAD + /*first few characters*/ 40; +const S32 MIN_ITEM_WIDTH_VISIBLE = LLFolderViewItem::ICON_WIDTH + + LLFolderViewItem::ICON_PAD + + LLFolderViewItem::ARROW_SIZE + + LLFolderViewItem::TEXT_PAD + + /*first few characters*/ 40; const S32 MINIMUM_RENAMER_WIDTH = 80; -const F32 FOLDER_CLOSE_TIME_CONSTANT = 0.02f; -const F32 FOLDER_OPEN_TIME_CONSTANT = 0.03f; -const S32 MAX_FOLDER_ITEM_OVERLAP = 2; enum { SIGNAL_NO_KEYBOARD_FOCUS = 1, @@ -103,2328 +97,6 @@ void properties_selected_items(void* user_data); void paste_items(void* user_data); void renamer_focus_lost( LLFocusableElement* handler, void* user_data ); -///---------------------------------------------------------------------------- -/// Class LLFolderViewItem -///---------------------------------------------------------------------------- - -// statics -const LLFontGL* LLFolderViewItem::sFont = NULL; -const LLFontGL* LLFolderViewItem::sSmallFont = NULL; -LLColor4 LLFolderViewItem::sFgColor; -LLColor4 LLFolderViewItem::sHighlightBgColor; -LLColor4 LLFolderViewItem::sHighlightFgColor; -LLColor4 LLFolderViewItem::sFilterBGColor; -LLColor4 LLFolderViewItem::sFilterTextColor; -LLColor4 LLFolderViewItem::sSuffixColor; -LLColor4 LLFolderViewItem::sSearchStatusColor; -LLUIImagePtr LLFolderViewItem::sArrowImage; -LLUIImagePtr LLFolderViewItem::sBoxImage; - -//static -void LLFolderViewItem::initClass() -{ - sFont = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); - sSmallFont = LLResMgr::getInstance()->getRes( LLFONT_SMALL ); - sFgColor = gColors.getColor( "MenuItemEnabledColor" ); - sHighlightBgColor = gColors.getColor( "MenuItemHighlightBgColor" ); - sHighlightFgColor = gColors.getColor( "MenuItemHighlightFgColor" ); - sFilterBGColor = gColors.getColor( "FilterBackgroundColor" ); - sFilterTextColor = gColors.getColor( "FilterTextColor" ); - sSuffixColor = gColors.getColor( "InventoryItemSuffixColor" ); - sSearchStatusColor = gColors.getColor( "InventorySearchStatusColor" ); - sArrowImage = LLUI::getUIImage("folder_arrow.tga"); - sBoxImage = LLUI::getUIImage("rounded_square.tga"); -} - -//static -void LLFolderViewItem::cleanupClass() -{ - sArrowImage = NULL; - sBoxImage = NULL; -} - -// Default constructor -// NOTE: Optimize this, we call it a *lot* when opening a large inventory -LLFolderViewItem::LLFolderViewItem( const std::string& name, LLUIImagePtr icon, - time_t creation_date, - LLFolderView* root, - LLFolderViewEventListener* listener ) : - LLUICtrl( name, LLRect(0, 0, 0, 0), TRUE, NULL, NULL, FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_RIGHT), - mLabel( name ), - mLabelWidth(0), - mCreationDate(creation_date), - mParentFolder( NULL ), - mListener( listener ), - mIsSelected( FALSE ), - mIsCurSelection( FALSE ), - mSelectPending(FALSE), - mLabelStyle( LLFontGL::NORMAL ), - mIcon(icon), - mHasVisibleChildren(FALSE), - mIndentation(0), - mNumDescendantsSelected(0), - mFiltered(FALSE), - mLastFilterGeneration(-1), - mStringMatchOffset(std::string::npos), - mControlLabelRotation(0.f), - mRoot( root ), - mDragAndDropTarget(FALSE), - mIsLoading(FALSE) -{ - refresh(); // possible opt: only call refreshFromListener() - setTabStop(FALSE); -} - -// Destroys the object -LLFolderViewItem::~LLFolderViewItem( void ) -{ - delete mListener; - mListener = NULL; -} - -LLFolderView* LLFolderViewItem::getRoot() -{ - return mRoot; -} - -// Returns true if this object is a child (or grandchild, etc.) of potential_ancestor. -BOOL LLFolderViewItem::isDescendantOf( const LLFolderViewFolder* potential_ancestor ) -{ - LLFolderViewItem* root = this; - while( root->mParentFolder ) - { - if( root->mParentFolder == potential_ancestor ) - { - return TRUE; - } - root = root->mParentFolder; - } - return FALSE; -} - -LLFolderViewItem* LLFolderViewItem::getNextOpenNode(BOOL include_children) -{ - if (!mParentFolder) - { - return NULL; - } - - LLFolderViewItem* itemp = mParentFolder->getNextFromChild( this, include_children ); - while(itemp && !itemp->getVisible()) - { - LLFolderViewItem* next_itemp = itemp->mParentFolder->getNextFromChild( itemp, include_children ); - if (itemp == next_itemp) - { - // hit last item - return itemp->getVisible() ? itemp : this; - } - itemp = next_itemp; - } - - return itemp; -} - -LLFolderViewItem* LLFolderViewItem::getPreviousOpenNode(BOOL include_children) -{ - if (!mParentFolder) - { - return NULL; - } - - LLFolderViewItem* itemp = mParentFolder->getPreviousFromChild( this, include_children ); - while(itemp && !itemp->getVisible()) - { - LLFolderViewItem* next_itemp = itemp->mParentFolder->getPreviousFromChild( itemp, include_children ); - if (itemp == next_itemp) - { - // hit first item - return itemp->getVisible() ? itemp : this; - } - itemp = next_itemp; - } - - return itemp; -} - -// is this item something we think we should be showing? -// for example, if we haven't gotten around to filtering it yet, then the answer is yes -// until we find out otherwise -BOOL LLFolderViewItem::potentiallyVisible() -{ - // we haven't been checked against min required filter - // or we have and we passed - return getLastFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration() || getFiltered(); -} - -BOOL LLFolderViewItem::getFiltered() -{ - return mFiltered && mLastFilterGeneration >= mRoot->getFilter()->getMinRequiredGeneration(); -} - -BOOL LLFolderViewItem::getFiltered(S32 filter_generation) -{ - return mFiltered && mLastFilterGeneration >= filter_generation; -} - -void LLFolderViewItem::setFiltered(BOOL filtered, S32 filter_generation) -{ - mFiltered = filtered; - mLastFilterGeneration = filter_generation; -} - -void LLFolderViewItem::setIcon(LLUIImagePtr icon) -{ - mIcon = icon; -} - -// refresh information from the listener -void LLFolderViewItem::refreshFromListener() -{ - if(mListener) - { - mLabel = mListener->getDisplayName(); - setIcon(mListener->getIcon()); - time_t creation_date = mListener->getCreationDate(); - if (mCreationDate != creation_date) - { - mCreationDate = mListener->getCreationDate(); - dirtyFilter(); - } - mLabelStyle = mListener->getLabelStyle(); - mLabelSuffix = mListener->getLabelSuffix(); - } -} - -void LLFolderViewItem::refresh() -{ - refreshFromListener(); - - std::string searchable_label(mLabel); - searchable_label.append(mLabelSuffix); - LLStringUtil::toUpper(searchable_label); - - if (mSearchableLabel.compare(searchable_label)) - { - mSearchableLabel.assign(searchable_label); - dirtyFilter(); - // some part of label has changed, so overall width has potentially changed - if (mParentFolder) - { - mParentFolder->requestArrange(); - } - } - - S32 label_width = sFont->getWidth(mLabel); - if( mLabelSuffix.size() ) - { - label_width += sFont->getWidth( mLabelSuffix ); - } - - mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + label_width; -} - -void LLFolderViewItem::applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor) -{ - functor(mListener); -} - -// This function is called when items are added or view filters change. It's -// implemented here but called by derived classes when folding the -// views. -void LLFolderViewItem::filterFromRoot( void ) -{ - LLFolderViewItem* root = getRoot(); - - root->filter(*((LLFolderView*)root)->getFilter()); -} - -// This function is called when the folder view is dirty. It's -// implemented here but called by derived classes when folding the -// views. -void LLFolderViewItem::arrangeFromRoot() -{ - LLFolderViewItem* root = getRoot(); - - S32 height = 0; - S32 width = 0; - root->arrange( &width, &height, 0 ); -} - -// This function clears the currently selected item, and records the -// specified selected item appropriately for display and use in the -// UI. If open is TRUE, then folders are opened up along the way to -// the selection. -void LLFolderViewItem::setSelectionFromRoot(LLFolderViewItem* selection, - BOOL openitem, - BOOL take_keyboard_focus) -{ - getRoot()->setSelection(selection, openitem, take_keyboard_focus); -} - -// helper function to change the selection from the root. -void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected) -{ - getRoot()->changeSelection(selection, selected); -} - -void LLFolderViewItem::extendSelectionFromRoot(LLFolderViewItem* selection) -{ - LLDynamicArray selected_items; - - getRoot()->extendSelection(selection, NULL, selected_items); -} - -EInventorySortGroup LLFolderViewItem::getSortGroup() const -{ - return SG_ITEM; -} - -// addToFolder() returns TRUE if it succeeds. FALSE otherwise -BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) -{ - if (!folder) - { - return FALSE; - } - mParentFolder = folder; - root->addItemID(getListener()->getUUID(), this); - return folder->addItem(this); -} - - -// Finds width and height of this object and it's children. Also -// makes sure that this view and it's children are the right size. -S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation) -{ - mIndentation = mParentFolder ? mParentFolder->getIndentation() + LEFT_INDENTATION : 0; - *width = llmax(*width, mLabelWidth + mIndentation); - *height = getItemHeight(); - return *height; -} - -S32 LLFolderViewItem::getItemHeight() -{ - S32 icon_height = mIcon->getHeight(); - S32 label_height = llround(sFont->getLineHeight()); - return llmax( icon_height, label_height ) + ICON_PAD; -} - -void LLFolderViewItem::filter( LLInventoryFilter& filter) -{ - BOOL filtered = mListener && filter.check(this); - - // if our visibility will change as a result of this filter, then - // we need to be rearranged in our parent folder - if (getVisible() != filtered) - { - if (mParentFolder) - { - mParentFolder->requestArrange(); - } - } - - setFiltered(filtered, filter.getCurrentGeneration()); - mStringMatchOffset = filter.getStringMatchOffset(); - filter.decrementFilterCount(); - - if (getRoot()->getDebugFilters()) - { - mStatusText = llformat("%d", mLastFilterGeneration); - } -} - -void LLFolderViewItem::dirtyFilter() -{ - mLastFilterGeneration = -1; - // bubble up dirty flag all the way to root - if (getParentFolder()) - { - getParentFolder()->setCompletedFilterGeneration(-1, TRUE); - } -} - -// *TODO: This can be optimized a lot by simply recording that it is -// selected in the appropriate places, and assuming that set selection -// means 'deselect' for a leaf item. Do this optimization after -// multiple selection is implemented to make sure it all plays nice -// together. -BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus) -{ - if( selection == this ) - { - mIsSelected = TRUE; - if(mListener) - { - mListener->selectItem(); - } - } - else - { - mIsSelected = FALSE; - } - return mIsSelected; -} - -BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected) -{ - if(selection == this && mIsSelected != selected) - { - mIsSelected = selected; - if(mListener) - { - mListener->selectItem(); - } - return TRUE; - } - return FALSE; -} - -void LLFolderViewItem::recursiveDeselect(BOOL deselect_self) -{ - if (mIsSelected && deselect_self) - { - mIsSelected = FALSE; - - // update ancestors' count of selected descendents - LLFolderViewFolder* parent_folder = getParentFolder(); - while(parent_folder) - { - parent_folder->mNumDescendantsSelected--; - parent_folder = parent_folder->getParentFolder(); - } - } -} - - -BOOL LLFolderViewItem::isMovable() -{ - if( mListener ) - { - return mListener->isItemMovable(); - } - else - { - return TRUE; - } -} - -BOOL LLFolderViewItem::isRemovable() -{ - if( mListener ) - { - return mListener->isItemRemovable(); - } - else - { - return TRUE; - } -} - -void LLFolderViewItem::destroyView() -{ - if (mParentFolder) - { - // removeView deletes me - mParentFolder->removeView(this); - } -} - -// Call through to the viewed object and return true if it can be -// removed. -//BOOL LLFolderViewItem::removeRecursively(BOOL single_item) -BOOL LLFolderViewItem::remove() -{ - if(!isRemovable()) - { - return FALSE; - } - if(mListener) - { - return mListener->removeItem(); - } - return TRUE; -} - -// Build an appropriate context menu for the item. -void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags) -{ - if(mListener) - { - mListener->buildContextMenu(menu, flags); - } -} - -void LLFolderViewItem::openItem( void ) -{ - if( mListener ) - { - mListener->openItem(); - } -} - -void LLFolderViewItem::preview( void ) -{ - if (mListener) - { - mListener->previewItem(); - } -} - -void LLFolderViewItem::rename(const std::string& new_name) -{ - if( !new_name.empty() ) - { - mLabel = new_name; - if( mListener ) - { - mListener->renameItem(new_name); - - if(mParentFolder) - { - mParentFolder->resort(this); - } - } - } -} - -const std::string& LLFolderViewItem::getSearchableLabel() const -{ - return mSearchableLabel; -} - -const std::string& LLFolderViewItem::getName( void ) const -{ - if(mListener) - { - return mListener->getName(); - } - return mLabel; -} - -// LLView functionality -BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) -{ - if(!mIsSelected) - { - setSelectionFromRoot(this, FALSE); - } - make_ui_sound("UISndClick"); - return TRUE; -} - -BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) -{ - // No handler needed for focus lost since this class has no - // state that depends on it. - gFocusMgr.setMouseCapture( this ); - - if (!mIsSelected) - { - if(mask & MASK_CONTROL) - { - changeSelectionFromRoot(this, !mIsSelected); - } - else if (mask & MASK_SHIFT) - { - extendSelectionFromRoot(this); - } - else - { - setSelectionFromRoot(this, FALSE); - } - make_ui_sound("UISndClick"); - } - else - { - mSelectPending = TRUE; - } - - if( isMovable() ) - { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y ); - LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y ); - } - return TRUE; -} - -BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) -{ - if( hasMouseCapture() && isMovable() ) - { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y ); - BOOL can_drag = TRUE; - if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) - { - LLFolderView* root = getRoot(); - - if(root->getCurSelectedItem()) - { - LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_WORLD; - - // *TODO: push this into listener and remove - // dependency on llagent - if(mListener && gInventory.isObjectDescendentOf(mListener->getUUID(), gAgent.getInventoryRootID())) - { - src = LLToolDragAndDrop::SOURCE_AGENT; - } - else if (mListener && gInventory.isObjectDescendentOf(mListener->getUUID(), gInventoryLibraryRoot)) - { - src = LLToolDragAndDrop::SOURCE_LIBRARY; - } - - can_drag = root->startDrag(src); - if (can_drag) - { - // if (mListener) mListener->startDrag(); - // RN: when starting drag and drop, clear out last auto-open - root->autoOpenTest(NULL); - root->setShowSelectionContext(TRUE); - - // Release keyboard focus, so that if stuff is dropped into the - // world, pressing the delete key won't blow away the inventory - // item. - gFocusMgr.setKeyboardFocus(NULL); - - return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); - } - } - } - - if (can_drag) - { - gViewerWindow->setCursor(UI_CURSOR_ARROW); - } - else - { - gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); - } - return TRUE; - } - else - { - getRoot()->setShowSelectionContext(FALSE); - gViewerWindow->setCursor(UI_CURSOR_ARROW); - // let parent handle this then... - return FALSE; - } -} - - -BOOL LLFolderViewItem::handleDoubleClick( S32 x, S32 y, MASK mask ) -{ - preview(); - return TRUE; -} - -BOOL LLFolderViewItem::handleScrollWheel(S32 x, S32 y, S32 clicks) -{ - if (getParent()) - { - return getParent()->handleScrollWheel(x, y, clicks); - } - return FALSE; -} - -BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) -{ - // if mouse hasn't moved since mouse down... - if ( pointInView(x, y) && mSelectPending ) - { - //...then select - if(mask & MASK_CONTROL) - { - changeSelectionFromRoot(this, !mIsSelected); - } - else if (mask & MASK_SHIFT) - { - extendSelectionFromRoot(this); - } - else - { - setSelectionFromRoot(this, FALSE); - } - } - - mSelectPending = FALSE; - - if( hasMouseCapture() ) - { - getRoot()->setShowSelectionContext(FALSE); - gFocusMgr.setMouseCapture( NULL ); - } - return TRUE; -} - -BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - BOOL accepted = FALSE; - BOOL handled = FALSE; - if(mListener) - { - accepted = mListener->dragOrDrop(mask,drop,cargo_type,cargo_data); - handled = accepted; - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - } - if(mParentFolder && !handled) - { - handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); - } - if (handled) - { - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewItem" << llendl; - } - - return handled; -} - - -void LLFolderViewItem::draw() -{ - bool possibly_has_children = false; - bool up_to_date = mListener && mListener->isUpToDate(); - if((up_to_date && hasVisibleChildren() ) || // we fetched our children and some of them have passed the filter... - (!up_to_date && mListener && mListener->hasChildren())) // ...or we know we have children but haven't fetched them (doesn't obey filter) - { - possibly_has_children = true; - } - if(/*mControlLabel[0] != '\0' && */possibly_has_children) - { - if (sArrowImage) - { - gl_draw_scaled_rotated_image(mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD, - ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, sArrowImage->getImage(), sFgColor); - } - } - - F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); - - // If we have keyboard focus, draw selection filled - BOOL show_context = getRoot()->getShowSelectionContext(); - BOOL filled = show_context || (gFocusMgr.getKeyboardFocus() == getRoot()); - - // always render "current" item, only render other selected items if - // mShowSingleSelection is FALSE - if( mIsSelected ) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLColor4 bg_color = sHighlightBgColor; - //const S32 TRAILING_PAD = 5; // It just looks better with this. - if (!mIsCurSelection) - { - // do time-based fade of extra objects - F32 fade_time = getRoot()->getSelectionFadeElapsedTime(); - if (getRoot()->getShowSingleSelection()) - { - // fading out - bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f); - } - else - { - // fading in - bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); - } - } - - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), - bg_color, filled); - if (mIsCurSelection) - { - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), - sHighlightFgColor, FALSE); - } - if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) - { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, - sHighlightFgColor, FALSE); - if (show_context) - { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, - sHighlightBgColor, TRUE); - } - } - } - if (mDragAndDropTarget) - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d( - 0, - getRect().getHeight(), - getRect().getWidth() - 2, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), - sHighlightBgColor, FALSE); - - if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) - { - gl_rect_2d( - 0, - llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, - getRect().getWidth() - 2, - 2, - sHighlightBgColor, FALSE); - } - mDragAndDropTarget = FALSE; - } - - - if(mIcon) - { - mIcon->draw(mIndentation + ARROW_SIZE + TEXT_PAD, getRect().getHeight() - mIcon->getHeight()); - } - - if (!mLabel.empty()) - { - // highlight filtered text - BOOL debug_filters = getRoot()->getDebugFilters(); - LLColor4 color = ( (mIsSelected && filled) ? sHighlightFgColor : sFgColor ); - F32 right_x; - F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; - - if (debug_filters) - { - if (!getFiltered() && !possibly_has_children) - { - color.mV[VALPHA] *= 0.5f; - } - - LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); - sSmallFont->renderUTF8(mStatusText, 0, text_left, y, filter_color, - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, - S32_MAX, S32_MAX, &right_x, FALSE ); - text_left = right_x; - } - - - if ( mIsLoading && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime") ) - { - // *TODO: Translate - sFont->renderUTF8( std::string("Loading... "), 0, text_left, y, sSearchStatusColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, S32_MAX, S32_MAX, &right_x, FALSE); - text_left = right_x; - } - - sFont->renderUTF8( mLabel, 0, text_left, y, color, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, - S32_MAX, S32_MAX, &right_x, FALSE ); - if (!mLabelSuffix.empty()) - { - sFont->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, - LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, - S32_MAX, S32_MAX, &right_x, FALSE ); - } - - if (sBoxImage.notNull() && mStringMatchOffset != std::string::npos) - { - // don't draw backgrounds for zero-length strings - S32 filter_string_length = mRoot->getFilterSubString().size(); - if (filter_string_length > 0) - { - std::string combined_string = mLabel + mLabelSuffix; - S32 left = llround(text_left) + sFont->getWidth(combined_string, 0, mStringMatchOffset) - 1; - S32 right = left + sFont->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; - S32 bottom = llfloor(getRect().getHeight() - sFont->getLineHeight() - 3); - S32 top = getRect().getHeight(); - - LLRect box_rect(left, top, right, bottom); - sBoxImage->draw(box_rect, sFilterBGColor); - F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset); - F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; - sFont->renderUTF8( combined_string, mStringMatchOffset, match_string_left, y, - sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, - filter_string_length, S32_MAX, &right_x, FALSE ); - } - } - } - - if( sDebugRects ) - { - drawDebugRect(); - } -} - - -///---------------------------------------------------------------------------- -/// Class LLFolderViewFolder -///---------------------------------------------------------------------------- - -// Default constructor -LLFolderViewFolder::LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, - LLFolderView* root, - LLFolderViewEventListener* listener ): - LLFolderViewItem( name, icon, 0, root, listener ), // 0 = no create time - mIsOpen(FALSE), - mExpanderHighlighted(FALSE), - mCurHeight(0.f), - mTargetHeight(0.f), - mAutoOpenCountdown(0.f), - mSubtreeCreationDate(0), - mAmTrash(LLFolderViewFolder::UNKNOWN), - mLastArrangeGeneration( -1 ), - mLastCalculatedWidth(0), - mCompletedFilterGeneration(-1), - mMostFilteredDescendantGeneration(-1) -{ - mType = std::string("(folder)"); -} - -// Destroys the object -LLFolderViewFolder::~LLFolderViewFolder( void ) -{ - // The LLView base class takes care of object destruction. make sure that we - // don't have mouse or keyboard focus - gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() -} - -// addToFolder() returns TRUE if it succeeds. FALSE otherwise -BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) -{ - if (!folder) - { - return FALSE; - } - mParentFolder = folder; - root->addItemID(getListener()->getUUID(), this); - return folder->addFolder(this); -} - -// Finds width and height of this object and it's children. Also -// makes sure that this view and it's children are the right size. -S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) -{ - mHasVisibleChildren = hasFilteredDescendants(filter_generation); - - LLInventoryFilter::EFolderShow show_folder_state = getRoot()->getShowFolderState(); - - // calculate height as a single item (without any children), and reshapes rectangle to match - LLFolderViewItem::arrange( width, height, filter_generation ); - - // clamp existing animated height so as to never get smaller than a single item - mCurHeight = llmax((F32)*height, mCurHeight); - - // initialize running height value as height of single item in case we have no children - *height = getItemHeight(); - F32 running_height = (F32)*height; - F32 target_height = (F32)*height; - - // are my children visible? - if (needsArrange()) - { - // set last arrange generation first, in case children are animating - // and need to be arranged again - mLastArrangeGeneration = mRoot->getArrangeGeneration(); - if (mIsOpen) - { - // Add sizes of children - S32 parent_item_height = getRect().getHeight(); - - for(folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) - { - LLFolderViewFolder* folderp = (*fit); - if (getRoot()->getDebugFilters()) - { - folderp->setVisible(TRUE); - } - else - { - folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? - (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter - } - - if (folderp->getVisible()) - { - S32 child_width = *width; - S32 child_height = 0; - S32 child_top = parent_item_height - llround(running_height); - - target_height += folderp->arrange( &child_width, &child_height, filter_generation ); - - running_height += (F32)child_height; - *width = llmax(*width, child_width); - folderp->setOrigin( 0, child_top - folderp->getRect().getHeight() ); - } - } - for(items_t::iterator iit = mItems.begin(); - iit != mItems.end(); ++iit) - { - LLFolderViewItem* itemp = (*iit); - if (getRoot()->getDebugFilters()) - { - itemp->setVisible(TRUE); - } - else - { - itemp->setVisible(itemp->getFiltered(filter_generation)); - } - - if (itemp->getVisible()) - { - S32 child_width = *width; - S32 child_height = 0; - S32 child_top = parent_item_height - llround(running_height); - - target_height += itemp->arrange( &child_width, &child_height, filter_generation ); - // don't change width, as this item is as wide as its parent folder by construction - itemp->reshape( itemp->getRect().getWidth(), child_height); - - running_height += (F32)child_height; - *width = llmax(*width, child_width); - itemp->setOrigin( 0, child_top - itemp->getRect().getHeight() ); - } - } - } - - mTargetHeight = target_height; - // cache this width so next time we can just return it - mLastCalculatedWidth = *width; - } - else - { - // just use existing width - *width = mLastCalculatedWidth; - } - - // animate current height towards target height - if (llabs(mCurHeight - mTargetHeight) > 1.f) - { - mCurHeight = lerp(mCurHeight, mTargetHeight, LLCriticalDamp::getInterpolant(mIsOpen ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); - - requestArrange(); - - // hide child elements that fall out of current animated height - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - // number of pixels that bottom of folder label is from top of parent folder - if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) - { - // hide if beyond current folder height - (*fit)->setVisible(FALSE); - } - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - // number of pixels that bottom of item label is from top of parent folder - if (getRect().getHeight() - (*iit)->getRect().mBottom - > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) - { - (*iit)->setVisible(FALSE); - } - } - } - else - { - mCurHeight = mTargetHeight; - } - - // don't change width as this item is already as wide as its parent folder - reshape(getRect().getWidth(),llround(mCurHeight)); - - // pass current height value back to parent - *height = llround(mCurHeight); - - return llround(mTargetHeight); -} - -BOOL LLFolderViewFolder::needsArrange() -{ - return mLastArrangeGeneration < mRoot->getArrangeGeneration(); -} - -void LLFolderViewFolder::setCompletedFilterGeneration(S32 generation, BOOL recurse_up) -{ - mMostFilteredDescendantGeneration = llmin(mMostFilteredDescendantGeneration, generation); - mCompletedFilterGeneration = generation; - // only aggregate up if we are a lower (older) value - if (recurse_up && mParentFolder && generation < mParentFolder->getCompletedFilterGeneration()) - { - mParentFolder->setCompletedFilterGeneration(generation, TRUE); - } -} - -void LLFolderViewFolder::filter( LLInventoryFilter& filter) -{ - S32 filter_generation = filter.getCurrentGeneration(); - // if failed to pass filter newer than must_pass_generation - // you will automatically fail this time, so we only - // check against items that have passed the filter - S32 must_pass_generation = filter.getMustPassGeneration(); - - // if we have already been filtered against this generation, skip out - if (getCompletedFilterGeneration() >= filter_generation) - { - return; - } - - // filter folder itself - if (getLastFilterGeneration() < filter_generation) - { - if (getLastFilterGeneration() >= must_pass_generation && // folder has been compared to a valid precursor filter - !mFiltered) // and did not pass the filter - { - // go ahead and flag this folder as done - mLastFilterGeneration = filter_generation; - } - else - { - // filter self only on first pass through - LLFolderViewItem::filter( filter ); - } - } - - if (getRoot()->getDebugFilters()) - { - mStatusText = llformat("%d", mLastFilterGeneration); - mStatusText += llformat("(%d)", mCompletedFilterGeneration); - mStatusText += llformat("+%d", mMostFilteredDescendantGeneration); - } - - // all descendants have been filtered later than must pass generation - // but none passed - if(getCompletedFilterGeneration() >= must_pass_generation && !hasFilteredDescendants(must_pass_generation)) - { - // don't traverse children if we've already filtered them since must_pass_generation - // and came back with nothing - return; - } - - // we entered here with at least one filter iteration left - // check to see if we have any more before continuing on to children - if (filter.getFilterCount() < 0) - { - return; - } - - // when applying a filter, matching folders get their contents downloaded first - if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) - { - gInventory.startBackgroundFetch(mListener->getUUID()); - } - - // now query children - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - // have we run out of iterations this frame? - if (filter.getFilterCount() < 0) - { - break; - } - - // mMostFilteredDescendantGeneration might have been reset - // in which case we need to update it even for folders that - // don't need to be filtered anymore - if ((*fit)->getCompletedFilterGeneration() >= filter_generation) - { - // track latest generation to pass any child items - if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter.getMinRequiredGeneration())) - { - mMostFilteredDescendantGeneration = filter_generation; - if (mRoot->needsAutoSelect()) - { - (*fit)->setOpenArrangeRecursively(TRUE); - } - } - // just skip it, it has already been filtered - continue; - } - - // update this folders filter status (and children) - (*fit)->filter( filter ); - - // track latest generation to pass any child items - if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter_generation)) - { - mMostFilteredDescendantGeneration = filter_generation; - if (mRoot->needsAutoSelect()) - { - (*fit)->setOpenArrangeRecursively(TRUE); - } - } - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if (filter.getFilterCount() < 0) - { - break; - } - if ((*iit)->getLastFilterGeneration() >= filter_generation) - { - if ((*iit)->getFiltered()) - { - mMostFilteredDescendantGeneration = filter_generation; - } - continue; - } - - if ((*iit)->getLastFilterGeneration() >= must_pass_generation && - !(*iit)->getFiltered(must_pass_generation)) - { - // failed to pass an earlier filter that was a subset of the current one - // go ahead and flag this item as done - (*iit)->setFiltered(FALSE, filter_generation); - continue; - } - - (*iit)->filter( filter ); - - if ((*iit)->getFiltered(filter.getMinRequiredGeneration())) - { - mMostFilteredDescendantGeneration = filter_generation; - } - } - - // if we didn't use all filter iterations - // that means we filtered all of our descendants - // instead of exhausting the filter count for this frame - if (filter.getFilterCount() > 0) - { - // flag this folder as having completed filter pass for all descendants - setCompletedFilterGeneration(filter_generation, FALSE/*dont recurse up to root*/); - } -} - -void LLFolderViewFolder::setFiltered(BOOL filtered, S32 filter_generation) -{ - // if this folder is now filtered, but wasn't before - // (it just passed) - if (filtered && !mFiltered) - { - // reset current height, because last time we drew it - // it might have had more visible items than now - mCurHeight = 0.f; - } - - LLFolderViewItem::setFiltered(filtered, filter_generation); -} - -void LLFolderViewFolder::dirtyFilter() -{ - // we're a folder, so invalidate our completed generation - setCompletedFilterGeneration(-1, FALSE); - LLFolderViewItem::dirtyFilter(); -} - -BOOL LLFolderViewFolder::hasFilteredDescendants() -{ - return mMostFilteredDescendantGeneration >= mRoot->getFilter()->getCurrentGeneration(); -} - -// Passes selection information on to children and record selection -// information if necessary. -BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus) -{ - BOOL rv = FALSE; - if( selection == this ) - { - mIsSelected = TRUE; - if(mListener) - { - mListener->selectItem(); - } - rv = TRUE; - } - else - { - mIsSelected = FALSE; - rv = FALSE; - } - BOOL child_selected = FALSE; - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if((*fit)->setSelection(selection, openitem, take_keyboard_focus)) - { - rv = TRUE; - child_selected = TRUE; - mNumDescendantsSelected++; - } - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if((*iit)->setSelection(selection, openitem, take_keyboard_focus)) - { - rv = TRUE; - child_selected = TRUE; - mNumDescendantsSelected++; - } - } - if(openitem && child_selected) - { - setOpenArrangeRecursively(TRUE); - } - return rv; -} - -// This method is used to change the selection of an item. If -// selection is 'this', then note selection as true. Returns TRUE -// if this or a child is now selected. -BOOL LLFolderViewFolder::changeSelection(LLFolderViewItem* selection, - BOOL selected) -{ - BOOL rv = FALSE; - if(selection == this) - { - mIsSelected = selected; - if(mListener && selected) - { - mListener->selectItem(); - } - rv = TRUE; - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if((*fit)->changeSelection(selection, selected)) - { - if (selected) - { - mNumDescendantsSelected++; - } - else - { - mNumDescendantsSelected--; - } - rv = TRUE; - } - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if((*iit)->changeSelection(selection, selected)) - { - if (selected) - { - mNumDescendantsSelected++; - } - else - { - mNumDescendantsSelected--; - } - rv = TRUE; - } - } - return rv; -} - -S32 LLFolderViewFolder::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& selected_items) -{ - S32 num_selected = 0; - - // pass on to child folders first - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - num_selected += (*fit)->extendSelection(selection, last_selected, selected_items); - mNumDescendantsSelected += num_selected; - } - - // handle selection of our immediate children... - BOOL reverse_select = FALSE; - BOOL found_last_selected = FALSE; - BOOL found_selection = FALSE; - LLDynamicArray items_to_select; - LLFolderViewItem* item; - - //...folders first... - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - item = (*fit); - if(item == selection) - { - found_selection = TRUE; - } - else if (item == last_selected) - { - found_last_selected = TRUE; - if (found_selection) - { - reverse_select = TRUE; - } - } - - if (found_selection || found_last_selected) - { - // deselect currently selected items so they can be pushed back on queue - if (item->isSelected()) - { - item->changeSelection(item, FALSE); - } - items_to_select.put(item); - } - - if (found_selection && found_last_selected) - { - break; - } - } - - if (!(found_selection && found_last_selected)) - { - //,,,then items - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - item = (*iit); - if(item == selection) - { - found_selection = TRUE; - } - else if (item == last_selected) - { - found_last_selected = TRUE; - if (found_selection) - { - reverse_select = TRUE; - } - } - - if (found_selection || found_last_selected) - { - // deselect currently selected items so they can be pushed back on queue - if (item->isSelected()) - { - item->changeSelection(item, FALSE); - } - items_to_select.put(item); - } - - if (found_selection && found_last_selected) - { - break; - } - } - } - - if (found_last_selected && found_selection) - { - // we have a complete selection inside this folder - for (S32 index = reverse_select ? items_to_select.getLength() - 1 : 0; - reverse_select ? index >= 0 : index < items_to_select.getLength(); reverse_select ? index-- : index++) - { - LLFolderViewItem* item = items_to_select[index]; - if (item->changeSelection(item, TRUE)) - { - selected_items.put(item); - mNumDescendantsSelected++; - num_selected++; - } - } - } - else if (found_selection) - { - // last selection was not in this folder....go ahead and select just the new item - if (selection->changeSelection(selection, TRUE)) - { - selected_items.put(selection); - mNumDescendantsSelected++; - num_selected++; - } - } - - return num_selected; -} - -void LLFolderViewFolder::recursiveDeselect(BOOL deselect_self) -{ - // make sure we don't have negative values - llassert(mNumDescendantsSelected >= 0); - - if (mIsSelected && deselect_self) - { - mIsSelected = FALSE; - - // update ancestors' count of selected descendents - LLFolderViewFolder* parent_folder = getParentFolder(); - while(parent_folder) - { - parent_folder->mNumDescendantsSelected--; - parent_folder = parent_folder->getParentFolder(); - } - } - - if (0 == mNumDescendantsSelected) - { - return; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - LLFolderViewItem* item = (*iit); - item->recursiveDeselect(TRUE); - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - LLFolderViewFolder* folder = (*fit); - folder->recursiveDeselect(TRUE); - } - -} - -void LLFolderViewFolder::destroyView() -{ - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - LLFolderViewItem* item = (*iit); - getRoot()->removeItemID(item->getListener()->getUUID()); - } - - std::for_each(mItems.begin(), mItems.end(), DeletePointer()); - mItems.clear(); - - while (!mFolders.empty()) - { - LLFolderViewFolder *folderp = mFolders.back(); - folderp->destroyView(); // removes entry from mFolders - } - - deleteAllChildren(); - - if (mParentFolder) - { - mParentFolder->removeView(this); - } -} - -// remove the specified item (and any children) if possible. Return -// TRUE if the item was deleted. -BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item) -{ - if(item->remove()) - { - //RN: this seem unneccessary as remove() moves to trash - //removeView(item); - return TRUE; - } - return FALSE; -} - -// simply remove the view (and any children) Don't bother telling the -// listeners. -void LLFolderViewFolder::removeView(LLFolderViewItem* item) -{ - if (!item || item->getParentFolder() != this) - { - return; - } - // deselect without traversing hierarchy - item->recursiveDeselect(TRUE); - getRoot()->removeFromSelectionList(item); - extractItem(item); - delete item; -} - -// extractItem() removes the specified item from the folder, but -// doesn't delete it. -void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) -{ - items_t::iterator it = std::find(mItems.begin(), mItems.end(), item); - if(it == mItems.end()) - { - // This is an evil downcast. However, it's only doing - // pointer comparison to find if (which it should be ) the - // item is in the container, so it's pretty safe. - LLFolderViewFolder* f = reinterpret_cast(item); - folders_t::iterator ft; - ft = std::find(mFolders.begin(), mFolders.end(), f); - if(ft != mFolders.end()) - { - mFolders.erase(ft); - } - } - else - { - mItems.erase(it); - } - //item has been removed, need to update filter - dirtyFilter(); - //because an item is going away regardless of filter status, force rearrange - requestArrange(); - getRoot()->removeItemID(item->getListener()->getUUID()); - removeChild(item); -} - -// This function is called by a child that needs to be resorted. -// This is only called for renaming an object because it won't work for date -void LLFolderViewFolder::resort(LLFolderViewItem* item) -{ - mItems.sort(mSortFunction); - mFolders.sort(mSortFunction); -} - -bool LLFolderViewFolder::isTrash() const -{ - if (mAmTrash == LLFolderViewFolder::UNKNOWN) - { - mAmTrash = mListener->getUUID() == gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH, false) ? LLFolderViewFolder::TRASH : LLFolderViewFolder::NOT_TRASH; - } - return mAmTrash == LLFolderViewFolder::TRASH; -} - -void LLFolderViewFolder::sortBy(U32 order) -{ - if (!mSortFunction.updateSort(order)) - { - // No changes. - return; - } - - // Propegate this change to sub folders - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->sortBy(order); - } - - mFolders.sort(mSortFunction); - mItems.sort(mSortFunction); - - if (order & LLInventoryFilter::SO_DATE) - { - time_t latest = 0; - - if (!mItems.empty()) - { - LLFolderViewItem* item = *(mItems.begin()); - latest = item->getCreationDate(); - } - - if (!mFolders.empty()) - { - LLFolderViewFolder* folder = *(mFolders.begin()); - if (folder->getCreationDate() > latest) - { - latest = folder->getCreationDate(); - } - } - mSubtreeCreationDate = latest; - } -} - -void LLFolderViewFolder::setItemSortOrder(U32 ordering) -{ - if (mSortFunction.updateSort(ordering)) - { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->setItemSortOrder(ordering); - } - - mFolders.sort(mSortFunction); - mItems.sort(mSortFunction); - } -} - -EInventorySortGroup LLFolderViewFolder::getSortGroup() const -{ - if (isTrash()) - { - return SG_TRASH_FOLDER; - } - - // Folders that can't be moved are 'system' folders. - if( mListener ) - { - if( !(mListener->isItemMovable()) ) - { - return SG_SYSTEM_FOLDER; - } - } - - return SG_NORMAL_FOLDER; -} - -BOOL LLFolderViewFolder::isMovable() -{ - if( mListener ) - { - if( !(mListener->isItemMovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isMovable()) - { - return FALSE; - } - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isMovable()) - { - return FALSE; - } - } - } - return TRUE; -} - - -BOOL LLFolderViewFolder::isRemovable() -{ - if( mListener ) - { - if( !(mListener->isItemRemovable()) ) - { - return FALSE; - } - - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - if(!(*iit)->isRemovable()) - { - return FALSE; - } - } - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - if(!(*fit)->isRemovable()) - { - return FALSE; - } - } - } - return TRUE; -} - -// this is an internal method used for adding items to folders. -BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) -{ - - items_t::iterator it = std::lower_bound( - mItems.begin(), - mItems.end(), - item, - mSortFunction); - mItems.insert(it,item); - item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); - item->setVisible(FALSE); - addChild( item ); - item->dirtyFilter(); - requestArrange(); - return TRUE; -} - -// this is an internal method used for adding items to folders. -BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) -{ - folders_t::iterator it = std::lower_bound( - mFolders.begin(), - mFolders.end(), - folder, - mSortFunction); - mFolders.insert(it,folder); - folder->setOrigin(0, 0); - folder->reshape(getRect().getWidth(), 0); - folder->setVisible(FALSE); - addChild( folder ); - folder->dirtyFilter(); - // rearrange all descendants too, as our indentation level might have changed - folder->requestArrange(TRUE); - return TRUE; -} - -void LLFolderViewFolder::requestArrange(BOOL include_descendants) -{ - mLastArrangeGeneration = -1; - // flag all items up to root - if (mParentFolder) - { - mParentFolder->requestArrange(); - } - - if (include_descendants) - { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end(); - ++iter) - { - (*iter)->requestArrange(TRUE); - } - } -} - -void LLFolderViewFolder::toggleOpen() -{ - setOpen(!mIsOpen); -} - -// Force a folder open or closed -void LLFolderViewFolder::setOpen(BOOL openitem) -{ - setOpenArrangeRecursively(openitem); -} - -void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse) -{ - BOOL was_open = mIsOpen; - mIsOpen = openitem; - if(!was_open && openitem) - { - if(mListener) - { - mListener->openItem(); - } - } - - if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) - { - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->setOpenArrangeRecursively(openitem, RECURSE_DOWN); /* Flawfinder: ignore */ - } - } - if (mParentFolder && (recurse == RECURSE_UP || recurse == RECURSE_UP_DOWN)) - { - mParentFolder->setOpenArrangeRecursively(openitem, RECURSE_UP); - } - - if (was_open != mIsOpen) - { - requestArrange(); - } -} - -BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, - BOOL drop, - EDragAndDropType c_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - BOOL accepted = mListener && mListener->dragOrDrop(mask,drop,c_type,cargo_data); - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - - // drag and drop to child item, so clear pending auto-opens - getRoot()->autoOpenTest(NULL); - - return TRUE; -} - -void LLFolderViewFolder::openItem( void ) -{ - toggleOpen(); -} - -void LLFolderViewFolder::applyFunctorRecursively(LLFolderViewFunctor& functor) -{ - functor.doFolder(this); - - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->applyFunctorRecursively(functor); - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - functor.doItem((*iit)); - } -} - -void LLFolderViewFolder::applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor) -{ - functor(mListener); - for (folders_t::iterator iter = mFolders.begin(); - iter != mFolders.end();) - { - folders_t::iterator fit = iter++; - (*fit)->applyListenerFunctorRecursively(functor); - } - for (items_t::iterator iter = mItems.begin(); - iter != mItems.end();) - { - items_t::iterator iit = iter++; - (*iit)->applyListenerFunctorRecursively(functor); - } -} - -// LLView functionality -BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg) -{ - LLFolderView* root_view = getRoot(); - - BOOL handled = FALSE; - if(mIsOpen) - { - handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, - cargo_data, accept, tooltip_msg) != NULL; - } - - if (!handled) - { - BOOL accepted = mListener && mListener->dragOrDrop(mask, drop,cargo_type,cargo_data); - - if (accepted) - { - mDragAndDropTarget = TRUE; - *accept = ACCEPT_YES_MULTI; - } - else - { - *accept = ACCEPT_NO; - } - - if (!drop && accepted) - { - root_view->autoOpenTest(this); - } - - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; - } - - return TRUE; -} - - -BOOL LLFolderViewFolder::handleRightMouseDown( S32 x, S32 y, MASK mask ) -{ - BOOL handled = FALSE; - // fetch contents of this folder, as context menu can depend on contents - // still, user would have to open context menu again to see the changes - gInventory.fetchDescendentsOf(mListener->getUUID()); - - if( mIsOpen ) - { - handled = childrenHandleRightMouseDown( x, y, mask ) != NULL; - } - if (!handled) - { - handled = LLFolderViewItem::handleRightMouseDown( x, y, mask ); - } - return handled; -} - - -BOOL LLFolderViewFolder::handleHover(S32 x, S32 y, MASK mask) -{ - BOOL handled = LLView::handleHover(x, y, mask); - - if (!handled) - { - // this doesn't do child processing - handled = LLFolderViewItem::handleHover(x, y, mask); - } - - //if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD && y > getRect().getHeight() - ) - //{ - // gViewerWindow->setCursor(UI_CURSOR_ARROW); - // mExpanderHighlighted = TRUE; - // handled = TRUE; - //} - return handled; -} - -BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) -{ - BOOL handled = FALSE; - if( mIsOpen ) - { - handled = childrenHandleMouseDown(x,y,mask) != NULL; - } - if( !handled ) - { - if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD) - { - toggleOpen(); - handled = TRUE; - } - else - { - // do normal selection logic - handled = LLFolderViewItem::handleMouseDown(x, y, mask); - } - } - - return handled; -} - -BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) -{ - BOOL handled = FALSE; - if( mIsOpen ) - { - handled = childrenHandleDoubleClick( x, y, mask ) != NULL; - } - if( !handled ) - { - if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD) - { - // don't select when user double-clicks plus sign - // so as not to contradict single-click behavior - toggleOpen(); - } - else - { - setSelectionFromRoot(this, FALSE); - toggleOpen(); - } - handled = TRUE; - } - return handled; -} - -void LLFolderViewFolder::draw() -{ - if (mAutoOpenCountdown != 0.f) - { - mControlLabelRotation = mAutoOpenCountdown * -90.f; - } - else if (mIsOpen) - { - mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f)); - } - else - { - mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f)); - } - - bool possibly_has_children = false; - bool up_to_date = mListener && mListener->isUpToDate(); - if(!up_to_date && mListener && mListener->hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter) - { - possibly_has_children = true; - } - - - BOOL loading = ( mIsOpen && possibly_has_children && !up_to_date ); - - if ( loading && !mIsLoading ) - { - // Measure how long we've been in the loading state - mTimeSinceRequestStart.reset(); - } - - mIsLoading = loading; - - LLFolderViewItem::draw(); - - // draw children if root folder, or any other folder that is open or animating to closed state - if( getRoot() == this || (mIsOpen || mCurHeight != mTargetHeight )) - { - LLView::draw(); - } - - mExpanderHighlighted = FALSE; -} - -time_t LLFolderViewFolder::getCreationDate() const -{ - return llmax(mCreationDate, mSubtreeCreationDate); -} - - -BOOL LLFolderViewFolder::potentiallyVisible() -{ - // folder should be visible by it's own filter status - return LLFolderViewItem::potentiallyVisible() - // or one or more of its descendants have passed the minimum filter requirement - || hasFilteredDescendants(mRoot->getFilter()->getMinRequiredGeneration()) - // or not all of its descendants have been checked against minimum filter requirement - || getCompletedFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration(); -} - -// this does prefix traversal, as folders are listed above their contents -LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) -{ - BOOL found_item = FALSE; - - LLFolderViewItem* result = NULL; - // when not starting from a given item, start at beginning - if(item == NULL) - { - found_item = TRUE; - } - - // find current item among children - folders_t::iterator fit = mFolders.begin(); - folders_t::iterator fend = mFolders.end(); - - items_t::iterator iit = mItems.begin(); - items_t::iterator iend = mItems.end(); - - // if not trivially starting at the beginning, we have to find the current item - if (!found_item) - { - // first, look among folders, since they are always above items - for(; fit != fend; ++fit) - { - if(item == (*fit)) - { - found_item = TRUE; - // if we are on downwards traversal - if (include_children && (*fit)->isOpen()) - { - // look for first descendant - return (*fit)->getNextFromChild(NULL, TRUE); - } - // otherwise advance to next folder - ++fit; - include_children = TRUE; - break; - } - } - - // didn't find in folders? Check items... - if (!found_item) - { - for(; iit != iend; ++iit) - { - if(item == (*iit)) - { - found_item = TRUE; - // point to next item - ++iit; - break; - } - } - } - } - - if (!found_item) - { - // you should never call this method with an item that isn't a child - // so we should always find something - llassert(FALSE); - return NULL; - } - - // at this point, either iit or fit point to a candidate "next" item - // if both are out of range, we need to punt up to our parent - - // now, starting from found folder, continue through folders - // searching for next visible folder - while(fit != fend && !(*fit)->getVisible()) - { - // turn on downwards traversal for next folder - ++fit; - } - - if (fit != fend) - { - result = (*fit); - } - else - { - // otherwise, scan for next visible item - while(iit != iend && !(*iit)->getVisible()) - { - ++iit; - } - - // check to see if we have a valid item - if (iit != iend) - { - result = (*iit); - } - } - - if( !result && mParentFolder ) - { - // If there are no siblings or children to go to, recurse up one level in the tree - // and skip children for this folder, as we've already discounted them - result = mParentFolder->getNextFromChild(this, FALSE); - } - - return result; -} - -// this does postfix traversal, as folders are listed above their contents -LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* item, BOOL include_children ) -{ - BOOL found_item = FALSE; - - LLFolderViewItem* result = NULL; - // when not starting from a given item, start at end - if(item == NULL) - { - found_item = TRUE; - } - - // find current item among children - folders_t::reverse_iterator fit = mFolders.rbegin(); - folders_t::reverse_iterator fend = mFolders.rend(); - - items_t::reverse_iterator iit = mItems.rbegin(); - items_t::reverse_iterator iend = mItems.rend(); - - // if not trivially starting at the end, we have to find the current item - if (!found_item) - { - // first, look among items, since they are always below the folders - for(; iit != iend; ++iit) - { - if(item == (*iit)) - { - found_item = TRUE; - // point to next item - ++iit; - break; - } - } - - // didn't find in items? Check folders... - if (!found_item) - { - for(; fit != fend; ++fit) - { - if(item == (*fit)) - { - found_item = TRUE; - // point to next folder - ++fit; - break; - } - } - } - } - - if (!found_item) - { - // you should never call this method with an item that isn't a child - // so we should always find something - llassert(FALSE); - return NULL; - } - - // at this point, either iit or fit point to a candidate "next" item - // if both are out of range, we need to punt up to our parent - - // now, starting from found item, continue through items - // searching for next visible item - while(iit != iend && !(*iit)->getVisible()) - { - ++iit; - } - - if (iit != iend) - { - // we found an appropriate item - result = (*iit); - } - else - { - // otherwise, scan for next visible folder - while(fit != fend && !(*fit)->getVisible()) - { - ++fit; - } - - // check to see if we have a valid folder - if (fit != fend) - { - // try selecting child element of this folder - if ((*fit)->isOpen()) - { - result = (*fit)->getPreviousFromChild(NULL); - } - else - { - result = (*fit); - } - } - } - - if( !result ) - { - // If there are no siblings or children to go to, recurse up one level in the tree - // which gets back to this folder, which will only be visited if it is a valid, visible item - result = this; - } - - return result; -} - //--------------------------------------------------------------------------- @@ -2494,39 +166,32 @@ void LLCloseAllFoldersFunctor::doItem(LLFolderViewItem* item) ///---------------------------------------------------------------------------- // Default constructor -LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, - const LLRect& rect, const LLUUID& source_id, LLView *parent_view ) : -#if LL_WINDOWS -#pragma warning( push ) -#pragma warning( disable : 4355 ) // warning C4355: 'this' : used in base member initializer list -#endif - LLFolderViewFolder( name, root_folder_icon, this, NULL ), -#if LL_WINDOWS -#pragma warning( pop ) -#endif +LLFolderView::LLFolderView(const Params& p) +: LLFolderViewFolder(p), mScrollContainer( NULL ), mPopupMenuHandle(), mAllowMultiSelect(TRUE), mShowFolderHierarchy(FALSE), - mSourceID(source_id), + mSourceID(p.task_id), mRenameItem( NULL ), mNeedsScroll( FALSE ), - mLastScrollItem( NULL ), + mPinningSelectedItem(FALSE), mNeedsAutoSelect( FALSE ), mAutoSelectOverride(FALSE), mNeedsAutoRename(FALSE), mDebugFilters(FALSE), mSortOrder(LLInventoryFilter::SO_FOLDERS_BY_NAME), // This gets overridden by a pref immediately - mFilter(name), + mFilter( new LLInventoryFilter(p.name) ), mShowSelectionContext(FALSE), mShowSingleSelection(FALSE), mArrangeGeneration(0), - mUserData(NULL), - mSelectCallback(NULL), mSignalSelectCallback(0), mMinWidth(0), - mDragAndDropThisFrame(FALSE) + mDragAndDropThisFrame(FALSE), + mCallbackRegistrar(NULL), + mParentPanel(p.parent_panel) { + LLRect rect = p.rect; LLRect new_rect(rect.mLeft, rect.mBottom + getRect().getHeight(), rect.mLeft + getRect().getWidth(), rect.mBottom); setRect( rect ); reshape(rect.getWidth(), rect.getHeight()); @@ -2543,30 +208,29 @@ LLFolderView::LLFolderView( const std::string& name, LLUIImagePtr root_folder_ic // just make sure the label ("Inventory Folder") never shows up mLabel = LLStringUtil::null; - mRenamer = new LLLineEditor(std::string("ren"), getRect(), LLStringUtil::null, sFont, - DB_INV_ITEM_NAME_STR_LEN, - &LLFolderView::commitRename, - NULL, - NULL, - this, - &LLLineEditor::prevalidatePrintableNotPipe); //mRenamer->setWriteableBgColor(LLColor4::white); // Escape is handled by reverting the rename, not commiting it (default behavior) - mRenamer->setCommitOnFocusLost(TRUE); - mRenamer->setVisible(FALSE); + LLLineEditor::Params params; + params.name("ren"); + params.rect(getRect()); + params.font(sFont); + params.max_length_bytes(DB_INV_ITEM_NAME_STR_LEN); + params.commit_callback.function(boost::bind(&LLFolderView::commitRename, this, _2)); + params.prevalidate_callback(&LLLineEditor::prevalidatePrintableNotPipe); + params.commit_on_focus_lost(true); + params.visible(false); + mRenamer = LLUICtrlFactory::create (params); addChild(mRenamer); // make the popup menu available - LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_inventory.xml", parent_view); + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_inventory.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); if (!menu) { - menu = new LLMenuGL(LLStringUtil::null); + menu = LLUICtrlFactory::getDefaultWidget("inventory_menu"); } - menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); - menu->setVisible(FALSE); + menu->setBackgroundColor(LLUIColorTable::instance().getColor("MenuPopupBgColor")); mPopupMenuHandle = menu->getHandle(); - setTabStop(TRUE); } // Destroys the object @@ -2580,7 +244,6 @@ LLFolderView::~LLFolderView( void ) mScrollContainer = NULL; mRenameItem = NULL; mRenamer = NULL; - gFocusMgr.releaseFocusIfNeeded( this ); if( gEditMenuHandler == this ) { @@ -2603,6 +266,9 @@ LLFolderView::~LLFolderView( void ) mFolders.clear(); mItemMap.clear(); + + delete mFilter; + mFilter = NULL; } BOOL LLFolderView::canFocusChildren() const @@ -2622,11 +288,13 @@ void LLFolderView::checkTreeResortForModelChanged() } } +static LLFastTimer::DeclareTimer FTM_SORT("Sort Inventory"); + void LLFolderView::setSortOrder(U32 order) { if (order != mSortOrder) { - LLFastTimer t(LLFastTimer::FTM_SORT); + LLFastTimer t(FTM_SORT); mSortOrder = order; for (folders_t::iterator iter = mFolders.begin(); @@ -2649,7 +317,7 @@ U32 LLFolderView::getSortOrder() const BOOL LLFolderView::addFolder( LLFolderViewFolder* folder) { // enforce sort order of My Inventory followed by Library - if (folder->getListener()->getUUID() == gInventoryLibraryRoot) + if (folder->getListener()->getUUID() == gInventory.getLibraryRootFolderID()) { mFolders.push_back(folder); } @@ -2670,11 +338,12 @@ void LLFolderView::closeAllFolders() { // Close all the folders setOpenArrangeRecursively(FALSE, LLFolderViewFolder::RECURSE_DOWN); + arrangeAll(); } void LLFolderView::openFolder(const std::string& foldername) { - LLFolderViewFolder* inv = getChild(foldername); + LLFolderViewFolder* inv = findChild(foldername); if (inv) { setSelection(inv, FALSE, FALSE); @@ -2690,19 +359,22 @@ void LLFolderView::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse mIsOpen = TRUE; } +static LLFastTimer::DeclareTimer FTM_ARRANGE("Arrange"); + // This view grows and shinks to enclose all of its children items and folders. S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_generation ) { - LLFastTimer t2(LLFastTimer::FTM_ARRANGE); + LLFastTimer t2(FTM_ARRANGE); - filter_generation = mFilter.getMinRequiredGeneration(); + filter_generation = mFilter->getMinRequiredGeneration(); mMinWidth = 0; mHasVisibleChildren = hasFilteredDescendants(filter_generation); // arrange always finishes, so optimistically set the arrange generation to the most current - mLastArrangeGeneration = mRoot->getArrangeGeneration(); + mLastArrangeGeneration = getRoot()->getArrangeGeneration(); - LLInventoryFilter::EFolderShow show_folder_state = getRoot()->getShowFolderState(); + LLInventoryFilter::EFolderShow show_folder_state = + getRoot()->getFilter()->getShowFolderState(); S32 total_width = LEFT_PAD; S32 running_height = mDebugFilters ? llceil(sSmallFont->getLineHeight()) : 0; @@ -2761,31 +433,32 @@ S32 LLFolderView::arrange( S32* unused_width, S32* unused_height, S32 filter_gen } } - S32 dummy_s32; - BOOL dummy_bool; - S32 min_width; - mScrollContainer->calcVisibleSize( &min_width, &dummy_s32, &dummy_bool, &dummy_bool); - reshape( llmax(min_width, total_width), running_height ); + LLRect scroll_rect = mScrollContainer->getContentWindowRect(); + reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); - S32 new_min_width; - mScrollContainer->calcVisibleSize( &new_min_width, &dummy_s32, &dummy_bool, &dummy_bool); - if (new_min_width != min_width) + LLRect new_scroll_rect = mScrollContainer->getContentWindowRect(); + if (new_scroll_rect.getWidth() != scroll_rect.getWidth()) { - reshape( llmax(min_width, total_width), running_height ); + reshape( llmax(scroll_rect.getWidth(), total_width), running_height ); } + // move item renamer text field to item's new position + updateRenamerPosition(); + mTargetHeight = (F32)target_height; return llround(mTargetHeight); } const std::string LLFolderView::getFilterSubString(BOOL trim) { - return mFilter.getFilterSubString(trim); + return mFilter->getFilterSubString(trim); } +static LLFastTimer::DeclareTimer FTM_FILTER("Filter Inventory"); + void LLFolderView::filter( LLInventoryFilter& filter ) { - LLFastTimer t2(LLFastTimer::FTM_FILTER); + LLFastTimer t2(FTM_FILTER); filter.setFilterCount(llclamp(gSavedSettings.getS32("FilterItemsPerFrame"), 1, 5000)); if (getCompletedFilterGeneration() < filter.getCurrentGeneration()) @@ -2794,19 +467,23 @@ void LLFolderView::filter( LLInventoryFilter& filter ) mMinWidth = 0; LLFolderViewFolder::filter(filter); } + else + { + mFiltered = TRUE; + } } void LLFolderView::reshape(S32 width, S32 height, BOOL called_from_parent) { - S32 min_width = 0; - S32 dummy_height; - BOOL dummy_bool; + LLRect scroll_rect; if (mScrollContainer) { - mScrollContainer->calcVisibleSize( &min_width, &dummy_height, &dummy_bool, &dummy_bool); + scroll_rect = mScrollContainer->getContentWindowRect(); } - width = llmax(mMinWidth, min_width); + width = llmax(mMinWidth, scroll_rect.getWidth()); LLView::reshape(width, height, called_from_parent); + + mReshapeSignal(mSelectedItems, FALSE); } void LLFolderView::addToSelectionList(LLFolderViewItem* item) @@ -2871,7 +548,7 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, if( selection && take_keyboard_focus) { - setFocus(TRUE); + mParentPanel->setFocus(TRUE); } // clear selection down here because change of keyboard focus can potentially @@ -2896,6 +573,30 @@ BOOL LLFolderView::setSelection(LLFolderViewItem* selection, BOOL openitem, return rv; } +void LLFolderView::setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus) +{ + LLFolderViewItem* itemp = getItemByID(obj_id); + if(itemp && itemp->getListener()) + { + itemp->arrangeAndSet(TRUE, take_keyboard_focus); + mSelectThisID.setNull(); + return; + } + else + { + // save the desired item to be selected later (if/when ready) + mSelectThisID = obj_id; + } +} + +void LLFolderView::updateSelection() +{ + if (mSelectThisID.notNull()) + { + setSelectionByID(mSelectThisID, false); + } +} + BOOL LLFolderView::changeSelection(LLFolderViewItem* selection, BOOL selected) { BOOL rv = FALSE; @@ -2970,7 +671,7 @@ void LLFolderView::sanitizeSelection() LLFolderViewItem* original_selected_item = getCurSelectedItem(); // Cache "Show all folders" filter setting - BOOL show_all_folders = (getRoot()->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS); + BOOL show_all_folders = (getRoot()->getFilter()->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS); std::vector items_to_remove; selected_items_t::iterator item_iter; @@ -3060,7 +761,7 @@ void LLFolderView::sanitizeSelection() else { // nothing selected to start with, so pick "My Inventory" as best guess - new_selection = getItemByID(gAgent.getInventoryRootID()); + new_selection = getItemByID(gInventory.getRootFolderID()); } if (new_selection) @@ -3077,6 +778,7 @@ void LLFolderView::clearSelection() recursiveDeselect(FALSE); mSelectedItems.clear(); } + mSelectThisID.setNull(); } BOOL LLFolderView::getSelectionList(std::set &selection) @@ -3113,24 +815,21 @@ BOOL LLFolderView::startDrag(LLToolDragAndDrop::ESource source) return can_drag; } -void LLFolderView::commitRename( LLUICtrl* renamer, void* user_data ) +void LLFolderView::commitRename( const LLSD& data ) { - LLFolderView* root = reinterpret_cast(user_data); - if( root ) - { - root->finishRenamingItem(); - } + finishRenamingItem(); } void LLFolderView::draw() { + static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", LLColor4::white); if (mDebugFilters) { std::string current_filter_string = llformat("Current Filter: %d, Least Filter: %d, Auto-accept Filter: %d", - mFilter.getCurrentGeneration(), mFilter.getMinRequiredGeneration(), mFilter.getMustPassGeneration()); + mFilter->getCurrentGeneration(), mFilter->getMinRequiredGeneration(), mFilter->getMustPassGeneration()); sSmallFont->renderUTF8(current_filter_string, 0, 2, getRect().getHeight() - sSmallFont->getLineHeight(), LLColor4(0.5f, 0.5f, 0.8f, 1.f), - LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE ); + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } // if cursor has moved off of me during drag and drop @@ -3139,10 +838,6 @@ void LLFolderView::draw() { closeAutoOpenedFolders(); } - if(this == gFocusMgr.getKeyboardFocus() && !getVisible()) - { - gFocusMgr.setKeyboardFocus( NULL ); - } // while dragging, update selection rendering to reflect single/multi drag status if (LLToolDragAndDrop::getInstance()->hasMouseCapture()) @@ -3168,21 +863,22 @@ void LLFolderView::draw() mSearchString.clear(); } - if (hasVisibleChildren() || getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) + if (hasVisibleChildren() + || mFilter->getShowFolderState() == LLInventoryFilter::SHOW_ALL_FOLDERS) { mStatusText.clear(); } else { - if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter.getMinRequiredGeneration()) + if (gInventory.backgroundFetchActive() || mCompletedFilterGeneration < mFilter->getMinRequiredGeneration()) { - mStatusText = std::string("Searching..."); // *TODO:translate - sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE ); + mStatusText = LLTrans::getString("Searching"); + sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } else { - mStatusText = std::string("No matching items found in inventory."); // *TODO:translate - sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE ); + mStatusText = LLTrans::getString("InventoryNoMatchingItems"); + sFont->renderUTF8(mStatusText, 0, 2, 1, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::TOP, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE ); } } @@ -3280,11 +976,11 @@ void LLFolderView::removeSelectedItems( void ) // change selection on successful delete if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), gFocusMgr.childHasKeyboardFocus(this)); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); } else { - setSelectionFromRoot(NULL, gFocusMgr.childHasKeyboardFocus(this)); + setSelectionFromRoot(NULL, mParentPanel->hasFocus()); } } } @@ -3310,11 +1006,11 @@ void LLFolderView::removeSelectedItems( void ) } if (new_selection) { - setSelectionFromRoot(new_selection, new_selection->isOpen(), gFocusMgr.childHasKeyboardFocus(this)); + setSelectionFromRoot(new_selection, new_selection->isOpen(), mParentPanel->hasFocus()); } else { - setSelectionFromRoot(NULL, gFocusMgr.childHasKeyboardFocus(this)); + setSelectionFromRoot(NULL, mParentPanel->hasFocus()); } for(S32 i = 0; i < count; ++i) @@ -3347,11 +1043,8 @@ void LLFolderView::openSelectedItems( void ) } else { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLMultiPreview* multi_previewp = new LLMultiPreview(LLRect(left, top, left + 300, top - 100)); - gFloaterView->getNewFloaterPosition(&left, &top); - LLMultiProperties* multi_propertiesp = new LLMultiProperties(LLRect(left, top, left + 300, top - 100)); + LLMultiPreview* multi_previewp = new LLMultiPreview(); + LLMultiProperties* multi_propertiesp = new LLMultiProperties(); selected_items_t::iterator item_it; for (item_it = mSelectedItems.begin(); item_it != mSelectedItems.end(); ++item_it) @@ -3371,8 +1064,8 @@ void LLFolderView::openSelectedItems( void ) LLFloater::setFloaterHost(NULL); // *NOTE: LLMulti* will safely auto-delete when open'd // without any children. - multi_previewp->open(); - multi_propertiesp->open(); + multi_previewp->openFloater(LLSD()); + multi_propertiesp->openFloater(LLSD()); } } } @@ -3389,10 +1082,7 @@ void LLFolderView::propertiesSelectedItems( void ) } else { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - - LLMultiProperties* multi_propertiesp = new LLMultiProperties(LLRect(left, top, left + 100, top - 100)); + LLMultiProperties* multi_propertiesp = new LLMultiProperties(); LLFloater::setFloaterHost(multi_propertiesp); @@ -3403,11 +1093,21 @@ void LLFolderView::propertiesSelectedItems( void ) } LLFloater::setFloaterHost(NULL); - multi_propertiesp->open(); /* Flawfinder: ignore */ + multi_propertiesp->openFloater(LLSD()); } } } +void LLFolderView::changeType(LLInventoryModel *model, LLAssetType::EType new_folder_type) +{ + LLFolderBridge *folder_bridge = LLFolderBridge::sSelf; + + if (!folder_bridge) return; + LLViewerInventoryCategory *cat = folder_bridge->getCategory(); + if (!cat) return; + cat->changeType(new_folder_type); +} + void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) { if (mAutoOpenItems.check() == item || mAutoOpenItems.getDepth() >= (U32)AUTO_OPEN_STACK_DEPTH) @@ -3429,7 +1129,9 @@ void LLFolderView::autoOpenItem( LLFolderViewFolder* item ) mAutoOpenItems.push(item); item->setOpen(TRUE); - scrollToShowItem(item); + LLRect content_rect = mScrollContainer->getContentWindowRect(); + LLRect constraint_rect(0,content_rect.getHeight(), content_rect.getWidth(), 0); + scrollToShowItem(item, constraint_rect); } void LLFolderView::closeAutoOpenedFolders() @@ -3608,47 +1310,19 @@ void LLFolderView::startRenamingSelectedItem( void ) { mRenameItem = item; - S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD - 1 + item->getIndentation(); - S32 y = llfloor(item->getRect().getHeight()-sFont->getLineHeight()-2); - item->localPointToScreen( x, y, &x, &y ); - screenPointToLocal( x, y, &x, &y ); - mRenamer->setOrigin( x, y ); + updateRenamerPosition(); - S32 scroller_height = 0; - S32 scroller_width = gViewerWindow->getWindowWidth(); - BOOL dummy_bool; - if (mScrollContainer) - { - mScrollContainer->calcVisibleSize( &scroller_width, &scroller_height, &dummy_bool, &dummy_bool); - } - - S32 width = llmax(llmin(item->getRect().getWidth() - x, scroller_width - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); - S32 height = llfloor(sFont->getLineHeight() + RENAME_HEIGHT_PAD); - mRenamer->reshape( width, height, TRUE ); mRenamer->setText(item->getName()); mRenamer->selectAll(); mRenamer->setVisible( TRUE ); // set focus will fail unless item is visible mRenamer->setFocus( TRUE ); - mRenamer->setLostTopCallback(onRenamerLost); + mRenamer->setTopLostCallback(onRenamerLost); gFocusMgr.setTopCtrl( mRenamer ); } } -void LLFolderView::setFocus(BOOL focus) -{ - if (focus) - { - if(!hasFocus()) - { - gEditMenuHandler = this; - } - } - - LLFolderViewFolder::setFocus(focus); -} - BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; @@ -3851,7 +1525,7 @@ BOOL LLFolderView::handleKeyHere( KEY key, MASK mask ) break; } - if (!handled && hasFocus()) + if (!handled && mParentPanel->hasFocus()) { if (key == KEY_BACKSPACE) { @@ -3940,20 +1614,11 @@ BOOL LLFolderView::handleMouseDown( S32 x, S32 y, MASK mask ) mKeyboardSelection = FALSE; mSearchString.clear(); - setFocus(TRUE); + mParentPanel->setFocus(TRUE); return LLView::handleMouseDown( x, y, mask ); } -void LLFolderView::onFocusLost( ) -{ - if( gEditMenuHandler == this ) - { - gEditMenuHandler = NULL; - } - LLUICtrl::onFocusLost(); -} - BOOL LLFolderView::search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward) { // get first selected item @@ -4030,13 +1695,15 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) { // all user operations move keyboard focus to inventory // this way, we know when to stop auto-updating a search - setFocus(TRUE); + mParentPanel->setFocus(TRUE); BOOL handled = childrenHandleRightMouseDown(x, y, mask) != NULL; S32 count = mSelectedItems.size(); LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if(handled && (count > 0) && menu) { + if (mCallbackRegistrar) + mCallbackRegistrar->pushScope(); //menu->empty(); const LLView::child_list_t *list = menu->getChildList(); @@ -4056,9 +1723,10 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask ) flags = 0x0; } - menu->arrange(); menu->updateParent(LLMenuGL::sMenuContainer); LLMenuGL::showPopup(this, menu, x, y); + if (mCallbackRegistrar) + mCallbackRegistrar->popScope(); } else { @@ -4127,49 +1795,41 @@ void LLFolderView::scrollToShowSelection() // If the parent is scroll containter, scroll it to make the selection // is maximally visible. -void LLFolderView::scrollToShowItem(LLFolderViewItem* item) +void LLFolderView::scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect) { + if (!mScrollContainer) return; + // don't scroll to items when mouse is being used to scroll/drag and drop if (gFocusMgr.childHasMouseCapture(mScrollContainer)) { mNeedsScroll = FALSE; return; } - if(item && mScrollContainer) + + // if item exists and is in visible portion of parent folder... + if(item) { - LLRect local_rect = item->getRect(); + LLRect local_rect = item->getLocalRect(); LLRect item_scrolled_rect; // item position relative to display area of scroller + LLRect visible_doc_rect = mScrollContainer->getVisibleContentRect(); S32 icon_height = mIcon.isNull() ? 0 : mIcon->getHeight(); S32 label_height = llround(sFont->getLineHeight()); // when navigating with keyboard, only move top of folders on screen, otherwise show whole folder - S32 max_height_to_show = gFocusMgr.childHasKeyboardFocus(this) ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); - item->localPointToOtherView(item->getIndentation(), llmax(0, local_rect.getHeight() - max_height_to_show), &item_scrolled_rect.mLeft, &item_scrolled_rect.mBottom, mScrollContainer); - item->localPointToOtherView(local_rect.getWidth(), local_rect.getHeight(), &item_scrolled_rect.mRight, &item_scrolled_rect.mTop, mScrollContainer); + S32 max_height_to_show = mScrollContainer->hasFocus() ? (llmax( icon_height, label_height ) + ICON_PAD) : local_rect.getHeight(); + + // get portion of item that we want to see... + LLRect item_local_rect = LLRect(item->getIndentation(), + local_rect.getHeight(), + llmin(MIN_ITEM_WIDTH_VISIBLE, local_rect.getWidth()), + llmax(0, local_rect.getHeight() - max_height_to_show)); - item_scrolled_rect.mRight = llmin(item_scrolled_rect.mLeft + MIN_ITEM_WIDTH_VISIBLE, item_scrolled_rect.mRight); - LLCoordGL scroll_offset(-mScrollContainer->getBorderWidth() - item_scrolled_rect.mLeft, - mScrollContainer->getRect().getHeight() - item_scrolled_rect.mTop - 1); + LLRect item_doc_rect; - S32 max_scroll_offset = getVisibleRect().getHeight() - item_scrolled_rect.getHeight(); - if (item != mLastScrollItem || // if we're scrolling to focus on a new item - // or the item has just appeared on screen and it wasn't onscreen before - (scroll_offset.mY > 0 && scroll_offset.mY < max_scroll_offset && - (mLastScrollOffset.mY < 0 || mLastScrollOffset.mY > max_scroll_offset))) - { - // we now have a position on screen that we want to keep stable - // offset of selection relative to top of visible area - mLastScrollOffset = scroll_offset; - mLastScrollItem = item; - } + item->localRectToOtherView(item_local_rect, &item_doc_rect, this); - mScrollContainer->scrollToShowRect( item_scrolled_rect, mLastScrollOffset ); + mScrollContainer->scrollToShowRect( item_doc_rect, constraint_rect ); - // after scrolling, store new offset - // in case we don't have room to maintain the original position - LLCoordGL new_item_left_top; - item->localPointToOtherView(item->getIndentation(), item->getRect().getHeight(), &new_item_left_top.mX, &new_item_left_top.mY, mScrollContainer); - mLastScrollOffset.set(-mScrollContainer->getBorderWidth() - new_item_left_top.mX, mScrollContainer->getRect().getHeight() - new_item_left_top.mY - 1); } } @@ -4232,11 +1892,90 @@ LLFolderViewItem* LLFolderView::getItemByID(const LLUUID& id) return NULL; } +bool LLFolderView::doToSelected(LLInventoryModel* model, const LLSD& userdata) +{ + std::string action = userdata.asString(); + + if ("rename" == action) + { + startRenamingSelectedItem(); + return true; + } + if ("delete" == action) + { + removeSelectedItems(); + return true; + } + + if ("copy" == action) + { + LLInventoryClipboard::instance().reset(); + } + + static const std::string change_folder_string = "change_folder_type_"; + if (action.length() > change_folder_string.length() && + (action.compare(0,change_folder_string.length(),"change_folder_type_") == 0)) + { + LLAssetType::EType new_folder_type = LLFolderType::lookupTypeFromXUIName(action.substr(change_folder_string.length())); + changeType(model, new_folder_type); + return true; + } + + + std::set selected_items; + getSelectionList(selected_items); + + LLMultiPreview* multi_previewp = NULL; + LLMultiProperties* multi_propertiesp = NULL; + + if (("task_open" == action || "open" == action) && selected_items.size() > 1) + { + multi_previewp = new LLMultiPreview(); + gFloaterView->addChild(multi_previewp); + + LLFloater::setFloaterHost(multi_previewp); + + } + else if (("task_properties" == action || "properties" == action) && selected_items.size() > 1) + { + multi_propertiesp = new LLMultiProperties(); + gFloaterView->addChild(multi_propertiesp); + + LLFloater::setFloaterHost(multi_propertiesp); + } + + std::set::iterator set_iter; + + for (set_iter = selected_items.begin(); set_iter != selected_items.end(); ++set_iter) + { + LLFolderViewItem* folder_item = getItemByID(*set_iter); + if(!folder_item) continue; + LLInvFVBridge* bridge = (LLInvFVBridge*)folder_item->getListener(); + if(!bridge) continue; + + bridge->performAction(this, model, action); + } + + LLFloater::setFloaterHost(NULL); + if (multi_previewp) + { + multi_previewp->openFloater(LLSD()); + } + else if (multi_propertiesp) + { + multi_propertiesp->openFloater(LLSD()); + } + + return true; +} + +static LLFastTimer::DeclareTimer FTM_AUTO_SELECT("Open and Select"); +static LLFastTimer::DeclareTimer FTM_INVENTORY("Inventory"); // Main idle routine void LLFolderView::doIdle() { - LLFastTimer t2(LLFastTimer::FTM_INVENTORY); + LLFastTimer t2(FTM_INVENTORY); BOOL debug_filters = gSavedSettings.getBOOL("DebugInventoryFilters"); if (debug_filters != getDebugFilters()) @@ -4245,12 +1984,12 @@ void LLFolderView::doIdle() arrangeAll(); } - mFilter.clearModified(); - BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter.getCurrentGeneration() && - mFilter.isNotDefault(); + mFilter->clearModified(); + BOOL filter_modified_and_active = mCompletedFilterGeneration < mFilter->getCurrentGeneration() && + mFilter->isNotDefault(); mNeedsAutoSelect = filter_modified_and_active && !(gFocusMgr.childHasKeyboardFocus(this) || gFocusMgr.getMouseCapture()); - + // filter to determine visiblity before arranging filterFromRoot(); @@ -4261,7 +2000,7 @@ void LLFolderView::doIdle() // potentially changed if (mNeedsAutoSelect) { - LLFastTimer t3(LLFastTimer::FTM_AUTO_SELECT); + LLFastTimer t3(FTM_AUTO_SELECT); // select new item only if a filtered item not currently selected LLFolderViewItem* selected_itemp = mSelectedItems.empty() ? NULL : mSelectedItems.back(); if ((!selected_itemp || !selected_itemp->getFiltered()) && !mAutoSelectOverride) @@ -4273,6 +2012,59 @@ void LLFolderView::doIdle() scrollToShowSelection(); } + // during filtering process, try to pin selected item's location on screen + // this will happen when searching your inventory and when new items arrive + if (filter_modified_and_active) + { + // calculate rectangle to pin item to at start of animated rearrange + if (!mPinningSelectedItem && !mSelectedItems.empty()) + { + // lets pin it! + mPinningSelectedItem = TRUE; + + LLRect visible_content_rect = mScrollContainer->getVisibleContentRect(); + LLFolderViewItem* selected_item = mSelectedItems.back(); + + LLRect item_rect; + selected_item->localRectToOtherView(selected_item->getLocalRect(), &item_rect, this); + // if item is visible in scrolled region + if (visible_content_rect.overlaps(item_rect)) + { + // then attempt to keep it in same place on screen + mScrollConstraintRect = item_rect; + mScrollConstraintRect.translate(-visible_content_rect.mLeft, -visible_content_rect.mBottom); + } + else + { + // otherwise we just want it onscreen somewhere + LLRect content_rect = mScrollContainer->getContentWindowRect(); + mScrollConstraintRect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + } + } + else + { + // stop pinning selected item after folders stop rearranging + if (!needsArrange()) + { + mPinningSelectedItem = FALSE; + } + } + + LLRect constraint_rect; + if (mPinningSelectedItem) + { + // use last known constraint rect for pinned item + constraint_rect = mScrollConstraintRect; + } + else + { + // during normal use (page up/page down, etc), just try to fit item on screen + LLRect content_rect = mScrollContainer->getContentWindowRect(); + constraint_rect.setOriginAndSize(0, 0, content_rect.getWidth(), content_rect.getHeight()); + } + + BOOL is_visible = isInVisibleChain(); if ( is_visible ) @@ -4286,20 +2078,20 @@ void LLFolderView::doIdle() if (mSelectedItems.size() && mNeedsScroll) { - scrollToShowItem(mSelectedItems.back()); + scrollToShowItem(mSelectedItems.back(), constraint_rect); // continue scrolling until animated layout change is done - if (getCompletedFilterGeneration() >= mFilter.getMinRequiredGeneration() && - (!needsArrange() || !is_visible)) + if (!filter_modified_and_active + && (!needsArrange() || !is_visible)) { mNeedsScroll = FALSE; } } - if (mSignalSelectCallback && mSelectCallback) + if (mSignalSelectCallback) { //RN: we use keyboard focus as a proxy for user-explicit actions BOOL take_keyboard_focus = (mSignalSelectCallback == SIGNAL_KEYBOARD_FOCUS); - mSelectCallback(mSelectedItems, take_keyboard_focus, mUserData); + mSelectSignal(mSelectedItems, take_keyboard_focus); } mSignalSelectCallback = FALSE; } @@ -4315,7 +2107,6 @@ void LLFolderView::idle(void* user_data) } } - void LLFolderView::dumpSelectionInformation() { llinfos << "LLFolderView::dumpSelectionInformation()" << llendl; @@ -4328,81 +2119,77 @@ void LLFolderView::dumpSelectionInformation() llinfos << "****************************************" << llendl; } +void LLFolderView::updateRenamerPosition() +{ + if(mRenameItem) + { + S32 x = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD - 1 + mRenameItem->getIndentation(); + S32 y = llfloor(mRenameItem->getRect().getHeight()-sFont->getLineHeight()-2); + mRenameItem->localPointToScreen( x, y, &x, &y ); + screenPointToLocal( x, y, &x, &y ); + mRenamer->setOrigin( x, y ); + + LLRect scroller_rect(0, 0, gViewerWindow->getWindowWidth(), 0); + if (mScrollContainer) + { + scroller_rect = mScrollContainer->getContentWindowRect(); + } + + S32 width = llmax(llmin(mRenameItem->getRect().getWidth() - x, scroller_rect.getWidth() - x - getRect().mLeft), MINIMUM_RENAMER_WIDTH); + S32 height = llfloor(sFont->getLineHeight() + RENAME_HEIGHT_PAD); + mRenamer->reshape( width, height, TRUE ); + } +} + + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- -bool LLInventorySort::updateSort(U32 order) -{ - if (order != mSortOrder) - { - mSortOrder = order; - mByDate = (order & LLInventoryFilter::SO_DATE); - mSystemToTop = (order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); - mFoldersByName = (order & LLInventoryFilter::SO_FOLDERS_BY_NAME); - return true; - } - return false; -} - -bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b) -{ - // We sort by name if we aren't sorting by date - // OR if these are folders and we are sorting folders by name. - bool by_name = (!mByDate - || (mFoldersByName - && (a->getSortGroup() != SG_ITEM))); - - if (a->getSortGroup() != b->getSortGroup()) - { - if (mSystemToTop) - { - // Group order is System Folders, Trash, Normal Folders, Items - return (a->getSortGroup() < b->getSortGroup()); - } - else if (mByDate) - { - // Trash needs to go to the bottom if we are sorting by date - if ( (a->getSortGroup() == SG_TRASH_FOLDER) - || (b->getSortGroup() == SG_TRASH_FOLDER)) - { - return (b->getSortGroup() == SG_TRASH_FOLDER); - } - } - } - - if (by_name) - { - S32 compare = LLStringUtil::compareDict(a->getLabel(), b->getLabel()); - if (0 == compare) - { - return (a->getCreationDate() > b->getCreationDate()); - } - else - { - return (compare < 0); - } - } - else - { - // BUG: This is very very slow. The getCreationDate() is log n in number - // of inventory items. - time_t first_create = a->getCreationDate(); - time_t second_create = b->getCreationDate(); - if (first_create == second_create) - { - return (LLStringUtil::compareDict(a->getLabel(), b->getLabel()) < 0); - } - else - { - return (first_create > second_create); - } - } -} //static -void LLFolderView::onRenamerLost( LLUICtrl* renamer, void* user_data) +void LLFolderView::onRenamerLost( LLFocusableElement* renamer, void* user_data) { - renamer->setVisible(FALSE); + LLUICtrl* uictrl = dynamic_cast(renamer); + if (uictrl) + { + uictrl->setVisible(FALSE); + } +} + +LLInventoryFilter* LLFolderView::getFilter() +{ + return mFilter; +} + +void LLFolderView::setFilterPermMask( PermissionMask filter_perm_mask ) +{ + mFilter->setFilterPermissions(filter_perm_mask); +} + +U32 LLFolderView::getFilterTypes() const +{ + return mFilter->getFilterTypes(); +} + +PermissionMask LLFolderView::getFilterPermissions() const +{ + return mFilter->getFilterPermissions(); +} + +// JAMESDEBUG +//LLInventoryFilter::EFolderShow LLFolderView::getShowFolderState() +//{ +// return mFilter->getShowFolderState(); +//} + +BOOL LLFolderView::isFilterModified() +{ + return mFilter->isNotDefault(); +} + +BOOL LLFolderView::getAllowMultiSelect() +{ + return mAllowMultiSelect; } void delete_selected_item(void* user_data) @@ -4449,585 +2236,3 @@ void properties_selected_items(void* user_data) fv->propertiesSelectedItems(); } } - -///---------------------------------------------------------------------------- -/// Class LLFolderViewEventListener -///---------------------------------------------------------------------------- - -void LLFolderViewEventListener::arrangeAndSet(LLFolderViewItem* focus, - BOOL set_selection, - BOOL take_keyboard_focus) -{ - if(!focus) return; - LLFolderView* root = focus->getRoot(); - focus->getParentFolder()->requestArrange(); - if(set_selection) - { - focus->setSelectionFromRoot(focus, TRUE, take_keyboard_focus); - if(root) - { - root->scrollToShowSelection(); - } - } -} - - -///---------------------------------------------------------------------------- -/// Class LLInventoryFilter -///---------------------------------------------------------------------------- -LLInventoryFilter::LLInventoryFilter(const std::string& name) : - mName(name), - mModified(FALSE), - mNeedTextRebuild(TRUE) -{ - mFilterOps.mFilterTypes = 0xffffffff; - mFilterOps.mMinDate = time_min(); - mFilterOps.mMaxDate = time_max(); - mFilterOps.mHoursAgo = 0; - mFilterOps.mShowFolderState = SHOW_NON_EMPTY_FOLDERS; - mFilterOps.mPermissions = PERM_NONE; - - mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately - - mSubStringMatchOffset = 0; - mFilterSubString.clear(); - mFilterGeneration = 0; - mMustPassGeneration = S32_MAX; - mMinRequiredGeneration = 0; - mFilterCount = 0; - mNextFilterGeneration = mFilterGeneration + 1; - - mLastLogoff = gSavedPerAccountSettings.getU32("LastLogoff"); - mFilterBehavior = FILTER_NONE; - - // copy mFilterOps into mDefaultFilterOps - markDefault(); -} - -LLInventoryFilter::~LLInventoryFilter() -{ -} - -BOOL LLInventoryFilter::check(LLFolderViewItem* item) -{ - time_t earliest; - - earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; - if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) - { - earliest = mFilterOps.mMinDate; - } - else if (!mFilterOps.mHoursAgo) - { - earliest = 0; - } - LLFolderViewEventListener* listener = item->getListener(); - mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; - BOOL passed = (0x1 << listener->getInventoryType() & mFilterOps.mFilterTypes || listener->getInventoryType() == LLInventoryType::IT_NONE) - && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) - && ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions) - && (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); - return passed; -} - -const std::string LLInventoryFilter::getFilterSubString(BOOL trim) -{ - return mFilterSubString; -} - -std::string::size_type LLInventoryFilter::getStringMatchOffset() const -{ - return mSubStringMatchOffset; -} - -// has user modified default filter params? -BOOL LLInventoryFilter::isNotDefault() -{ - return mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes - || mFilterSubString.size() - || mFilterOps.mPermissions != mDefaultFilterOps.mPermissions - || mFilterOps.mMinDate != mDefaultFilterOps.mMinDate - || mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate - || mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo; -} - -BOOL LLInventoryFilter::isActive() -{ - return mFilterOps.mFilterTypes != 0xffffffff - || mFilterSubString.size() - || mFilterOps.mPermissions != PERM_NONE - || mFilterOps.mMinDate != time_min() - || mFilterOps.mMaxDate != time_max() - || mFilterOps.mHoursAgo != 0; -} - -BOOL LLInventoryFilter::isModified() -{ - return mModified; -} - -BOOL LLInventoryFilter::isModifiedAndClear() -{ - BOOL ret = mModified; - mModified = FALSE; - return ret; -} - -void LLInventoryFilter::setFilterTypes(U32 types) -{ - if (mFilterOps.mFilterTypes != types) - { - // keep current items only if no type bits getting turned off - BOOL fewer_bits_set = (mFilterOps.mFilterTypes & ~types); - BOOL more_bits_set = (~mFilterOps.mFilterTypes & types); - - mFilterOps.mFilterTypes = types; - if (more_bits_set && fewer_bits_set) - { - // neither less or more restrive, both simultaneously - // so we need to filter from scratch - setModified(FILTER_RESTART); - } - else if (more_bits_set) - { - // target is only one of all requested types so more type bits == less restrictive - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (fewer_bits_set) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - - } -} - -void LLInventoryFilter::setFilterSubString(const std::string& string) -{ - if (mFilterSubString != string) - { - // hitting BACKSPACE, for example - BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string); - // appending new characters - BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); - mFilterSubString = string; - LLStringUtil::toUpper(mFilterSubString); - LLStringUtil::trimHead(mFilterSubString); - - if (less_restrictive) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (more_restrictive) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - else - { - setModified(FILTER_RESTART); - } - } -} - -void LLInventoryFilter::setFilterPermissions(PermissionMask perms) -{ - if (mFilterOps.mPermissions != perms) - { - // keep current items only if no perm bits getting turned off - BOOL fewer_bits_set = (mFilterOps.mPermissions & ~perms); - BOOL more_bits_set = (~mFilterOps.mPermissions & perms); - mFilterOps.mPermissions = perms; - - if (more_bits_set && fewer_bits_set) - { - setModified(FILTER_RESTART); - } - else if (more_bits_set) - { - // target must have all requested permission bits, so more bits == more restrictive - setModified(FILTER_MORE_RESTRICTIVE); - } - else if (fewer_bits_set) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - } -} - -void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) -{ - mFilterOps.mHoursAgo = 0; - if (mFilterOps.mMinDate != min_date) - { - mFilterOps.mMinDate = min_date; - setModified(); - } - if (mFilterOps.mMaxDate != llmax(mFilterOps.mMinDate, max_date)) - { - mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); - setModified(); - } -} - -void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) -{ - if (sl && !isSinceLogoff()) - { - setDateRange(mLastLogoff, time_max()); - setModified(); - } - if (!sl && isSinceLogoff()) - { - setDateRange(0, time_max()); - setModified(); - } -} - -BOOL LLInventoryFilter::isSinceLogoff() -{ - return (mFilterOps.mMinDate == (time_t)mLastLogoff) && - (mFilterOps.mMaxDate == time_max()); -} - -void LLInventoryFilter::setHoursAgo(U32 hours) -{ - if (mFilterOps.mHoursAgo != hours) - { - // *NOTE: need to cache last filter time, in case filter goes stale - BOOL less_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours > mFilterOps.mHoursAgo); - BOOL more_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours <= mFilterOps.mHoursAgo); - mFilterOps.mHoursAgo = hours; - mFilterOps.mMinDate = time_min(); - mFilterOps.mMaxDate = time_max(); - if (less_restrictive) - { - setModified(FILTER_LESS_RESTRICTIVE); - } - else if (more_restrictive) - { - setModified(FILTER_MORE_RESTRICTIVE); - } - else - { - setModified(FILTER_RESTART); - } - } -} -void LLInventoryFilter::setShowFolderState(EFolderShow state) -{ - if (mFilterOps.mShowFolderState != state) - { - mFilterOps.mShowFolderState = state; - if (state == SHOW_NON_EMPTY_FOLDERS) - { - // showing fewer folders than before - setModified(FILTER_MORE_RESTRICTIVE); - } - else if (state == SHOW_ALL_FOLDERS) - { - // showing same folders as before and then some - setModified(FILTER_LESS_RESTRICTIVE); - } - else - { - setModified(); - } - } -} - -void LLInventoryFilter::setSortOrder(U32 order) -{ - if (mOrder != order) - { - mOrder = order; - setModified(); - } -} - -void LLInventoryFilter::markDefault() -{ - mDefaultFilterOps = mFilterOps; -} - -void LLInventoryFilter::resetDefault() -{ - mFilterOps = mDefaultFilterOps; - setModified(); -} - -void LLInventoryFilter::setModified(EFilterBehavior behavior) -{ - mModified = TRUE; - mNeedTextRebuild = TRUE; - mFilterGeneration = mNextFilterGeneration++; - - if (mFilterBehavior == FILTER_NONE) - { - mFilterBehavior = behavior; - } - else if (mFilterBehavior != behavior) - { - // trying to do both less restrictive and more restrictive filter - // basically means restart from scratch - mFilterBehavior = FILTER_RESTART; - } - - if (isNotDefault()) - { - // if not keeping current filter results, update last valid as well - switch(mFilterBehavior) - { - case FILTER_RESTART: - mMustPassGeneration = mFilterGeneration; - mMinRequiredGeneration = mFilterGeneration; - break; - case FILTER_LESS_RESTRICTIVE: - mMustPassGeneration = mFilterGeneration; - break; - case FILTER_MORE_RESTRICTIVE: - mMinRequiredGeneration = mFilterGeneration; - // must have passed either current filter generation (meaningless, as it hasn't been run yet) - // or some older generation, so keep the value - mMustPassGeneration = llmin(mMustPassGeneration, mFilterGeneration); - break; - default: - llerrs << "Bad filter behavior specified" << llendl; - } - } - else - { - // shortcut disabled filters to show everything immediately - mMinRequiredGeneration = 0; - mMustPassGeneration = S32_MAX; - } -} - -BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t) -{ - return mFilterOps.mFilterTypes & (0x01 << t); -} - -std::string LLInventoryFilter::getFilterText() -{ - if (!mNeedTextRebuild) - { - return mFilterText; - } - - mNeedTextRebuild = FALSE; - std::string filtered_types; - std::string not_filtered_types; - BOOL filtered_by_type = FALSE; - BOOL filtered_by_all_types = TRUE; - S32 num_filter_types = 0; - mFilterText.clear(); - - if (isFilterWith(LLInventoryType::IT_ANIMATION)) - { - filtered_types += " Animations,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Animations,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_CALLINGCARD)) - { - filtered_types += " Calling Cards,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Calling Cards,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_WEARABLE)) - { - filtered_types += " Clothing,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Clothing,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_GESTURE)) - { - filtered_types += " Gestures,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Gestures,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_LANDMARK)) - { - filtered_types += " Landmarks,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Landmarks,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_NOTECARD)) - { - filtered_types += " Notecards,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Notecards,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_OBJECT) && isFilterWith(LLInventoryType::IT_ATTACHMENT)) - { - filtered_types += " Objects,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Objects,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_LSL)) - { - filtered_types += " Scripts,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Scripts,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_SOUND)) - { - filtered_types += " Sounds,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Sounds,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_TEXTURE)) - { - filtered_types += " Textures,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Textures,"; - filtered_by_all_types = FALSE; - } - - if (isFilterWith(LLInventoryType::IT_SNAPSHOT)) - { - filtered_types += " Snapshots,"; - filtered_by_type = TRUE; - num_filter_types++; - } - else - { - not_filtered_types += " Snapshots,"; - filtered_by_all_types = FALSE; - } - - if (!gInventory.backgroundFetchActive() && filtered_by_type && !filtered_by_all_types) - { - mFilterText += " - "; - if (num_filter_types < 5) - { - mFilterText += filtered_types; - } - else - { - mFilterText += "No "; - mFilterText += not_filtered_types; - } - // remove the ',' at the end - mFilterText.erase(mFilterText.size() - 1, 1); - } - - if (isSinceLogoff()) - { - mFilterText += " - Since Logoff"; - } - return mFilterText; -} - -void LLInventoryFilter::toLLSD(LLSD& data) -{ - data["filter_types"] = (LLSD::Integer)getFilterTypes(); - data["min_date"] = (LLSD::Integer)getMinDate(); - data["max_date"] = (LLSD::Integer)getMaxDate(); - data["hours_ago"] = (LLSD::Integer)getHoursAgo(); - data["show_folder_state"] = (LLSD::Integer)getShowFolderState(); - data["permissions"] = (LLSD::Integer)getFilterPermissions(); - data["substring"] = (LLSD::String)getFilterSubString(); - data["sort_order"] = (LLSD::Integer)getSortOrder(); - data["since_logoff"] = (LLSD::Boolean)isSinceLogoff(); -} - -void LLInventoryFilter::fromLLSD(LLSD& data) -{ - if(data.has("filter_types")) - { - setFilterTypes((U32)data["filter_types"].asInteger()); - } - - if(data.has("min_date") && data.has("max_date")) - { - setDateRange(data["min_date"].asInteger(), data["max_date"].asInteger()); - } - - if(data.has("hours_ago")) - { - setHoursAgo((U32)data["hours_ago"].asInteger()); - } - - if(data.has("show_folder_state")) - { - setShowFolderState((EFolderShow)data["show_folder_state"].asInteger()); - } - - if(data.has("permissions")) - { - setFilterPermissions((PermissionMask)data["permissions"].asInteger()); - } - - if(data.has("substring")) - { - setFilterSubString(std::string(data["substring"].asString())); - } - - if(data.has("sort_order")) - { - setSortOrder((U32)data["sort_order"].asInteger()); - } - - if(data.has("since_logoff")) - { - setDateRangeLastLogoff((bool)data["since_logoff"].asBoolean()); - } -} diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h index 3fe3095c58..a05dec3193 100644 --- a/indra/newview/llfolderview.h +++ b/indra/newview/llfolderview.h @@ -41,9 +41,12 @@ #ifndef LL_LLFOLDERVIEW_H #define LL_LLFOLDERVIEW_H +// JAMESDEBUG - trim this list #include #include #include +#include +#include #include "lluictrl.h" #include "v4color.h" @@ -52,97 +55,11 @@ #include "stdenums.h" #include "llfontgl.h" #include "lleditmenuhandler.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "lldepthstack.h" #include "lltooldraganddrop.h" - -class LLMenuGL; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFolderViewEventListener -// -// This is an abstract base class that users of the folderview classes -// would use to catch the useful events emitted from the folder -// views. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - -class LLFolderViewItem; -class LLFolderView; -class LLInventoryModel; -class LLScrollableContainerView; - -class LLFolderViewEventListener -{ -public: - virtual ~LLFolderViewEventListener( void ) {} - virtual const std::string& getName() const = 0; - virtual const std::string& getDisplayName() const = 0; - virtual const LLUUID& getUUID() const = 0; - virtual time_t getCreationDate() const = 0; // UTC seconds - virtual PermissionMask getPermissionMask() const = 0; - virtual LLUIImagePtr getIcon() const = 0; - virtual LLFontGL::StyleFlags getLabelStyle() const = 0; - virtual std::string getLabelSuffix() const = 0; - virtual void openItem( void ) = 0; - virtual void previewItem( void ) = 0; - virtual void selectItem(void) = 0; - virtual void showProperties(void) = 0; - virtual BOOL isItemRenameable() const = 0; - virtual BOOL renameItem(const std::string& new_name) = 0; - virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder - virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed - virtual BOOL removeItem() = 0; - virtual void removeBatch(LLDynamicArray& batch) = 0; - virtual void move( LLFolderViewEventListener* parent_listener ) = 0; - virtual BOOL isItemCopyable() const = 0; - virtual BOOL copyToClipboard() const = 0; - virtual void cutToClipboard() = 0; - virtual BOOL isClipboardPasteable() const = 0; - virtual void pasteFromClipboard() = 0; - virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; - virtual BOOL isUpToDate() const = 0; - virtual BOOL hasChildren() const = 0; - virtual LLInventoryType::EType getInventoryType() const = 0; - virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) {} - - // This method should be called when a drag begins. returns TRUE - // if the drag can begin, otherwise FALSE. - virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0; - - // This method will be called to determine if a drop can be - // performed, and will set drop to TRUE if a drop is - // requested. Returns TRUE if a drop is possible/happened, - // otherwise FALSE. - virtual BOOL dragOrDrop(MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data) = 0; - - // This method is called when the object being referenced by the - // bridge is actually dropped. This allows for cleanup of the old - // view, reference counting, etc. -// virtual void dropped() = 0; - - // this method accesses the parent and arranges and sets it as - // specified. - void arrangeAndSet(LLFolderViewItem* focus, BOOL set_selection, - BOOL take_keyboard_focus = TRUE); -}; - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFolderViewListenerFunctor -// -// This simple abstract base class can be used to applied to all -// listeners in a hierarchy. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLFolderViewListenerFunctor -{ -public: - virtual ~LLFolderViewListenerFunctor() {} - virtual void operator()(LLFolderViewEventListener* listener) = 0; -}; +// JAMESDEBUG - move this up +#include "llfolderviewitem.h" // because LLFolderView is-a LLFolderViewFolder //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFolderViewFunctor @@ -164,552 +81,6 @@ public: virtual void doItem(LLFolderViewItem* item) = 0; }; -class LLInventoryFilter -{ -public: - typedef enum e_folder_show - { - SHOW_ALL_FOLDERS, - SHOW_NON_EMPTY_FOLDERS, - SHOW_NO_FOLDERS - } EFolderShow; - - typedef enum e_filter_behavior - { - FILTER_NONE, // nothing to do, already filtered - FILTER_RESTART, // restart filtering from scratch - FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter - FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one - } EFilterBehavior; - - static const U32 SO_DATE = 1; - static const U32 SO_FOLDERS_BY_NAME = 2; - static const U32 SO_SYSTEM_FOLDERS_TO_TOP = 4; - - LLInventoryFilter(const std::string& name); - virtual ~LLInventoryFilter(); - - void setFilterTypes(U32 types); - U32 getFilterTypes() const { return mFilterOps.mFilterTypes; } - - void setFilterSubString(const std::string& string); - const std::string getFilterSubString(BOOL trim = FALSE); - - void setFilterPermissions(PermissionMask perms); - PermissionMask getFilterPermissions() const { return mFilterOps.mPermissions; } - - void setDateRange(time_t min_date, time_t max_date); - void setDateRangeLastLogoff(BOOL sl); - time_t getMinDate() const { return mFilterOps.mMinDate; } - time_t getMaxDate() const { return mFilterOps.mMaxDate; } - - void setHoursAgo(U32 hours); - U32 getHoursAgo() const { return mFilterOps.mHoursAgo; } - - void setShowFolderState( EFolderShow state); - EFolderShow getShowFolderState() { return mFilterOps.mShowFolderState; } - - void setSortOrder(U32 order); - U32 getSortOrder() { return mOrder; } - - BOOL check(LLFolderViewItem* item); - std::string::size_type getStringMatchOffset() const; - BOOL isActive(); - BOOL isNotDefault(); - BOOL isModified(); - BOOL isModifiedAndClear(); - BOOL isSinceLogoff(); - void clearModified() { mModified = FALSE; mFilterBehavior = FILTER_NONE; } - const std::string getName() const { return mName; } - std::string getFilterText(); - - void setFilterCount(S32 count) { mFilterCount = count; } - S32 getFilterCount() { return mFilterCount; } - void decrementFilterCount() { mFilterCount--; } - - void markDefault(); - void resetDefault(); - - BOOL isFilterWith(LLInventoryType::EType t); - - S32 getCurrentGeneration() const { return mFilterGeneration; } - S32 getMinRequiredGeneration() const { return mMinRequiredGeneration; } - S32 getMustPassGeneration() const { return mMustPassGeneration; } - - //RN: this is public to allow system to externally force a global refilter - void setModified(EFilterBehavior behavior = FILTER_RESTART); - - void toLLSD(LLSD& data); - void fromLLSD(LLSD& data); - -protected: - struct filter_ops - { - U32 mFilterTypes; - time_t mMinDate; - time_t mMaxDate; - U32 mHoursAgo; - EFolderShow mShowFolderState; - PermissionMask mPermissions; - }; - filter_ops mFilterOps; - filter_ops mDefaultFilterOps; - std::string::size_type mSubStringMatchOffset; - std::string mFilterSubString; - U32 mOrder; - const std::string mName; - S32 mFilterGeneration; - S32 mMustPassGeneration; - S32 mMinRequiredGeneration; - S32 mFilterCount; - S32 mNextFilterGeneration; - EFilterBehavior mFilterBehavior; - -private: - U32 mLastLogoff; - BOOL mModified; - BOOL mNeedTextRebuild; - std::string mFilterText; -}; - -// These are grouping of inventory types. -// Order matters when sorting system folders to the top. -enum EInventorySortGroup -{ - SG_SYSTEM_FOLDER, - SG_TRASH_FOLDER, - SG_NORMAL_FOLDER, - SG_ITEM -}; - -class LLInventorySort -{ -public: - LLInventorySort() - : mSortOrder(0), - mByDate(false), - mSystemToTop(false), - mFoldersByName(false) { } - - // Returns true if order has changed - bool updateSort(U32 order); - U32 getSort() { return mSortOrder; } - - bool operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b); -private: - U32 mSortOrder; - bool mByDate; - bool mSystemToTop; - bool mFoldersByName; -}; - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFolderViewItem -// -// An instance of this class represents a single item in a folder view -// such as an inventory item or a file. -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLFontGL; -class LLFolderViewFolder; -class LLFolderView; - -class LLFolderViewItem : public LLUICtrl -{ -protected: - friend class LLFolderViewEventListener; - - static const LLFontGL* sFont; - static const LLFontGL* sSmallFont; - static LLColor4 sFgColor; - static LLColor4 sHighlightBgColor; - static LLColor4 sHighlightFgColor; - static LLColor4 sFilterBGColor; - static LLColor4 sFilterTextColor; - static LLColor4 sSuffixColor; - static LLColor4 sSearchStatusColor; - static LLUIImagePtr sArrowImage; - static LLUIImagePtr sBoxImage; - - std::string mLabel; - std::string mSearchableLabel; - std::string mType; - S32 mLabelWidth; - time_t mCreationDate; - LLFolderViewFolder* mParentFolder; - LLFolderViewEventListener* mListener; - BOOL mIsSelected; - BOOL mIsCurSelection; - BOOL mSelectPending; - LLFontGL::StyleFlags mLabelStyle; - std::string mLabelSuffix; - LLUIImagePtr mIcon; - std::string mStatusText; - BOOL mHasVisibleChildren; - S32 mIndentation; - S32 mNumDescendantsSelected; - BOOL mFiltered; - S32 mLastFilterGeneration; - std::string::size_type mStringMatchOffset; - F32 mControlLabelRotation; - LLFolderView* mRoot; - BOOL mDragAndDropTarget; - BOOL mIsLoading; - LLTimer mTimeSinceRequestStart; - - // This function clears the currently selected item, and records - // the specified selected item appropriately for display and use - // in the UI. If open is TRUE, then folders are opened up along - // the way to the selection. - void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus = TRUE); - - // helper function to change the selection from the root. - void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); - - // helper function to change the selection from the root. - void extendSelectionFromRoot(LLFolderViewItem* selection); - - // this is an internal method used for adding items to folders. A - // no-op at this leve, but reimplemented in derived classes. - virtual BOOL addItem(LLFolderViewItem*) { return FALSE; } - virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } - -public: - static void initClass(); - static void cleanupClass(); - - // This function is called when the folder view is dirty. It's - // implemented here but called by derived classes when folding the - // views. - void arrangeFromRoot(); - void filterFromRoot( void ); - - // creation_date is in UTC seconds - LLFolderViewItem( const std::string& name, LLUIImagePtr icon, time_t creation_date, LLFolderView* root, LLFolderViewEventListener* listener ); - virtual ~LLFolderViewItem( void ); - - // addToFolder() returns TRUE if it succeeds. FALSE otherwise - enum { ARRANGE = TRUE, DO_NOT_ARRANGE = FALSE }; - virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root); - - virtual EInventorySortGroup getSortGroup() const; - - // Finds width and height of this object and it's children. Also - // makes sure that this view and it's children are the right size. - virtual S32 arrange( S32* width, S32* height, S32 filter_generation ); - virtual S32 getItemHeight(); - - // applies filters to control visibility of inventory items - virtual void filter( LLInventoryFilter& filter); - - // updates filter serial number and optionally propagated value up to root - S32 getLastFilterGeneration() { return mLastFilterGeneration; } - - virtual void dirtyFilter(); - - // If the selection is 'this' then note that otherwise - // ignore. Returns TRUE if this object was affected. If open is - // TRUE, then folders are opened up along the way to the - // selection. - virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus); - - // This method is used to toggle the selection of an item. If - // selection is 'this', then note selection, and return TRUE. - virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - - // this method is used to group select items - virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items){ return FALSE; } - - // this method is used to group select items - virtual void recursiveDeselect(BOOL deselect_self); - - // gets multiple-element selection - virtual BOOL getSelectionList(std::set &selection){return TRUE;} - - // Returns true is this object and all of its children can be removed (deleted by user) - virtual BOOL isRemovable(); - - // Returns true is this object and all of its children can be moved - virtual BOOL isMovable(); - - // destroys this item recursively - virtual void destroyView(); - - S32 getNumSelectedDescendants() { return mNumDescendantsSelected; } - - BOOL isSelected() { return mIsSelected; } - - void setIsCurSelection(BOOL select) { mIsCurSelection = select; } - - BOOL getIsCurSelection() { return mIsCurSelection; } - - BOOL hasVisibleChildren() { return mHasVisibleChildren; } - - // Call through to the viewed object and return true if it can be - // removed. Returns true if it's removed. - //virtual BOOL removeRecursively(BOOL single_item); - BOOL remove(); - - // Build an appropriate context menu for the item. Flags unused. - void buildContextMenu(LLMenuGL& menu, U32 flags); - - // This method returns the actual name of the thing being - // viewed. This method will ask the viewed object itself. - const std::string& getName( void ) const; - - const std::string& getSearchableLabel( void ) const; - - // This method returns the label displayed on the view. This - // method was primarily added to allow sorting on the folder - // contents possible before the entire view has been constructed. - const std::string& getLabel() const { return mLabel; } - - // Used for sorting, like getLabel() above. - virtual time_t getCreationDate() const { return mCreationDate; } - - LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; } - const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; } - - LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE ); - LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE ); - - const LLFolderViewEventListener* getListener( void ) const { return mListener; } - LLFolderViewEventListener* getListener( void ) { return mListener; } - - // just rename the object. - void rename(const std::string& new_name); - - // open - virtual void openItem( void ); - virtual void preview(void); - - // Show children (unfortunate that this is called "open") - virtual void setOpen(BOOL open = TRUE) {}; - - virtual BOOL isOpen() { return FALSE; } - - LLFolderView* getRoot(); - BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); - S32 getIndentation() { return mIndentation; } - - virtual BOOL potentiallyVisible(); // do we know for a fact that this item has been filtered out? - - virtual BOOL getFiltered(); - virtual BOOL getFiltered(S32 filter_generation); - virtual void setFiltered(BOOL filtered, S32 filter_generation); - - // change the icon - void setIcon(LLUIImagePtr icon); - - // refresh information from the object being viewed. - void refreshFromListener(); - virtual void refresh(); - - virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); - - // LLView functionality - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleHover( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - - // virtual void handleDropped(); - virtual void draw(); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); -}; - - -// function used for sorting. -typedef bool (*sort_order_f)(LLFolderViewItem* a, LLFolderViewItem* b); - - -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Class LLFolderViewFolder -// -// An instance of an LLFolderViewFolder represents a collection of -// more folders and items. This is used to build the hierarchy of -// items found in the folder view. :) -//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -class LLFolderViewFolder : public LLFolderViewItem -{ -public: - typedef enum e_trash - { - UNKNOWN, TRASH, NOT_TRASH - } ETrash; - -protected: - typedef std::list items_t; - typedef std::list folders_t; - items_t mItems; - folders_t mFolders; - LLInventorySort mSortFunction; - - BOOL mIsOpen; - BOOL mExpanderHighlighted; - F32 mCurHeight; - F32 mTargetHeight; - F32 mAutoOpenCountdown; - time_t mSubtreeCreationDate; - mutable ETrash mAmTrash; - S32 mLastArrangeGeneration; - S32 mLastCalculatedWidth; - S32 mCompletedFilterGeneration; - S32 mMostFilteredDescendantGeneration; -public: - typedef enum e_recurse_type - { - RECURSE_NO, - RECURSE_UP, - RECURSE_DOWN, - RECURSE_UP_DOWN - } ERecurseType; - - LLFolderViewFolder( const std::string& name, LLUIImagePtr icon, - LLFolderView* root, - LLFolderViewEventListener* listener ); - virtual ~LLFolderViewFolder( void ); - - virtual BOOL potentiallyVisible(); - - LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); - LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); - - // addToFolder() returns TRUE if it succeeds. FALSE otherwise - virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root); - - // Finds width and height of this object and it's children. Also - // makes sure that this view and it's children are the right size. - virtual S32 arrange( S32* width, S32* height, S32 filter_generation ); - - BOOL needsArrange(); - - // Returns the sort group (system, trash, folder) for this folder. - virtual EInventorySortGroup getSortGroup() const; - - virtual void setCompletedFilterGeneration(S32 generation, BOOL recurse_up); - virtual S32 getCompletedFilterGeneration() { return mCompletedFilterGeneration; } - - BOOL hasFilteredDescendants(S32 filter_generation) { return mMostFilteredDescendantGeneration >= filter_generation; } - BOOL hasFilteredDescendants(); - - // applies filters to control visibility of inventory items - virtual void filter( LLInventoryFilter& filter); - virtual void setFiltered(BOOL filtered, S32 filter_generation); - virtual void dirtyFilter(); - - // Passes selection information on to children and record - // selection information if necessary. Returns TRUE if this object - // (or a child) was affected. - virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, - BOOL take_keyboard_focus); - - // This method is used to change the selection of an item. If - // selection is 'this', then note selection as true. Returns TRUE - // if this or a child is now selected. - virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); - - // this method is used to group select items - virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items); - - virtual void recursiveDeselect(BOOL deselect_self); - - // Returns true is this object and all of its children can be removed. - virtual BOOL isRemovable(); - - // Returns true is this object and all of its children can be moved - virtual BOOL isMovable(); - - // destroys this folder, and all children - virtual void destroyView(); - - // If this folder can be removed, remove all children that can be - // removed, return TRUE if this is empty after the operation and - // it's viewed folder object can be removed. - //virtual BOOL removeRecursively(BOOL single_item); - //virtual BOOL remove(); - - // remove the specified item (and any children) if - // possible. Return TRUE if the item was deleted. - BOOL removeItem(LLFolderViewItem* item); - - // simply remove the view (and any children) Don't bother telling - // the listeners. - void removeView(LLFolderViewItem* item); - - // extractItem() removes the specified item from the folder, but - // doesn't delete it. - void extractItem( LLFolderViewItem* item ); - - // This function is called by a child that needs to be resorted. - void resort(LLFolderViewItem* item); - - void setItemSortOrder(U32 ordering); - void sortBy(U32); - //BOOL (*func)(LLFolderViewItem* a, LLFolderViewItem* b)); - - void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; } - - // folders can be opened. This will usually be called by internal - // methods. - virtual void toggleOpen(); - - // Force a folder open or closed - virtual void setOpen(BOOL openitem = TRUE); - - // Called when a child is refreshed. - // don't rearrange child folder contents unless explicitly requested - virtual void requestArrange(BOOL include_descendants = FALSE); - - // internal method which doesn't update the entire view. This - // method was written because the list iterators destroy the state - // of other iterations, thus, we can't arrange while iterating - // through the children (such as when setting which is selected. - virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO); - - // Get the current state of the folder. - virtual BOOL isOpen() { return mIsOpen; } - - // special case if an object is dropped on the child. - BOOL handleDragAndDropFromChild(MASK mask, - BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - - void applyFunctorRecursively(LLFolderViewFunctor& functor); - virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); - - virtual void openItem( void ); - virtual BOOL addItem(LLFolderViewItem* item); - virtual BOOL addFolder( LLFolderViewFolder* folder); - - // LLView functionality - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, - EDragAndDropType cargo_type, - void* cargo_data, - EAcceptance* accept, - std::string& tooltip_msg); - virtual void draw(); - - time_t getCreationDate() const; - bool isTrash() const; -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLFolderView @@ -718,38 +89,51 @@ public: // manages the screen region of the folder view. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLUICtrl; +class LLFolderViewEventListener; +class LLInventoryModel; class LLLineEditor; +class LLMenuGL; +class LLScrollContainer; +class LLUICtrl; -class LLFolderView : public LLFolderViewFolder, LLEditMenuHandler +class LLFolderView : public LLFolderViewFolder, public LLEditMenuHandler { public: - typedef void (*SelectCallback)(const std::deque &items, BOOL user_action, void* data); - - static F32 sAutoOpenTime; - + struct Params : public LLInitParam::Block + { + Mandatory parent_panel; + Optional task_id; + }; LLFolderView( const std::string& name, LLUIImagePtr root_folder_icon, const LLRect& rect, - const LLUUID& source_id, LLView *parent_view ); + const LLUUID& source_id, LLPanel *parent_view ); + LLFolderView(const Params&); virtual ~LLFolderView( void ); virtual BOOL canFocusChildren() const; + virtual LLFolderView* getRoot() { return this; } + // FolderViews default to sort by name. This will change that, // and resort the items if necessary. void setSortOrder(U32 order); void checkTreeResortForModelChanged(); - void setFilterPermMask(PermissionMask filter_perm_mask) { mFilter.setFilterPermissions(filter_perm_mask); } - void setSelectCallback(SelectCallback callback, void* user_data) { mSelectCallback = callback, mUserData = user_data; } + void setFilterPermMask(PermissionMask filter_perm_mask); void setAllowMultiSelect(BOOL allow) { mAllowMultiSelect = allow; } - - LLInventoryFilter* getFilter() { return &mFilter; } + + typedef boost::signals2::signal& items, BOOL user_action)> signal_t; + void setSelectCallback(const signal_t::slot_type& cb) { mSelectSignal.connect(cb); } + void setReshapeCallback(const signal_t::slot_type& cb) { mReshapeSignal.connect(cb); } + + // filter is never null + LLInventoryFilter* getFilter(); const std::string getFilterSubString(BOOL trim = FALSE); - U32 getFilterTypes() const { return mFilter.getFilterTypes(); } - PermissionMask getFilterPermissions() const { return mFilter.getFilterPermissions(); } - LLInventoryFilter::EFolderShow getShowFolderState() { return mFilter.getShowFolderState(); } + U32 getFilterTypes() const; + PermissionMask getFilterPermissions() const; + // JAMESDEBUG use getFilter()->getShowFolderState(); + //LLInventoryFilter::EFolderShow getShowFolderState(); U32 getSortOrder() const; - BOOL isFilterModified() { return mFilter.isNotDefault(); } - BOOL getAllowMultiSelect() { return mAllowMultiSelect; } + BOOL isFilterModified(); + BOOL getAllowMultiSelect(); // Close all folders in the view void closeAllFolders(); @@ -775,7 +159,13 @@ public: // Record the selected item and pass it down the hierachy. virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus); - + + // Used by menu callbacks + void setSelectionByID(const LLUUID& obj_id, BOOL take_keyboard_focus); + + // Called once a frame to update the selection if mSelectThisID has been set + void updateSelection(); + // This method is used to toggle the selection of an item. Walks // children, and keeps track of selected objects. virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); @@ -800,6 +190,9 @@ public: void openSelectedItems( void ); void propertiesSelectedItems( void ); + // change the folder type + void changeType(LLInventoryModel *model, LLAssetType::EType new_folder_type); + void autoOpenItem(LLFolderViewFolder* item); void closeAutoOpenedFolders(); BOOL autoOpenTest(LLFolderViewFolder* item); @@ -828,9 +221,6 @@ public: //void dragItemIntoFolder( LLFolderViewItem* moving_item, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); //void dragFolderIntoFolder( LLFolderViewFolder* moving_folder, LLFolderViewFolder* dst_folder, BOOL drop, BOOL* accept ); - // LLUICtrl Functionality - /*virtual*/ void setFocus(BOOL focus); - // LLView functionality ///*virtual*/ BOOL handleKey( KEY key, MASK mask, BOOL called_from_parent ); /*virtual*/ BOOL handleKeyHere( KEY key, MASK mask ); @@ -845,14 +235,13 @@ public: EAcceptance* accept, std::string& tooltip_msg); /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - /*virtual*/ void onFocusLost(); virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void draw(); virtual void deleteAllChildren(); void scrollToShowSelection(); - void scrollToShowItem(LLFolderViewItem* item); - void setScrollContainer( LLScrollableContainerView* parent ) { mScrollContainer = parent; } + void scrollToShowItem(LLFolderViewItem* item, const LLRect& constraint_rect); + void setScrollContainer( LLScrollContainer* parent ) { mScrollContainer = parent; } LLRect getVisibleRect(); BOOL search(LLFolderViewItem* first_item, const std::string &search_string, BOOL backward); @@ -865,7 +254,9 @@ public: void addItemID(const LLUUID& id, LLFolderViewItem* itemp); void removeItemID(const LLUUID& id); LLFolderViewItem* getItemByID(const LLUUID& id); - + + bool doToSelected(LLInventoryModel* model, const LLSD& userdata); + void doIdle(); // Real idle routine static void idle(void* user_data); // static glue to doIdle() @@ -873,20 +264,26 @@ public: BOOL needsAutoRename() { return mNeedsAutoRename; } void setNeedsAutoRename(BOOL val) { mNeedsAutoRename = val; } + void setCallbackRegistrar(LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* registrar) { mCallbackRegistrar = registrar; } + BOOL getDebugFilters() { return mDebugFilters; } + LLPanel* getParentPanel() { return mParentPanel; } // DEBUG only void dumpSelectionInformation(); + +private: + void updateRenamerPosition(); protected: - LLScrollableContainerView* mScrollContainer; // NULL if this is not a child of a scroll container. + LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. - static void commitRename( LLUICtrl* renamer, void* user_data ); - static void onRenamerLost( LLUICtrl* renamer, void* user_data); + void commitRename( const LLSD& data ); + static void onRenamerLost( LLFocusableElement* renamer, void* user_data); void finishRenamingItem( void ); void closeRenamer( void ); - + protected: LLHandle mPopupMenuHandle; @@ -902,8 +299,8 @@ protected: LLLineEditor* mRenamer; BOOL mNeedsScroll; - LLFolderViewItem* mLastScrollItem; - LLCoordGL mLastScrollOffset; + BOOL mPinningSelectedItem; + LLRect mScrollConstraintRect; BOOL mNeedsAutoSelect; BOOL mAutoSelectOverride; BOOL mNeedsAutoRename; @@ -915,19 +312,27 @@ protected: LLFrameTimer mAutoOpenTimer; LLFrameTimer mSearchTimer; std::string mSearchString; - LLInventoryFilter mFilter; + LLInventoryFilter* mFilter; BOOL mShowSelectionContext; BOOL mShowSingleSelection; LLFrameTimer mMultiSelectionFadeTimer; S32 mArrangeGeneration; - void* mUserData; - SelectCallback mSelectCallback; + signal_t mSelectSignal; + signal_t mReshapeSignal; S32 mSignalSelectCallback; S32 mMinWidth; std::map mItemMap; BOOL mDragAndDropThisFrame; + + LLUUID mSelectThisID; // if non null, select this item + + LLPanel* mParentPanel; + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar* mCallbackRegistrar; + +public: + static F32 sAutoOpenTime; }; bool sort_item_name(LLFolderViewItem* a, LLFolderViewItem* b); diff --git a/indra/newview/llfoldervieweventlistener.h b/indra/newview/llfoldervieweventlistener.h new file mode 100644 index 0000000000..254ce4062a --- /dev/null +++ b/indra/newview/llfoldervieweventlistener.h @@ -0,0 +1,101 @@ +/** + * @file llfoldervieweventlistener.h + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLFOLDERVIEWEVENTLISTENER_H +#define LLFOLDERVIEWEVENTLISTENER_H + +#include "lldarray.h" // JAMESDEBUG convert to std::vector +#include "llfontgl.h" // just for StyleFlags enum +#include "llpointer.h" + + +class LLFolderViewItem; +class LLFolderView; +class LLFontGL; +class LLInventoryModel; +class LLMenuGL; +class LLScrollContainer; +class LLUIImage; +class LLUUID; + +// This is an abstract base class that users of the folderview classes +// would use to catch the useful events emitted from the folder +// views. +class LLFolderViewEventListener +{ +public: + virtual ~LLFolderViewEventListener( void ) {} + virtual const std::string& getName() const = 0; + virtual const std::string& getDisplayName() const = 0; + virtual const LLUUID& getUUID() const = 0; + virtual time_t getCreationDate() const = 0; // UTC seconds + virtual PermissionMask getPermissionMask() const = 0; + virtual LLAssetType::EType getPreferredType() const = 0; + virtual LLPointer getIcon() const = 0; + virtual LLFontGL::StyleFlags getLabelStyle() const = 0; + virtual std::string getLabelSuffix() const = 0; + virtual void openItem( void ) = 0; + virtual void closeItem( void ) = 0; + virtual void previewItem( void ) = 0; + virtual void selectItem(void) = 0; + virtual void showProperties(void) = 0; + virtual BOOL isItemRenameable() const = 0; + virtual BOOL renameItem(const std::string& new_name) = 0; + virtual BOOL isItemMovable( void ) = 0; // Can be moved to another folder + virtual BOOL isItemRemovable( void ) = 0; // Can be destroyed + virtual BOOL removeItem() = 0; + virtual void removeBatch(LLDynamicArray& batch) = 0; + virtual void move( LLFolderViewEventListener* parent_listener ) = 0; + virtual BOOL isItemCopyable() const = 0; + virtual BOOL copyToClipboard() const = 0; + virtual void cutToClipboard() = 0; + virtual BOOL isClipboardPasteable() const = 0; + virtual void pasteFromClipboard() = 0; + virtual void pasteLinkFromClipboard() = 0; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags) = 0; + virtual BOOL isUpToDate() const = 0; + virtual BOOL hasChildren() const = 0; + virtual LLInventoryType::EType getInventoryType() const = 0; + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) = 0; + + // This method should be called when a drag begins. returns TRUE + // if the drag can begin, otherwise FALSE. + virtual BOOL startDrag(EDragAndDropType* type, LLUUID* id) const = 0; + + // This method will be called to determine if a drop can be + // performed, and will set drop to TRUE if a drop is + // requested. Returns TRUE if a drop is possible/happened, + // otherwise FALSE. + virtual BOOL dragOrDrop(MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data) = 0; +}; + +#endif diff --git a/indra/newview/llfolderviewitem.cpp b/indra/newview/llfolderviewitem.cpp new file mode 100644 index 0000000000..f1e499e14b --- /dev/null +++ b/indra/newview/llfolderviewitem.cpp @@ -0,0 +1,2489 @@ +/** +* @file llfolderviewitem.cpp +* @brief Items and folders that can appear in a hierarchical folder view +* +* $LicenseInfo:firstyear=2001&license=viewergpl$ +* +* Copyright (c) 2001-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#include "llviewerprecompiledheaders.h" + +#include "llfolderviewitem.h" + +// viewer includes +#include "llfolderview.h" // Items depend extensively on LLFolderViews +#include "llfoldervieweventlistener.h" +#include "llinventoryfilter.h" +#include "llinventorymodel.h" // *TODO: make it take a pointer to an inventory-model interface +#include "llviewercontrol.h" // gSavedSettings +#include "llviewerwindow.h" // Argh, only for setCursor() + +// linden library includes +#include "llfocusmgr.h" // gFocusMgr +#include "llpanel.h" // panel->hasFocus() +#include "lltrans.h" + +///---------------------------------------------------------------------------- +/// Class LLFolderViewItem +///---------------------------------------------------------------------------- + +// statics +const LLFontGL* LLFolderViewItem::sFont = NULL; +const LLFontGL* LLFolderViewItem::sSmallFont = NULL; +LLUIImagePtr LLFolderViewItem::sArrowImage; +LLUIImagePtr LLFolderViewItem::sBoxImage; + +// only integers can be initialized in header +const F32 LLFolderViewItem::FOLDER_CLOSE_TIME_CONSTANT = 0.02f; +const F32 LLFolderViewItem::FOLDER_OPEN_TIME_CONSTANT = 0.03f; + +const LLColor4U DEFAULT_WHITE(255, 255, 255); + +//static +void LLFolderViewItem::initClass() +{ + sFont = LLFontGL::getFontSansSerifSmall(); + sSmallFont = LLFontGL::getFontMonospace(); + sArrowImage = LLUI::getUIImage("folder_arrow.tga"); + sBoxImage = LLUI::getUIImage("rounded_square.tga"); +} + +//static +void LLFolderViewItem::cleanupClass() +{ + sArrowImage = NULL; + sBoxImage = NULL; +} + + +// NOTE: Optimize this, we call it a *lot* when opening a large inventory +LLFolderViewItem::Params::Params() +: icon("icon"), + folder_arrow_image("folder_arrow_image", LLUI::getUIImage("folder_arrow.tga")), + selection_image("selection_image", LLUI::getUIImage("rounded_square.tga")) +{ + mouse_opaque(true); + follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_RIGHT); + // JAMESDEBUG tab_stop(false); +} + +// Default constructor +LLFolderViewItem::LLFolderViewItem(LLFolderViewItem::Params p) +: LLView(p), + mLabelWidth(0), + mLabelWidthDirty(false), + mParentFolder( NULL ), + mIsSelected( FALSE ), + mIsCurSelection( FALSE ), + mSelectPending(FALSE), + mLabelStyle( LLFontGL::NORMAL ), + mHasVisibleChildren(FALSE), + mIndentation(0), + mNumDescendantsSelected(0), + mFiltered(FALSE), + mLastFilterGeneration(-1), + mStringMatchOffset(std::string::npos), + mControlLabelRotation(0.f), + mDragAndDropTarget(FALSE), + mIsLoading(FALSE), + mLabel(p.name), + mRoot(p.root), + mCreationDate(p.creation_date), + mListener(p.listener), + mArrowImage(p.folder_arrow_image), + mBoxImage(p.selection_image) +{ + refresh(); +} + +// Destroys the object +LLFolderViewItem::~LLFolderViewItem( void ) +{ + delete mListener; + mListener = NULL; +} + +LLFolderView* LLFolderViewItem::getRoot() +{ + return mRoot; +} + +// Returns true if this object is a child (or grandchild, etc.) of potential_ancestor. +BOOL LLFolderViewItem::isDescendantOf( const LLFolderViewFolder* potential_ancestor ) +{ + LLFolderViewItem* root = this; + while( root->mParentFolder ) + { + if( root->mParentFolder == potential_ancestor ) + { + return TRUE; + } + root = root->mParentFolder; + } + return FALSE; +} + +LLFolderViewItem* LLFolderViewItem::getNextOpenNode(BOOL include_children) +{ + if (!mParentFolder) + { + return NULL; + } + + LLFolderViewItem* itemp = mParentFolder->getNextFromChild( this, include_children ); + while(itemp && !itemp->getVisible()) + { + LLFolderViewItem* next_itemp = itemp->mParentFolder->getNextFromChild( itemp, include_children ); + if (itemp == next_itemp) + { + // hit last item + return itemp->getVisible() ? itemp : this; + } + itemp = next_itemp; + } + + return itemp; +} + +LLFolderViewItem* LLFolderViewItem::getPreviousOpenNode(BOOL include_children) +{ + if (!mParentFolder) + { + return NULL; + } + + LLFolderViewItem* itemp = mParentFolder->getPreviousFromChild( this, include_children ); + while(itemp && !itemp->getVisible()) + { + LLFolderViewItem* next_itemp = itemp->mParentFolder->getPreviousFromChild( itemp, include_children ); + if (itemp == next_itemp) + { + // hit first item + return itemp->getVisible() ? itemp : this; + } + itemp = next_itemp; + } + + return itemp; +} + +// is this item something we think we should be showing? +// for example, if we haven't gotten around to filtering it yet, then the answer is yes +// until we find out otherwise +BOOL LLFolderViewItem::potentiallyVisible() +{ + // we haven't been checked against min required filter + // or we have and we passed + return getLastFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration() || getFiltered(); +} + +BOOL LLFolderViewItem::getFiltered() +{ + return mFiltered && mLastFilterGeneration >= getRoot()->getFilter()->getMinRequiredGeneration(); +} + +BOOL LLFolderViewItem::getFiltered(S32 filter_generation) +{ + return mFiltered && mLastFilterGeneration >= filter_generation; +} + +void LLFolderViewItem::setFiltered(BOOL filtered, S32 filter_generation) +{ + mFiltered = filtered; + mLastFilterGeneration = filter_generation; +} + +void LLFolderViewItem::setIcon(LLUIImagePtr icon) +{ + mIcon = icon; +} + +// refresh information from the listener +void LLFolderViewItem::refreshFromListener() +{ + if(mListener) + { + mLabel = mListener->getDisplayName(); + LLAssetType::EType preferred_type = mListener->getPreferredType(); + + // *TODO: to be removed when database supports multi language. This is a + // temporary attempt to display the inventory folder in the user locale. + // mantipov: *NOTE: be sure this code is synchronized with LLFriendCardsManager::findChildFolderUUID + // it uses the same way to find localized string + if (LLAssetType::lookupIsProtectedCategoryType(preferred_type)) + { + LLTrans::findString(mLabel, "InvFolder " + mLabel); + }; + + setIcon(mListener->getIcon()); + time_t creation_date = mListener->getCreationDate(); + if (mCreationDate != creation_date) + { + mCreationDate = mListener->getCreationDate(); + dirtyFilter(); + } + mLabelStyle = mListener->getLabelStyle(); + mLabelSuffix = mListener->getLabelSuffix(); + } +} + +void LLFolderViewItem::refresh() +{ + refreshFromListener(); + + std::string searchable_label(mLabel); + searchable_label.append(mLabelSuffix); + LLStringUtil::toUpper(searchable_label); + + if (mSearchableLabel.compare(searchable_label)) + { + mSearchableLabel.assign(searchable_label); + dirtyFilter(); + // some part of label has changed, so overall width has potentially changed, and sort order too + if (mParentFolder) + { + mParentFolder->requestSort(); + mParentFolder->requestArrange(); + } + } + + mLabelWidthDirty = true; +} + +void LLFolderViewItem::applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor) +{ + functor(mListener); +} + +// This function is called when items are added or view filters change. It's +// implemented here but called by derived classes when folding the +// views. +void LLFolderViewItem::filterFromRoot( void ) +{ + LLFolderViewItem* root = getRoot(); + + root->filter(*((LLFolderView*)root)->getFilter()); +} + +// This function is called when the folder view is dirty. It's +// implemented here but called by derived classes when folding the +// views. +void LLFolderViewItem::arrangeFromRoot() +{ + LLFolderViewItem* root = getRoot(); + + S32 height = 0; + S32 width = 0; + root->arrange( &width, &height, 0 ); +} + +// Utility function for LLFolderView +void LLFolderViewItem::arrangeAndSet(BOOL set_selection, + BOOL take_keyboard_focus) +{ + LLFolderView* root = getRoot(); + getParentFolder()->requestArrange(); + if(set_selection) + { + setSelectionFromRoot(this, TRUE, take_keyboard_focus); + if(root) + { + root->scrollToShowSelection(); + } + } +} + +// This function clears the currently selected item, and records the +// specified selected item appropriately for display and use in the +// UI. If open is TRUE, then folders are opened up along the way to +// the selection. +void LLFolderViewItem::setSelectionFromRoot(LLFolderViewItem* selection, + BOOL openitem, + BOOL take_keyboard_focus) +{ + getRoot()->setSelection(selection, openitem, take_keyboard_focus); +} + +// helper function to change the selection from the root. +void LLFolderViewItem::changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected) +{ + getRoot()->changeSelection(selection, selected); +} + +void LLFolderViewItem::extendSelectionFromRoot(LLFolderViewItem* selection) +{ + LLDynamicArray selected_items; + + getRoot()->extendSelection(selection, NULL, selected_items); +} + +EInventorySortGroup LLFolderViewItem::getSortGroup() const +{ + return SG_ITEM; +} + +// addToFolder() returns TRUE if it succeeds. FALSE otherwise +BOOL LLFolderViewItem::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) +{ + if (!folder) + { + return FALSE; + } + mParentFolder = folder; + root->addItemID(getListener()->getUUID(), this); + return folder->addItem(this); +} + + +// Finds width and height of this object and it's children. Also +// makes sure that this view and it's children are the right size. +S32 LLFolderViewItem::arrange( S32* width, S32* height, S32 filter_generation) +{ + mIndentation = mParentFolder ? mParentFolder->getIndentation() + LEFT_INDENTATION : 0; + if (mLabelWidthDirty) + { + mLabelWidth = ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + sFont->getWidth(mSearchableLabel); + mLabelWidthDirty = false; + } + + *width = llmax(*width, mLabelWidth + mIndentation); + *height = getItemHeight(); + return *height; +} + +S32 LLFolderViewItem::getItemHeight() +{ + S32 icon_height = mIcon->getHeight(); + S32 label_height = llround(sFont->getLineHeight()); + return llmax( icon_height, label_height ) + ICON_PAD; +} + +void LLFolderViewItem::filter( LLInventoryFilter& filter) +{ + BOOL filtered = mListener && filter.check(this); + + // if our visibility will change as a result of this filter, then + // we need to be rearranged in our parent folder + if (getVisible() != filtered) + { + if (mParentFolder) + { + mParentFolder->requestArrange(); + } + } + + setFiltered(filtered, filter.getCurrentGeneration()); + mStringMatchOffset = filter.getStringMatchOffset(); + filter.decrementFilterCount(); + + if (getRoot()->getDebugFilters()) + { + mStatusText = llformat("%d", mLastFilterGeneration); + } +} + +void LLFolderViewItem::dirtyFilter() +{ + mLastFilterGeneration = -1; + // bubble up dirty flag all the way to root + if (getParentFolder()) + { + getParentFolder()->setCompletedFilterGeneration(-1, TRUE); + } +} + +// *TODO: This can be optimized a lot by simply recording that it is +// selected in the appropriate places, and assuming that set selection +// means 'deselect' for a leaf item. Do this optimization after +// multiple selection is implemented to make sure it all plays nice +// together. +BOOL LLFolderViewItem::setSelection(LLFolderViewItem* selection, BOOL openitem, BOOL take_keyboard_focus) +{ + if( selection == this ) + { + mIsSelected = TRUE; + if(mListener) + { + mListener->selectItem(); + } + } + else + { + mIsSelected = FALSE; + } + return mIsSelected; +} + +BOOL LLFolderViewItem::changeSelection(LLFolderViewItem* selection, BOOL selected) +{ + if(selection == this && mIsSelected != selected) + { + mIsSelected = selected; + if(mListener) + { + mListener->selectItem(); + } + return TRUE; + } + return FALSE; +} + +void LLFolderViewItem::recursiveDeselect(BOOL deselect_self) +{ + if (mIsSelected && deselect_self) + { + mIsSelected = FALSE; + + // update ancestors' count of selected descendents + LLFolderViewFolder* parent_folder = getParentFolder(); + while(parent_folder) + { + parent_folder->mNumDescendantsSelected--; + parent_folder = parent_folder->getParentFolder(); + } + } +} + + +BOOL LLFolderViewItem::isMovable() +{ + if( mListener ) + { + return mListener->isItemMovable(); + } + else + { + return TRUE; + } +} + +BOOL LLFolderViewItem::isRemovable() +{ + if( mListener ) + { + return mListener->isItemRemovable(); + } + else + { + return TRUE; + } +} + +void LLFolderViewItem::destroyView() +{ + if (mParentFolder) + { + // removeView deletes me + mParentFolder->removeView(this); + } +} + +// Call through to the viewed object and return true if it can be +// removed. +//BOOL LLFolderViewItem::removeRecursively(BOOL single_item) +BOOL LLFolderViewItem::remove() +{ + if(!isRemovable()) + { + return FALSE; + } + if(mListener) + { + return mListener->removeItem(); + } + return TRUE; +} + +// Build an appropriate context menu for the item. +void LLFolderViewItem::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + if(mListener) + { + mListener->buildContextMenu(menu, flags); + } +} + +void LLFolderViewItem::openItem( void ) +{ + if( mListener ) + { + mListener->openItem(); + } +} + +void LLFolderViewItem::preview( void ) +{ + if (mListener) + { + mListener->previewItem(); + } +} + +void LLFolderViewItem::rename(const std::string& new_name) +{ + if( !new_name.empty() ) + { + if( mListener ) + { + mListener->renameItem(new_name); + + if(mParentFolder) + { + mParentFolder->requestSort(); + } + } + } +} + +const std::string& LLFolderViewItem::getSearchableLabel() const +{ + return mSearchableLabel; +} + +const std::string& LLFolderViewItem::getName( void ) const +{ + if(mListener) + { + return mListener->getName(); + } + return mLabel; +} + +// LLView functionality +BOOL LLFolderViewItem::handleRightMouseDown( S32 x, S32 y, MASK mask ) +{ + if(!mIsSelected) + { + setSelectionFromRoot(this, FALSE); + } + make_ui_sound("UISndClick"); + return TRUE; +} + +BOOL LLFolderViewItem::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + // No handler needed for focus lost since this class has no + // state that depends on it. + gFocusMgr.setMouseCapture( this ); + + if (!mIsSelected) + { + if(mask & MASK_CONTROL) + { + changeSelectionFromRoot(this, !mIsSelected); + } + else if (mask & MASK_SHIFT) + { + extendSelectionFromRoot(this); + } + else + { + setSelectionFromRoot(this, FALSE); + } + make_ui_sound("UISndClick"); + } + else + { + mSelectPending = TRUE; + } + + if( isMovable() ) + { + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y ); + LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y ); + } + return TRUE; +} + +BOOL LLFolderViewItem::handleHover( S32 x, S32 y, MASK mask ) +{ + if( hasMouseCapture() && isMovable() ) + { + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y ); + BOOL can_drag = TRUE; + if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) + { + LLFolderView* root = getRoot(); + + if(root->getCurSelectedItem()) + { + LLToolDragAndDrop::ESource src = LLToolDragAndDrop::SOURCE_WORLD; + + // *TODO: push this into listener and remove + // dependency on llagent + if (mListener + && gInventory.isObjectDescendentOf(mListener->getUUID(), gInventory.getRootFolderID())) + { + src = LLToolDragAndDrop::SOURCE_AGENT; + } + else if (mListener + && gInventory.isObjectDescendentOf(mListener->getUUID(), gInventory.getLibraryRootFolderID())) + { + src = LLToolDragAndDrop::SOURCE_LIBRARY; + } + + can_drag = root->startDrag(src); + if (can_drag) + { + // if (mListener) mListener->startDrag(); + // RN: when starting drag and drop, clear out last auto-open + root->autoOpenTest(NULL); + root->setShowSelectionContext(TRUE); + + // Release keyboard focus, so that if stuff is dropped into the + // world, pressing the delete key won't blow away the inventory + // item. + gFocusMgr.setKeyboardFocus(NULL); + + return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); + } + } + } + + if (can_drag) + { + gViewerWindow->setCursor(UI_CURSOR_ARROW); + } + else + { + gViewerWindow->setCursor(UI_CURSOR_NOLOCKED); + } + return TRUE; + } + else + { + getRoot()->setShowSelectionContext(FALSE); + gViewerWindow->setCursor(UI_CURSOR_ARROW); + // let parent handle this then... + return FALSE; + } +} + + +BOOL LLFolderViewItem::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + preview(); + return TRUE; +} + +BOOL LLFolderViewItem::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + if (getParent()) + { + return getParent()->handleScrollWheel(x, y, clicks); + } + return FALSE; +} + +BOOL LLFolderViewItem::handleMouseUp( S32 x, S32 y, MASK mask ) +{ + // if mouse hasn't moved since mouse down... + if ( pointInView(x, y) && mSelectPending ) + { + //...then select + if(mask & MASK_CONTROL) + { + changeSelectionFromRoot(this, !mIsSelected); + } + else if (mask & MASK_SHIFT) + { + extendSelectionFromRoot(this); + } + else + { + setSelectionFromRoot(this, FALSE); + } + } + + mSelectPending = FALSE; + + if( hasMouseCapture() ) + { + getRoot()->setShowSelectionContext(FALSE); + gFocusMgr.setMouseCapture( NULL ); + } + return TRUE; +} + +BOOL LLFolderViewItem::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL accepted = FALSE; + BOOL handled = FALSE; + if(mListener) + { + accepted = mListener->dragOrDrop(mask,drop,cargo_type,cargo_data); + handled = accepted; + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + } + if(mParentFolder && !handled) + { + handled = mParentFolder->handleDragAndDropFromChild(mask,drop,cargo_type,cargo_data,accept,tooltip_msg); + } + if (handled) + { + lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewItem" << llendl; + } + + return handled; +} + + +void LLFolderViewItem::draw() +{ + static LLUIColor sFgColor = LLUIColorTable::instance().getColor("MenuItemEnabledColor", DEFAULT_WHITE); + static LLUIColor sHighlightBgColor = LLUIColorTable::instance().getColor("MenuItemHighlightBgColor", DEFAULT_WHITE); + static LLUIColor sHighlightFgColor = LLUIColorTable::instance().getColor("MenuItemHighlightFgColor", DEFAULT_WHITE); + static LLUIColor sFilterBGColor = LLUIColorTable::instance().getColor("FilterBackgroundColor", DEFAULT_WHITE); + static LLUIColor sFilterTextColor = LLUIColorTable::instance().getColor("FilterTextColor", DEFAULT_WHITE); + static LLUIColor sSuffixColor = LLUIColorTable::instance().getColor("InventoryItemSuffixColor", DEFAULT_WHITE); + static LLUIColor sSearchStatusColor = LLUIColorTable::instance().getColor("InventorySearchStatusColor", DEFAULT_WHITE); + + bool possibly_has_children = false; + bool up_to_date = mListener && mListener->isUpToDate(); + if((up_to_date && hasVisibleChildren() ) || // we fetched our children and some of them have passed the filter... + (!up_to_date && mListener && mListener->hasChildren())) // ...or we know we have children but haven't fetched them (doesn't obey filter) + { + possibly_has_children = true; + } + if(/*mControlLabel[0] != '\0' && */possibly_has_children) + { + if (sArrowImage) + { + gl_draw_scaled_rotated_image(mIndentation, getRect().getHeight() - ARROW_SIZE - TEXT_PAD, + ARROW_SIZE, ARROW_SIZE, mControlLabelRotation, sArrowImage->getImage(), sFgColor); + } + } + + F32 text_left = (F32)(ARROW_SIZE + TEXT_PAD + ICON_WIDTH + ICON_PAD + mIndentation); + + // If we have keyboard focus, draw selection filled + BOOL show_context = getRoot()->getShowSelectionContext(); + BOOL filled = show_context || (getRoot()->getParentPanel()->hasFocus()); + + // always render "current" item, only render other selected items if + // mShowSingleSelection is FALSE + if( mIsSelected ) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + LLColor4 bg_color = sHighlightBgColor; + //const S32 TRAILING_PAD = 5; // It just looks better with this. + if (!mIsCurSelection) + { + // do time-based fade of extra objects + F32 fade_time = getRoot()->getSelectionFadeElapsedTime(); + if (getRoot()->getShowSingleSelection()) + { + // fading out + bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, bg_color.mV[VALPHA], 0.f); + } + else + { + // fading in + bg_color.mV[VALPHA] = clamp_rescale(fade_time, 0.f, 0.4f, 0.f, bg_color.mV[VALPHA]); + } + } + + gl_rect_2d( + 0, + getRect().getHeight(), + getRect().getWidth() - 2, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), + bg_color, filled); + if (mIsCurSelection) + { + gl_rect_2d( + 0, + getRect().getHeight(), + getRect().getWidth() - 2, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), + sHighlightFgColor, FALSE); + } + if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) + { + gl_rect_2d( + 0, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, + getRect().getWidth() - 2, + 2, + sHighlightFgColor, FALSE); + if (show_context) + { + gl_rect_2d( + 0, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, + getRect().getWidth() - 2, + 2, + sHighlightBgColor, TRUE); + } + } + } + if (mDragAndDropTarget) + { + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gl_rect_2d( + 0, + getRect().getHeight(), + getRect().getWidth() - 2, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD), + sHighlightBgColor, FALSE); + + if (getRect().getHeight() > llround(sFont->getLineHeight()) + ICON_PAD + 2) + { + gl_rect_2d( + 0, + llfloor(getRect().getHeight() - sFont->getLineHeight() - ICON_PAD) - 2, + getRect().getWidth() - 2, + 2, + sHighlightBgColor, FALSE); + } + mDragAndDropTarget = FALSE; + } + + + if(mIcon) + { + mIcon->draw(mIndentation + ARROW_SIZE + TEXT_PAD, getRect().getHeight() - mIcon->getHeight()); + } + + if (!mLabel.empty()) + { + // highlight filtered text + BOOL debug_filters = getRoot()->getDebugFilters(); + LLColor4 color = ( (mIsSelected && filled) ? sHighlightFgColor : sFgColor ); + F32 right_x; + F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; + + if (debug_filters) + { + if (!getFiltered() && !possibly_has_children) + { + color.mV[VALPHA] *= 0.5f; + } + + LLColor4 filter_color = mLastFilterGeneration >= getRoot()->getFilter()->getCurrentGeneration() ? LLColor4(0.5f, 0.8f, 0.5f, 1.f) : LLColor4(0.8f, 0.5f, 0.5f, 1.f); + sSmallFont->renderUTF8(mStatusText, 0, text_left, y, filter_color, + LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x, FALSE ); + text_left = right_x; + } + + + if ( mIsLoading + && mTimeSinceRequestStart.getElapsedTimeF32() >= gSavedSettings.getF32("FolderLoadingMessageWaitTime") ) + { + sFont->renderUTF8(LLTrans::getString("LoadingData"), 0, text_left, y, sSearchStatusColor, + LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE); + text_left = right_x; + } + + sFont->renderUTF8( mLabel, 0, text_left, y, color, + LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x, FALSE ); + if (!mLabelSuffix.empty()) + { + sFont->renderUTF8( mLabelSuffix, 0, right_x, y, sSuffixColor, + LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + S32_MAX, S32_MAX, &right_x, FALSE ); + } + + if (sBoxImage.notNull() && mStringMatchOffset != std::string::npos) + { + // don't draw backgrounds for zero-length strings + S32 filter_string_length = getRoot()->getFilterSubString().size(); + if (filter_string_length > 0) + { + std::string combined_string = mLabel + mLabelSuffix; + S32 left = llround(text_left) + sFont->getWidth(combined_string, 0, mStringMatchOffset) - 1; + S32 right = left + sFont->getWidth(combined_string, mStringMatchOffset, filter_string_length) + 2; + S32 bottom = llfloor(getRect().getHeight() - sFont->getLineHeight() - 3); + S32 top = getRect().getHeight(); + + LLRect box_rect(left, top, right, bottom); + sBoxImage->draw(box_rect, sFilterBGColor); + F32 match_string_left = text_left + sFont->getWidthF32(combined_string, 0, mStringMatchOffset); + F32 y = (F32)getRect().getHeight() - sFont->getLineHeight() - (F32)TEXT_PAD; + sFont->renderUTF8( combined_string, mStringMatchOffset, match_string_left, y, + sFilterTextColor, LLFontGL::LEFT, LLFontGL::BOTTOM, mLabelStyle, LLFontGL::NO_SHADOW, + filter_string_length, S32_MAX, &right_x, FALSE ); + } + } + } + + if( sDebugRects ) + { + drawDebugRect(); + } + + //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) + //std::set::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); + //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) + //{ + // drawDebugRect(); + //} +} + + +///---------------------------------------------------------------------------- +/// Class LLFolderViewFolder +///---------------------------------------------------------------------------- + +LLFolderViewFolder::LLFolderViewFolder( const LLFolderViewItem::Params& p ): +LLFolderViewItem( p ), // 0 = no create time +mIsOpen(FALSE), +mExpanderHighlighted(FALSE), +mCurHeight(0.f), +mTargetHeight(0.f), +mAutoOpenCountdown(0.f), +mSubtreeCreationDate(0), +mAmTrash(LLFolderViewFolder::UNKNOWN), +mLastArrangeGeneration( -1 ), +mLastCalculatedWidth(0), +mCompletedFilterGeneration(-1), +mMostFilteredDescendantGeneration(-1), +mNeedsSort(false) +{} + +// Destroys the object +LLFolderViewFolder::~LLFolderViewFolder( void ) +{ + // The LLView base class takes care of object destruction. make sure that we + // don't have mouse or keyboard focus + gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() +} + +// addToFolder() returns TRUE if it succeeds. FALSE otherwise +BOOL LLFolderViewFolder::addToFolder(LLFolderViewFolder* folder, LLFolderView* root) +{ + if (!folder) + { + return FALSE; + } + mParentFolder = folder; + root->addItemID(getListener()->getUUID(), this); + return folder->addFolder(this); +} + +// Finds width and height of this object and it's children. Also +// makes sure that this view and it's children are the right size. +S32 LLFolderViewFolder::arrange( S32* width, S32* height, S32 filter_generation) +{ + // sort before laying out contents + if (mNeedsSort) + { + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + mNeedsSort = false; + } + + mHasVisibleChildren = hasFilteredDescendants(filter_generation); + + LLInventoryFilter::EFolderShow show_folder_state = getRoot()->getFilter()->getShowFolderState(); + + // calculate height as a single item (without any children), and reshapes rectangle to match + LLFolderViewItem::arrange( width, height, filter_generation ); + + // clamp existing animated height so as to never get smaller than a single item + mCurHeight = llmax((F32)*height, mCurHeight); + + // initialize running height value as height of single item in case we have no children + *height = getItemHeight(); + F32 running_height = (F32)*height; + F32 target_height = (F32)*height; + + // are my children visible? + if (needsArrange()) + { + // set last arrange generation first, in case children are animating + // and need to be arranged again + mLastArrangeGeneration = getRoot()->getArrangeGeneration(); + if (mIsOpen) + { + // Add sizes of children + S32 parent_item_height = getRect().getHeight(); + + for(folders_t::iterator fit = mFolders.begin(); fit != mFolders.end(); ++fit) + { + LLFolderViewFolder* folderp = (*fit); + if (getRoot()->getDebugFilters()) + { + folderp->setVisible(TRUE); + } + else + { + folderp->setVisible(show_folder_state == LLInventoryFilter::SHOW_ALL_FOLDERS || // always show folders? + (folderp->getFiltered(filter_generation) || folderp->hasFilteredDescendants(filter_generation))); // passed filter or has descendants that passed filter + } + + if (folderp->getVisible()) + { + S32 child_width = *width; + S32 child_height = 0; + S32 child_top = parent_item_height - llround(running_height); + + target_height += folderp->arrange( &child_width, &child_height, filter_generation ); + + running_height += (F32)child_height; + *width = llmax(*width, child_width); + folderp->setOrigin( 0, child_top - folderp->getRect().getHeight() ); + } + } + for(items_t::iterator iit = mItems.begin(); + iit != mItems.end(); ++iit) + { + LLFolderViewItem* itemp = (*iit); + if (getRoot()->getDebugFilters()) + { + itemp->setVisible(TRUE); + } + else + { + itemp->setVisible(itemp->getFiltered(filter_generation)); + } + + if (itemp->getVisible()) + { + S32 child_width = *width; + S32 child_height = 0; + S32 child_top = parent_item_height - llround(running_height); + + target_height += itemp->arrange( &child_width, &child_height, filter_generation ); + // don't change width, as this item is as wide as its parent folder by construction + itemp->reshape( itemp->getRect().getWidth(), child_height); + + running_height += (F32)child_height; + *width = llmax(*width, child_width); + itemp->setOrigin( 0, child_top - itemp->getRect().getHeight() ); + } + } + } + + mTargetHeight = target_height; + // cache this width so next time we can just return it + mLastCalculatedWidth = *width; + } + else + { + // just use existing width + *width = mLastCalculatedWidth; + } + + // animate current height towards target height + if (llabs(mCurHeight - mTargetHeight) > 1.f) + { + mCurHeight = lerp(mCurHeight, mTargetHeight, LLCriticalDamp::getInterpolant(mIsOpen ? FOLDER_OPEN_TIME_CONSTANT : FOLDER_CLOSE_TIME_CONSTANT)); + + requestArrange(); + + // hide child elements that fall out of current animated height + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + // number of pixels that bottom of folder label is from top of parent folder + if (getRect().getHeight() - (*fit)->getRect().mTop + (*fit)->getItemHeight() + > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + { + // hide if beyond current folder height + (*fit)->setVisible(FALSE); + } + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + // number of pixels that bottom of item label is from top of parent folder + if (getRect().getHeight() - (*iit)->getRect().mBottom + > llround(mCurHeight) + MAX_FOLDER_ITEM_OVERLAP) + { + (*iit)->setVisible(FALSE); + } + } + } + else + { + mCurHeight = mTargetHeight; + } + + // don't change width as this item is already as wide as its parent folder + reshape(getRect().getWidth(),llround(mCurHeight)); + + // pass current height value back to parent + *height = llround(mCurHeight); + + return llround(mTargetHeight); +} + +BOOL LLFolderViewFolder::needsArrange() +{ + return mLastArrangeGeneration < getRoot()->getArrangeGeneration(); +} + +void LLFolderViewFolder::requestSort() +{ + mNeedsSort = true; + // whenever item order changes, we need to lay things out again + requestArrange(); +} + +void LLFolderViewFolder::setCompletedFilterGeneration(S32 generation, BOOL recurse_up) +{ + mMostFilteredDescendantGeneration = llmin(mMostFilteredDescendantGeneration, generation); + mCompletedFilterGeneration = generation; + // only aggregate up if we are a lower (older) value + if (recurse_up && mParentFolder && generation < mParentFolder->getCompletedFilterGeneration()) + { + mParentFolder->setCompletedFilterGeneration(generation, TRUE); + } +} + +void LLFolderViewFolder::filter( LLInventoryFilter& filter) +{ + S32 filter_generation = filter.getCurrentGeneration(); + // if failed to pass filter newer than must_pass_generation + // you will automatically fail this time, so we only + // check against items that have passed the filter + S32 must_pass_generation = filter.getMustPassGeneration(); + + // if we have already been filtered against this generation, skip out + if (getCompletedFilterGeneration() >= filter_generation) + { + return; + } + + // filter folder itself + if (getLastFilterGeneration() < filter_generation) + { + if (getLastFilterGeneration() >= must_pass_generation && // folder has been compared to a valid precursor filter + !mFiltered) // and did not pass the filter + { + // go ahead and flag this folder as done + mLastFilterGeneration = filter_generation; + } + else + { + // filter self only on first pass through + LLFolderViewItem::filter( filter ); + } + } + + if (getRoot()->getDebugFilters()) + { + mStatusText = llformat("%d", mLastFilterGeneration); + mStatusText += llformat("(%d)", mCompletedFilterGeneration); + mStatusText += llformat("+%d", mMostFilteredDescendantGeneration); + } + + // all descendants have been filtered later than must pass generation + // but none passed + if(getCompletedFilterGeneration() >= must_pass_generation && !hasFilteredDescendants(must_pass_generation)) + { + // don't traverse children if we've already filtered them since must_pass_generation + // and came back with nothing + return; + } + + // we entered here with at least one filter iteration left + // check to see if we have any more before continuing on to children + if (filter.getFilterCount() < 0) + { + return; + } + + // when applying a filter, matching folders get their contents downloaded first + if (filter.isNotDefault() && getFiltered(filter.getMinRequiredGeneration()) && (mListener && !gInventory.isCategoryComplete(mListener->getUUID()))) + { + gInventory.startBackgroundFetch(mListener->getUUID()); + } + + // now query children + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + // have we run out of iterations this frame? + if (filter.getFilterCount() < 0) + { + break; + } + + // mMostFilteredDescendantGeneration might have been reset + // in which case we need to update it even for folders that + // don't need to be filtered anymore + if ((*fit)->getCompletedFilterGeneration() >= filter_generation) + { + // track latest generation to pass any child items + if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter.getMinRequiredGeneration())) + { + mMostFilteredDescendantGeneration = filter_generation; + if (getRoot()->needsAutoSelect()) + { + (*fit)->setOpenArrangeRecursively(TRUE); + } + } + // just skip it, it has already been filtered + continue; + } + + // update this folders filter status (and children) + (*fit)->filter( filter ); + + // track latest generation to pass any child items + if ((*fit)->getFiltered() || (*fit)->hasFilteredDescendants(filter_generation)) + { + mMostFilteredDescendantGeneration = filter_generation; + if (getRoot()->needsAutoSelect()) + { + (*fit)->setOpenArrangeRecursively(TRUE); + } + } + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if (filter.getFilterCount() < 0) + { + break; + } + if ((*iit)->getLastFilterGeneration() >= filter_generation) + { + if ((*iit)->getFiltered()) + { + mMostFilteredDescendantGeneration = filter_generation; + } + continue; + } + + if ((*iit)->getLastFilterGeneration() >= must_pass_generation && + !(*iit)->getFiltered(must_pass_generation)) + { + // failed to pass an earlier filter that was a subset of the current one + // go ahead and flag this item as done + (*iit)->setFiltered(FALSE, filter_generation); + continue; + } + + (*iit)->filter( filter ); + + if ((*iit)->getFiltered(filter.getMinRequiredGeneration())) + { + mMostFilteredDescendantGeneration = filter_generation; + } + } + + // if we didn't use all filter iterations + // that means we filtered all of our descendants + // instead of exhausting the filter count for this frame + if (filter.getFilterCount() > 0) + { + // flag this folder as having completed filter pass for all descendants + setCompletedFilterGeneration(filter_generation, FALSE/*dont recurse up to root*/); + } +} + +void LLFolderViewFolder::setFiltered(BOOL filtered, S32 filter_generation) +{ + // if this folder is now filtered, but wasn't before + // (it just passed) + if (filtered && !mFiltered) + { + // reset current height, because last time we drew it + // it might have had more visible items than now + mCurHeight = 0.f; + } + + LLFolderViewItem::setFiltered(filtered, filter_generation); +} + +void LLFolderViewFolder::dirtyFilter() +{ + // we're a folder, so invalidate our completed generation + setCompletedFilterGeneration(-1, FALSE); + LLFolderViewItem::dirtyFilter(); +} + +BOOL LLFolderViewFolder::hasFilteredDescendants() +{ + return mMostFilteredDescendantGeneration >= getRoot()->getFilter()->getCurrentGeneration(); +} + +// Passes selection information on to children and record selection +// information if necessary. +BOOL LLFolderViewFolder::setSelection(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus) +{ + BOOL rv = FALSE; + if( selection == this ) + { + mIsSelected = TRUE; + if(mListener) + { + mListener->selectItem(); + } + rv = TRUE; + } + else + { + mIsSelected = FALSE; + rv = FALSE; + } + BOOL child_selected = FALSE; + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if((*fit)->setSelection(selection, openitem, take_keyboard_focus)) + { + rv = TRUE; + child_selected = TRUE; + mNumDescendantsSelected++; + } + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if((*iit)->setSelection(selection, openitem, take_keyboard_focus)) + { + rv = TRUE; + child_selected = TRUE; + mNumDescendantsSelected++; + } + } + if(openitem && child_selected) + { + setOpenArrangeRecursively(TRUE); + } + return rv; +} + +// This method is used to change the selection of an item. If +// selection is 'this', then note selection as true. Returns TRUE +// if this or a child is now selected. +BOOL LLFolderViewFolder::changeSelection(LLFolderViewItem* selection, + BOOL selected) +{ + BOOL rv = FALSE; + if(selection == this) + { + mIsSelected = selected; + if(mListener && selected) + { + mListener->selectItem(); + } + rv = TRUE; + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if((*fit)->changeSelection(selection, selected)) + { + if (selected) + { + mNumDescendantsSelected++; + } + else + { + mNumDescendantsSelected--; + } + rv = TRUE; + } + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if((*iit)->changeSelection(selection, selected)) + { + if (selected) + { + mNumDescendantsSelected++; + } + else + { + mNumDescendantsSelected--; + } + rv = TRUE; + } + } + return rv; +} + +S32 LLFolderViewFolder::extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& selected_items) +{ + S32 num_selected = 0; + + // pass on to child folders first + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + num_selected += (*fit)->extendSelection(selection, last_selected, selected_items); + mNumDescendantsSelected += num_selected; + } + + // handle selection of our immediate children... + BOOL reverse_select = FALSE; + BOOL found_last_selected = FALSE; + BOOL found_selection = FALSE; + LLDynamicArray items_to_select; + LLFolderViewItem* item; + + //...folders first... + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + item = (*fit); + if(item == selection) + { + found_selection = TRUE; + } + else if (item == last_selected) + { + found_last_selected = TRUE; + if (found_selection) + { + reverse_select = TRUE; + } + } + + if (found_selection || found_last_selected) + { + // deselect currently selected items so they can be pushed back on queue + if (item->isSelected()) + { + item->changeSelection(item, FALSE); + } + items_to_select.put(item); + } + + if (found_selection && found_last_selected) + { + break; + } + } + + if (!(found_selection && found_last_selected)) + { + //,,,then items + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + item = (*iit); + if(item == selection) + { + found_selection = TRUE; + } + else if (item == last_selected) + { + found_last_selected = TRUE; + if (found_selection) + { + reverse_select = TRUE; + } + } + + if (found_selection || found_last_selected) + { + // deselect currently selected items so they can be pushed back on queue + if (item->isSelected()) + { + item->changeSelection(item, FALSE); + } + items_to_select.put(item); + } + + if (found_selection && found_last_selected) + { + break; + } + } + } + + if (found_last_selected && found_selection) + { + // we have a complete selection inside this folder + for (S32 index = reverse_select ? items_to_select.getLength() - 1 : 0; + reverse_select ? index >= 0 : index < items_to_select.getLength(); reverse_select ? index-- : index++) + { + LLFolderViewItem* item = items_to_select[index]; + if (item->changeSelection(item, TRUE)) + { + selected_items.put(item); + mNumDescendantsSelected++; + num_selected++; + } + } + } + else if (found_selection) + { + // last selection was not in this folder....go ahead and select just the new item + if (selection->changeSelection(selection, TRUE)) + { + selected_items.put(selection); + mNumDescendantsSelected++; + num_selected++; + } + } + + return num_selected; +} + +void LLFolderViewFolder::recursiveDeselect(BOOL deselect_self) +{ + // make sure we don't have negative values + llassert(mNumDescendantsSelected >= 0); + + if (mIsSelected && deselect_self) + { + mIsSelected = FALSE; + + // update ancestors' count of selected descendents + LLFolderViewFolder* parent_folder = getParentFolder(); + while(parent_folder) + { + parent_folder->mNumDescendantsSelected--; + parent_folder = parent_folder->getParentFolder(); + } + } + + if (0 == mNumDescendantsSelected) + { + return; + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + LLFolderViewItem* item = (*iit); + item->recursiveDeselect(TRUE); + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + LLFolderViewFolder* folder = (*fit); + folder->recursiveDeselect(TRUE); + } + +} + +void LLFolderViewFolder::destroyView() +{ + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + LLFolderViewItem* item = (*iit); + getRoot()->removeItemID(item->getListener()->getUUID()); + } + + std::for_each(mItems.begin(), mItems.end(), DeletePointer()); + mItems.clear(); + + while (!mFolders.empty()) + { + LLFolderViewFolder *folderp = mFolders.back(); + folderp->destroyView(); // removes entry from mFolders + } + + deleteAllChildren(); + + if (mParentFolder) + { + mParentFolder->removeView(this); + } +} + +// remove the specified item (and any children) if possible. Return +// TRUE if the item was deleted. +BOOL LLFolderViewFolder::removeItem(LLFolderViewItem* item) +{ + if(item->remove()) + { + //RN: this seem unneccessary as remove() moves to trash + //removeView(item); + return TRUE; + } + return FALSE; +} + +// simply remove the view (and any children) Don't bother telling the +// listeners. +void LLFolderViewFolder::removeView(LLFolderViewItem* item) +{ + if (!item || item->getParentFolder() != this) + { + return; + } + // deselect without traversing hierarchy + item->recursiveDeselect(TRUE); + getRoot()->removeFromSelectionList(item); + extractItem(item); + delete item; +} + +// extractItem() removes the specified item from the folder, but +// doesn't delete it. +void LLFolderViewFolder::extractItem( LLFolderViewItem* item ) +{ + items_t::iterator it = std::find(mItems.begin(), mItems.end(), item); + if(it == mItems.end()) + { + // This is an evil downcast. However, it's only doing + // pointer comparison to find if (which it should be ) the + // item is in the container, so it's pretty safe. + LLFolderViewFolder* f = reinterpret_cast(item); + folders_t::iterator ft; + ft = std::find(mFolders.begin(), mFolders.end(), f); + if(ft != mFolders.end()) + { + mFolders.erase(ft); + } + } + else + { + mItems.erase(it); + } + //item has been removed, need to update filter + dirtyFilter(); + //because an item is going away regardless of filter status, force rearrange + requestArrange(); + getRoot()->removeItemID(item->getListener()->getUUID()); + removeChild(item); +} + +bool LLFolderViewFolder::isTrash() const +{ + if (mAmTrash == LLFolderViewFolder::UNKNOWN) + { + mAmTrash = mListener->getUUID() == gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH, false) ? LLFolderViewFolder::TRASH : LLFolderViewFolder::NOT_TRASH; + } + return mAmTrash == LLFolderViewFolder::TRASH; +} + +void LLFolderViewFolder::sortBy(U32 order) +{ + if (!mSortFunction.updateSort(order)) + { + // No changes. + return; + } + + // Propegate this change to sub folders + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->sortBy(order); + } + + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + + if (order & LLInventoryFilter::SO_DATE) + { + time_t latest = 0; + + if (!mItems.empty()) + { + LLFolderViewItem* item = *(mItems.begin()); + latest = item->getCreationDate(); + } + + if (!mFolders.empty()) + { + LLFolderViewFolder* folder = *(mFolders.begin()); + if (folder->getCreationDate() > latest) + { + latest = folder->getCreationDate(); + } + } + mSubtreeCreationDate = latest; + } +} + +void LLFolderViewFolder::setItemSortOrder(U32 ordering) +{ + if (mSortFunction.updateSort(ordering)) + { + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setItemSortOrder(ordering); + } + + mFolders.sort(mSortFunction); + mItems.sort(mSortFunction); + } +} + +EInventorySortGroup LLFolderViewFolder::getSortGroup() const +{ + if (isTrash()) + { + return SG_TRASH_FOLDER; + } + + // Folders that can't be moved are 'system' folders. + if( mListener ) + { + if( !(mListener->isItemMovable()) ) + { + return SG_SYSTEM_FOLDER; + } + } + + return SG_NORMAL_FOLDER; +} + +BOOL LLFolderViewFolder::isMovable() +{ + if( mListener ) + { + if( !(mListener->isItemMovable()) ) + { + return FALSE; + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if(!(*iit)->isMovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isMovable()) + { + return FALSE; + } + } + } + return TRUE; +} + + +BOOL LLFolderViewFolder::isRemovable() +{ + if( mListener ) + { + if( !(mListener->isItemRemovable()) ) + { + return FALSE; + } + + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + if(!(*iit)->isRemovable()) + { + return FALSE; + } + } + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + if(!(*fit)->isRemovable()) + { + return FALSE; + } + } + } + return TRUE; +} + +// this is an internal method used for adding items to folders. +BOOL LLFolderViewFolder::addItem(LLFolderViewItem* item) +{ + mItems.push_back(item); + item->setRect(LLRect(0, 0, getRect().getWidth(), 0)); + item->setVisible(FALSE); + addChild( item ); + item->dirtyFilter(); + requestArrange(); + requestSort(); + return TRUE; +} + +// this is an internal method used for adding items to folders. +BOOL LLFolderViewFolder::addFolder(LLFolderViewFolder* folder) +{ + mFolders.push_back(folder); + folder->setOrigin(0, 0); + folder->reshape(getRect().getWidth(), 0); + folder->setVisible(FALSE); + addChild( folder ); + folder->dirtyFilter(); + // rearrange all descendants too, as our indentation level might have changed + folder->requestArrange(TRUE); + requestSort(); + return TRUE; +} + +void LLFolderViewFolder::requestArrange(BOOL include_descendants) +{ + mLastArrangeGeneration = -1; + // flag all items up to root + if (mParentFolder) + { + mParentFolder->requestArrange(); + } + + if (include_descendants) + { + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end(); + ++iter) + { + (*iter)->requestArrange(TRUE); + } + } +} + +void LLFolderViewFolder::toggleOpen() +{ + setOpen(!mIsOpen); +} + +// Force a folder open or closed +void LLFolderViewFolder::setOpen(BOOL openitem) +{ + setOpenArrangeRecursively(openitem); +} + +void LLFolderViewFolder::setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse) +{ + BOOL was_open = mIsOpen; + mIsOpen = openitem; + if (mListener) + { + if(!was_open && openitem) + { + mListener->openItem(); + } + else if(was_open && !openitem) + { + mListener->closeItem(); + } + } + + if (recurse == RECURSE_DOWN || recurse == RECURSE_UP_DOWN) + { + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->setOpenArrangeRecursively(openitem, RECURSE_DOWN); /* Flawfinder: ignore */ + } + } + if (mParentFolder && (recurse == RECURSE_UP || recurse == RECURSE_UP_DOWN)) + { + mParentFolder->setOpenArrangeRecursively(openitem, RECURSE_UP); + } + + if (was_open != mIsOpen) + { + requestArrange(); + } +} + +BOOL LLFolderViewFolder::handleDragAndDropFromChild(MASK mask, + BOOL drop, + EDragAndDropType c_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + BOOL accepted = mListener && mListener->dragOrDrop(mask,drop,c_type,cargo_data); + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + + // drag and drop to child item, so clear pending auto-opens + getRoot()->autoOpenTest(NULL); + + return TRUE; +} + +void LLFolderViewFolder::openItem( void ) +{ + toggleOpen(); +} + +void LLFolderViewFolder::applyFunctorRecursively(LLFolderViewFunctor& functor) +{ + functor.doFolder(this); + + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->applyFunctorRecursively(functor); + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + functor.doItem((*iit)); + } +} + +void LLFolderViewFolder::applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor) +{ + functor(mListener); + for (folders_t::iterator iter = mFolders.begin(); + iter != mFolders.end();) + { + folders_t::iterator fit = iter++; + (*fit)->applyListenerFunctorRecursively(functor); + } + for (items_t::iterator iter = mItems.begin(); + iter != mItems.end();) + { + items_t::iterator iit = iter++; + (*iit)->applyListenerFunctorRecursively(functor); + } +} + +// LLView functionality +BOOL LLFolderViewFolder::handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg) +{ + LLFolderView* root_view = getRoot(); + + BOOL handled = FALSE; + if(mIsOpen) + { + handled = childrenHandleDragAndDrop(x, y, mask, drop, cargo_type, + cargo_data, accept, tooltip_msg) != NULL; + } + + if (!handled) + { + BOOL accepted = mListener && mListener->dragOrDrop(mask, drop,cargo_type,cargo_data); + + if (accepted) + { + mDragAndDropTarget = TRUE; + *accept = ACCEPT_YES_MULTI; + } + else + { + *accept = ACCEPT_NO; + } + + if (!drop && accepted) + { + root_view->autoOpenTest(this); + } + + lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLFolderViewFolder" << llendl; + } + + return TRUE; +} + + +BOOL LLFolderViewFolder::handleRightMouseDown( S32 x, S32 y, MASK mask ) +{ + BOOL handled = FALSE; + // fetch contents of this folder, as context menu can depend on contents + // still, user would have to open context menu again to see the changes + gInventory.fetchDescendentsOf(mListener->getUUID()); + + if( mIsOpen ) + { + handled = childrenHandleRightMouseDown( x, y, mask ) != NULL; + } + if (!handled) + { + handled = LLFolderViewItem::handleRightMouseDown( x, y, mask ); + } + return handled; +} + + +BOOL LLFolderViewFolder::handleHover(S32 x, S32 y, MASK mask) +{ + BOOL handled = LLView::handleHover(x, y, mask); + + if (!handled) + { + // this doesn't do child processing + handled = LLFolderViewItem::handleHover(x, y, mask); + } + + //if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD && y > getRect().getHeight() - ) + //{ + // gViewerWindow->setCursor(UI_CURSOR_ARROW); + // mExpanderHighlighted = TRUE; + // handled = TRUE; + //} + return handled; +} + +BOOL LLFolderViewFolder::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + BOOL handled = FALSE; + if( mIsOpen ) + { + handled = childrenHandleMouseDown(x,y,mask) != NULL; + } + if( !handled ) + { + if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD) + { + toggleOpen(); + handled = TRUE; + } + else + { + // do normal selection logic + handled = LLFolderViewItem::handleMouseDown(x, y, mask); + } + } + + return handled; +} + +BOOL LLFolderViewFolder::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + const LLUUID &cat_uuid = getListener()->getUUID(); + const LLViewerInventoryCategory *cat = gInventory.getCategory(cat_uuid); + if (cat && cat->getPreferredType() == LLAssetType::AT_OUTFIT) + { + getListener()->performAction(NULL, NULL,"replaceoutfit"); + return TRUE; + } + + BOOL handled = FALSE; + if( mIsOpen ) + { + handled = childrenHandleDoubleClick( x, y, mask ) != NULL; + } + if( !handled ) + { + if(x < LEFT_INDENTATION + mIndentation && x > mIndentation - LEFT_PAD) + { + // don't select when user double-clicks plus sign + // so as not to contradict single-click behavior + toggleOpen(); + } + else + { + setSelectionFromRoot(this, FALSE); + toggleOpen(); + } + handled = TRUE; + } + return handled; +} + +void LLFolderViewFolder::draw() +{ + if (mAutoOpenCountdown != 0.f) + { + mControlLabelRotation = mAutoOpenCountdown * -90.f; + } + else if (mIsOpen) + { + mControlLabelRotation = lerp(mControlLabelRotation, -90.f, LLCriticalDamp::getInterpolant(0.04f)); + } + else + { + mControlLabelRotation = lerp(mControlLabelRotation, 0.f, LLCriticalDamp::getInterpolant(0.025f)); + } + + bool possibly_has_children = false; + bool up_to_date = mListener && mListener->isUpToDate(); + if(!up_to_date && mListener && mListener->hasChildren()) // we know we have children but haven't fetched them (doesn't obey filter) + { + possibly_has_children = true; + } + + + BOOL loading = ( mIsOpen && possibly_has_children && !up_to_date ); + + if ( loading && !mIsLoading ) + { + // Measure how long we've been in the loading state + mTimeSinceRequestStart.reset(); + } + + mIsLoading = loading; + + LLFolderViewItem::draw(); + + // draw children if root folder, or any other folder that is open or animating to closed state + if( getRoot() == this || (mIsOpen || mCurHeight != mTargetHeight )) + { + LLView::draw(); + } + + mExpanderHighlighted = FALSE; +} + +time_t LLFolderViewFolder::getCreationDate() const +{ + return llmax(mCreationDate, mSubtreeCreationDate); +} + + +BOOL LLFolderViewFolder::potentiallyVisible() +{ + // folder should be visible by it's own filter status + return LLFolderViewItem::potentiallyVisible() + // or one or more of its descendants have passed the minimum filter requirement + || hasFilteredDescendants(getRoot()->getFilter()->getMinRequiredGeneration()) + // or not all of its descendants have been checked against minimum filter requirement + || getCompletedFilterGeneration() < getRoot()->getFilter()->getMinRequiredGeneration(); +} + +// this does prefix traversal, as folders are listed above their contents +LLFolderViewItem* LLFolderViewFolder::getNextFromChild( LLFolderViewItem* item, BOOL include_children ) +{ + BOOL found_item = FALSE; + + LLFolderViewItem* result = NULL; + // when not starting from a given item, start at beginning + if(item == NULL) + { + found_item = TRUE; + } + + // find current item among children + folders_t::iterator fit = mFolders.begin(); + folders_t::iterator fend = mFolders.end(); + + items_t::iterator iit = mItems.begin(); + items_t::iterator iend = mItems.end(); + + // if not trivially starting at the beginning, we have to find the current item + if (!found_item) + { + // first, look among folders, since they are always above items + for(; fit != fend; ++fit) + { + if(item == (*fit)) + { + found_item = TRUE; + // if we are on downwards traversal + if (include_children && (*fit)->isOpen()) + { + // look for first descendant + return (*fit)->getNextFromChild(NULL, TRUE); + } + // otherwise advance to next folder + ++fit; + include_children = TRUE; + break; + } + } + + // didn't find in folders? Check items... + if (!found_item) + { + for(; iit != iend; ++iit) + { + if(item == (*iit)) + { + found_item = TRUE; + // point to next item + ++iit; + break; + } + } + } + } + + if (!found_item) + { + // you should never call this method with an item that isn't a child + // so we should always find something + llassert(FALSE); + return NULL; + } + + // at this point, either iit or fit point to a candidate "next" item + // if both are out of range, we need to punt up to our parent + + // now, starting from found folder, continue through folders + // searching for next visible folder + while(fit != fend && !(*fit)->getVisible()) + { + // turn on downwards traversal for next folder + ++fit; + } + + if (fit != fend) + { + result = (*fit); + } + else + { + // otherwise, scan for next visible item + while(iit != iend && !(*iit)->getVisible()) + { + ++iit; + } + + // check to see if we have a valid item + if (iit != iend) + { + result = (*iit); + } + } + + if( !result && mParentFolder ) + { + // If there are no siblings or children to go to, recurse up one level in the tree + // and skip children for this folder, as we've already discounted them + result = mParentFolder->getNextFromChild(this, FALSE); + } + + return result; +} + +// this does postfix traversal, as folders are listed above their contents +LLFolderViewItem* LLFolderViewFolder::getPreviousFromChild( LLFolderViewItem* item, BOOL include_children ) +{ + BOOL found_item = FALSE; + + LLFolderViewItem* result = NULL; + // when not starting from a given item, start at end + if(item == NULL) + { + found_item = TRUE; + } + + // find current item among children + folders_t::reverse_iterator fit = mFolders.rbegin(); + folders_t::reverse_iterator fend = mFolders.rend(); + + items_t::reverse_iterator iit = mItems.rbegin(); + items_t::reverse_iterator iend = mItems.rend(); + + // if not trivially starting at the end, we have to find the current item + if (!found_item) + { + // first, look among items, since they are always below the folders + for(; iit != iend; ++iit) + { + if(item == (*iit)) + { + found_item = TRUE; + // point to next item + ++iit; + break; + } + } + + // didn't find in items? Check folders... + if (!found_item) + { + for(; fit != fend; ++fit) + { + if(item == (*fit)) + { + found_item = TRUE; + // point to next folder + ++fit; + break; + } + } + } + } + + if (!found_item) + { + // you should never call this method with an item that isn't a child + // so we should always find something + llassert(FALSE); + return NULL; + } + + // at this point, either iit or fit point to a candidate "next" item + // if both are out of range, we need to punt up to our parent + + // now, starting from found item, continue through items + // searching for next visible item + while(iit != iend && !(*iit)->getVisible()) + { + ++iit; + } + + if (iit != iend) + { + // we found an appropriate item + result = (*iit); + } + else + { + // otherwise, scan for next visible folder + while(fit != fend && !(*fit)->getVisible()) + { + ++fit; + } + + // check to see if we have a valid folder + if (fit != fend) + { + // try selecting child element of this folder + if ((*fit)->isOpen()) + { + result = (*fit)->getPreviousFromChild(NULL); + } + else + { + result = (*fit); + } + } + } + + if( !result ) + { + // If there are no siblings or children to go to, recurse up one level in the tree + // which gets back to this folder, which will only be visited if it is a valid, visible item + result = this; + } + + return result; +} + + +bool LLInventorySort::updateSort(U32 order) +{ + if (order != mSortOrder) + { + mSortOrder = order; + mByDate = (order & LLInventoryFilter::SO_DATE); + mSystemToTop = (order & LLInventoryFilter::SO_SYSTEM_FOLDERS_TO_TOP); + mFoldersByName = (order & LLInventoryFilter::SO_FOLDERS_BY_NAME); + return true; + } + return false; +} + +bool LLInventorySort::operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b) +{ + // We sort by name if we aren't sorting by date + // OR if these are folders and we are sorting folders by name. + bool by_name = (!mByDate + || (mFoldersByName + && (a->getSortGroup() != SG_ITEM))); + + if (a->getSortGroup() != b->getSortGroup()) + { + if (mSystemToTop) + { + // Group order is System Folders, Trash, Normal Folders, Items + return (a->getSortGroup() < b->getSortGroup()); + } + else if (mByDate) + { + // Trash needs to go to the bottom if we are sorting by date + if ( (a->getSortGroup() == SG_TRASH_FOLDER) + || (b->getSortGroup() == SG_TRASH_FOLDER)) + { + return (b->getSortGroup() == SG_TRASH_FOLDER); + } + } + } + + if (by_name) + { + S32 compare = LLStringUtil::compareDict(a->getLabel(), b->getLabel()); + if (0 == compare) + { + return (a->getCreationDate() > b->getCreationDate()); + } + else + { + return (compare < 0); + } + } + else + { + // BUG: This is very very slow. The getCreationDate() is log n in number + // of inventory items. + time_t first_create = a->getCreationDate(); + time_t second_create = b->getCreationDate(); + if (first_create == second_create) + { + return (LLStringUtil::compareDict(a->getLabel(), b->getLabel()) < 0); + } + else + { + return (first_create > second_create); + } + } +} diff --git a/indra/newview/llfolderviewitem.h b/indra/newview/llfolderviewitem.h new file mode 100644 index 0000000000..31866c83c8 --- /dev/null +++ b/indra/newview/llfolderviewitem.h @@ -0,0 +1,528 @@ +/** +* @file llfolderviewitem.h +* @brief Items and folders that can appear in a hierarchical folder view +* +* $LicenseInfo:firstyear=2001&license=viewergpl$ +* +* Copyright (c) 2001-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#ifndef LLFOLDERVIEWITEM_H +#define LLFOLDERVIEWITEM_H + +#include "llview.h" + +class LLFontGL; +class LLFolderView; +class LLFolderViewEventListener; +class LLFolderViewFolder; +class LLFolderViewFunctor; +class LLFolderViewItem; +class LLFolderViewListenerFunctor; +class LLInventoryFilter; +class LLMenuGL; +class LLUIImage; + +// These are grouping of inventory types. +// Order matters when sorting system folders to the top. +enum EInventorySortGroup +{ + SG_SYSTEM_FOLDER, + SG_TRASH_FOLDER, + SG_NORMAL_FOLDER, + SG_ITEM +}; + +// JAMESDEBUG *TODO: do we really need one sort object per folder? +// can we just have one of these per LLFolderView ? +class LLInventorySort +{ +public: + LLInventorySort() + : mSortOrder(0), + mByDate(false), + mSystemToTop(false), + mFoldersByName(false) { } + + // Returns true if order has changed + bool updateSort(U32 order); + U32 getSort() { return mSortOrder; } + + bool operator()(const LLFolderViewItem* const& a, const LLFolderViewItem* const& b); +private: + U32 mSortOrder; + bool mByDate; + bool mSystemToTop; + bool mFoldersByName; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFolderViewItem +// +// An instance of this class represents a single item in a folder view +// such as an inventory item or a file. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFolderViewItem : public LLView +{ +public: + static void initClass(); + static void cleanupClass(); + + // jamesdebug was LLUICtrl::Params + struct Params : public LLInitParam::Block + { + Optional icon; + Optional root; + Optional listener; + + Optional folder_arrow_image; + Optional selection_image; + + Optional creation_date; //UTC seconds + + Params(); + }; + + // layout constants + static const S32 LEFT_PAD = 5; + static const S32 LEFT_INDENTATION = 13; + static const S32 ICON_PAD = 2; + static const S32 ICON_WIDTH = 16; + static const S32 TEXT_PAD = 1; + static const S32 ARROW_SIZE = 12; + static const S32 MAX_FOLDER_ITEM_OVERLAP = 2; + // animation parameters + static const F32 FOLDER_CLOSE_TIME_CONSTANT; + static const F32 FOLDER_OPEN_TIME_CONSTANT; + +protected: + friend class LLUICtrlFactory; + friend class LLFolderViewEventListener; + + LLFolderViewItem(Params p = LLFolderViewItem::Params()); + + static const LLFontGL* sFont; + static const LLFontGL* sSmallFont; + static LLUIImagePtr sArrowImage; + static LLUIImagePtr sBoxImage; + + std::string mLabel; + std::string mSearchableLabel; + S32 mLabelWidth; + bool mLabelWidthDirty; + time_t mCreationDate; + LLFolderViewFolder* mParentFolder; + LLFolderViewEventListener* mListener; + BOOL mIsSelected; + BOOL mIsCurSelection; + BOOL mSelectPending; + LLFontGL::StyleFlags mLabelStyle; + std::string mLabelSuffix; + LLUIImagePtr mIcon; + std::string mStatusText; + BOOL mHasVisibleChildren; + S32 mIndentation; + S32 mNumDescendantsSelected; + BOOL mFiltered; + S32 mLastFilterGeneration; + std::string::size_type mStringMatchOffset; + F32 mControlLabelRotation; + LLFolderView* mRoot; + BOOL mDragAndDropTarget; + LLUIImagePtr mArrowImage; + LLUIImagePtr mBoxImage; + BOOL mIsLoading; + LLTimer mTimeSinceRequestStart; + + // helper function to change the selection from the root. + void changeSelectionFromRoot(LLFolderViewItem* selection, BOOL selected); + + // helper function to change the selection from the root. + void extendSelectionFromRoot(LLFolderViewItem* selection); + + // this is an internal method used for adding items to folders. A + // no-op at this leve, but reimplemented in derived classes. + virtual BOOL addItem(LLFolderViewItem*) { return FALSE; } + virtual BOOL addFolder(LLFolderViewFolder*) { return FALSE; } + +public: + // This function clears the currently selected item, and records + // the specified selected item appropriately for display and use + // in the UI. If open is TRUE, then folders are opened up along + // the way to the selection. + void setSelectionFromRoot(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus = TRUE); + + // This function is called when the folder view is dirty. It's + // implemented here but called by derived classes when folding the + // views. + void arrangeFromRoot(); + void filterFromRoot( void ); + + void arrangeAndSet(BOOL set_selection, BOOL take_keyboard_focus); + + virtual ~LLFolderViewItem( void ); + + // addToFolder() returns TRUE if it succeeds. FALSE otherwise + enum { ARRANGE = TRUE, DO_NOT_ARRANGE = FALSE }; + virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root); + + virtual EInventorySortGroup getSortGroup() const; + + // Finds width and height of this object and it's children. Also + // makes sure that this view and it's children are the right size. + virtual S32 arrange( S32* width, S32* height, S32 filter_generation ); + virtual S32 getItemHeight(); + + // applies filters to control visibility of inventory items + virtual void filter( LLInventoryFilter& filter); + + // updates filter serial number and optionally propagated value up to root + S32 getLastFilterGeneration() { return mLastFilterGeneration; } + + virtual void dirtyFilter(); + + // If the selection is 'this' then note that otherwise + // ignore. Returns TRUE if this object was affected. If open is + // TRUE, then folders are opened up along the way to the + // selection. + virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus); + + // This method is used to toggle the selection of an item. If + // selection is 'this', then note selection, and return TRUE. + virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); + + // this method is used to group select items + virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items){ return FALSE; } + + // this method is used to group select items + virtual void recursiveDeselect(BOOL deselect_self); + + // gets multiple-element selection + virtual BOOL getSelectionList(std::set &selection){return TRUE;} + + // Returns true is this object and all of its children can be removed (deleted by user) + virtual BOOL isRemovable(); + + // Returns true is this object and all of its children can be moved + virtual BOOL isMovable(); + + // destroys this item recursively + virtual void destroyView(); + + S32 getNumSelectedDescendants() { return mNumDescendantsSelected; } + + BOOL isSelected() { return mIsSelected; } + + void setIsCurSelection(BOOL select) { mIsCurSelection = select; } + + BOOL getIsCurSelection() { return mIsCurSelection; } + + BOOL hasVisibleChildren() { return mHasVisibleChildren; } + + // Call through to the viewed object and return true if it can be + // removed. Returns true if it's removed. + //virtual BOOL removeRecursively(BOOL single_item); + BOOL remove(); + + // Build an appropriate context menu for the item. Flags unused. + void buildContextMenu(LLMenuGL& menu, U32 flags); + + // This method returns the actual name of the thing being + // viewed. This method will ask the viewed object itself. + const std::string& getName( void ) const; + + const std::string& getSearchableLabel( void ) const; + + // This method returns the label displayed on the view. This + // method was primarily added to allow sorting on the folder + // contents possible before the entire view has been constructed. + const std::string& getLabel() const { return mLabel; } + + // Used for sorting, like getLabel() above. + virtual time_t getCreationDate() const { return mCreationDate; } + + LLFolderViewFolder* getParentFolder( void ) { return mParentFolder; } + const LLFolderViewFolder* getParentFolder( void ) const { return mParentFolder; } + + LLFolderViewItem* getNextOpenNode( BOOL include_children = TRUE ); + LLFolderViewItem* getPreviousOpenNode( BOOL include_children = TRUE ); + + const LLFolderViewEventListener* getListener( void ) const { return mListener; } + LLFolderViewEventListener* getListener( void ) { return mListener; } + + // just rename the object. + void rename(const std::string& new_name); + + // open + virtual void openItem( void ); + virtual void preview(void); + + // Show children (unfortunate that this is called "open") + virtual void setOpen(BOOL open = TRUE) {}; + + virtual BOOL isOpen() { return FALSE; } + + virtual LLFolderView* getRoot(); + BOOL isDescendantOf( const LLFolderViewFolder* potential_ancestor ); + S32 getIndentation() { return mIndentation; } + + virtual BOOL potentiallyVisible(); // do we know for a fact that this item has been filtered out? + + virtual BOOL getFiltered(); + virtual BOOL getFiltered(S32 filter_generation); + virtual void setFiltered(BOOL filtered, S32 filter_generation); + + // change the icon + void setIcon(LLUIImagePtr icon); + + // refresh information from the object being viewed. + void refreshFromListener(); + virtual void refresh(); + + virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); + + // LLView functionality + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + + // virtual void handleDropped(); + virtual void draw(); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); +}; + + +// function used for sorting. +typedef bool (*sort_order_f)(LLFolderViewItem* a, LLFolderViewItem* b); + + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFolderViewFolder +// +// An instance of an LLFolderViewFolder represents a collection of +// more folders and items. This is used to build the hierarchy of +// items found in the folder view. :) +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFolderViewFolder : public LLFolderViewItem +{ +protected: + LLFolderViewFolder( const LLFolderViewItem::Params& ); + friend class LLUICtrlFactory; + +public: + typedef enum e_trash + { + UNKNOWN, TRASH, NOT_TRASH + } ETrash; + +protected: + typedef std::list items_t; + typedef std::list folders_t; + items_t mItems; + folders_t mFolders; + LLInventorySort mSortFunction; + + BOOL mIsOpen; + BOOL mExpanderHighlighted; + F32 mCurHeight; + F32 mTargetHeight; + F32 mAutoOpenCountdown; + time_t mSubtreeCreationDate; + mutable ETrash mAmTrash; + S32 mLastArrangeGeneration; + S32 mLastCalculatedWidth; + S32 mCompletedFilterGeneration; + S32 mMostFilteredDescendantGeneration; + bool mNeedsSort; +public: + typedef enum e_recurse_type + { + RECURSE_NO, + RECURSE_UP, + RECURSE_DOWN, + RECURSE_UP_DOWN + } ERecurseType; + + + virtual ~LLFolderViewFolder( void ); + + virtual BOOL potentiallyVisible(); + + LLFolderViewItem* getNextFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); + LLFolderViewItem* getPreviousFromChild( LLFolderViewItem*, BOOL include_children = TRUE ); + + // addToFolder() returns TRUE if it succeeds. FALSE otherwise + virtual BOOL addToFolder(LLFolderViewFolder* folder, LLFolderView* root); + + // Finds width and height of this object and it's children. Also + // makes sure that this view and it's children are the right size. + virtual S32 arrange( S32* width, S32* height, S32 filter_generation ); + + BOOL needsArrange(); + void requestSort(); + + // Returns the sort group (system, trash, folder) for this folder. + virtual EInventorySortGroup getSortGroup() const; + + virtual void setCompletedFilterGeneration(S32 generation, BOOL recurse_up); + virtual S32 getCompletedFilterGeneration() { return mCompletedFilterGeneration; } + + BOOL hasFilteredDescendants(S32 filter_generation) { return mMostFilteredDescendantGeneration >= filter_generation; } + BOOL hasFilteredDescendants(); + + // applies filters to control visibility of inventory items + virtual void filter( LLInventoryFilter& filter); + virtual void setFiltered(BOOL filtered, S32 filter_generation); + virtual void dirtyFilter(); + + // Passes selection information on to children and record + // selection information if necessary. Returns TRUE if this object + // (or a child) was affected. + virtual BOOL setSelection(LLFolderViewItem* selection, BOOL openitem, + BOOL take_keyboard_focus); + + // This method is used to change the selection of an item. If + // selection is 'this', then note selection as true. Returns TRUE + // if this or a child is now selected. + virtual BOOL changeSelection(LLFolderViewItem* selection, BOOL selected); + + // this method is used to group select items + virtual S32 extendSelection(LLFolderViewItem* selection, LLFolderViewItem* last_selected, LLDynamicArray& items); + + virtual void recursiveDeselect(BOOL deselect_self); + + // Returns true is this object and all of its children can be removed. + virtual BOOL isRemovable(); + + // Returns true is this object and all of its children can be moved + virtual BOOL isMovable(); + + // destroys this folder, and all children + virtual void destroyView(); + + // If this folder can be removed, remove all children that can be + // removed, return TRUE if this is empty after the operation and + // it's viewed folder object can be removed. + //virtual BOOL removeRecursively(BOOL single_item); + //virtual BOOL remove(); + + // remove the specified item (and any children) if + // possible. Return TRUE if the item was deleted. + BOOL removeItem(LLFolderViewItem* item); + + // simply remove the view (and any children) Don't bother telling + // the listeners. + void removeView(LLFolderViewItem* item); + + // extractItem() removes the specified item from the folder, but + // doesn't delete it. + void extractItem( LLFolderViewItem* item ); + + // This function is called by a child that needs to be resorted. + void resort(LLFolderViewItem* item); + + void setItemSortOrder(U32 ordering); + void sortBy(U32); + //BOOL (*func)(LLFolderViewItem* a, LLFolderViewItem* b)); + + void setAutoOpenCountdown(F32 countdown) { mAutoOpenCountdown = countdown; } + + // folders can be opened. This will usually be called by internal + // methods. + virtual void toggleOpen(); + + // Force a folder open or closed + virtual void setOpen(BOOL openitem = TRUE); + + // Called when a child is refreshed. + // don't rearrange child folder contents unless explicitly requested + virtual void requestArrange(BOOL include_descendants = FALSE); + + // internal method which doesn't update the entire view. This + // method was written because the list iterators destroy the state + // of other iterations, thus, we can't arrange while iterating + // through the children (such as when setting which is selected. + virtual void setOpenArrangeRecursively(BOOL openitem, ERecurseType recurse = RECURSE_NO); + + // Get the current state of the folder. + virtual BOOL isOpen() { return mIsOpen; } + + // special case if an object is dropped on the child. + BOOL handleDragAndDropFromChild(MASK mask, + BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + + void applyFunctorRecursively(LLFolderViewFunctor& functor); + virtual void applyListenerFunctorRecursively(LLFolderViewListenerFunctor& functor); + + virtual void openItem( void ); + virtual BOOL addItem(LLFolderViewItem* item); + virtual BOOL addFolder( LLFolderViewFolder* folder); + + // LLView functionality + virtual BOOL handleHover(S32 x, S32 y, MASK mask); + virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + EDragAndDropType cargo_type, + void* cargo_data, + EAcceptance* accept, + std::string& tooltip_msg); + virtual void draw(); + + time_t getCreationDate() const; + bool isTrash() const; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFolderViewListenerFunctor +// +// This simple abstract base class can be used to applied to all +// listeners in a hierarchy. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLFolderViewListenerFunctor +{ +public: + virtual ~LLFolderViewListenerFunctor() {} + virtual void operator()(LLFolderViewEventListener* listener) = 0; +}; + +#endif // LLFOLDERVIEWITEM_H diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp new file mode 100644 index 0000000000..bef5f094e3 --- /dev/null +++ b/indra/newview/llfriendcard.cpp @@ -0,0 +1,425 @@ +/** + * @file llfriendcard.cpp + * @brief Implementation of classes to process Friends Cards + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llinventory.h" +#include "lltrans.h" + +#include "llfriendcard.h" + +#include "llcallingcard.h" // for LLAvatarTracker +#include "llviewerinventory.h" +#include "llinventorymodel.h" + +// Constants; + +static const std::string INVENTORY_STRING_FRIENDS_SUBFOLDER = "Friends"; +static const std::string INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER = "All"; + +// helper functions + +/* +mantipov *NOTE: unable to use +LLTrans::getString("InvFolder Friends"); or +LLTrans::getString("InvFolder FriendsAll"); +in next two functions to set localized folders' names because of there is a hack in the +LLFolderViewItem::refreshFromListener() method for protected asset types. +So, localized names will be got from the strings with "InvFolder LABEL_NAME" in the strings.xml +*/ +inline const std::string& get_friend_folder_name() +{ + return INVENTORY_STRING_FRIENDS_SUBFOLDER; +} + +inline const std::string& get_friend_all_subfolder_name() +{ + return INVENTORY_STRING_FRIENDS_ALL_SUBFOLDER; +} + +void move_from_to_arrays(LLInventoryModel::cat_array_t& from, LLInventoryModel::cat_array_t& to) +{ + while (from.count() > 0) + { + to.put(from.get(0)); + from.remove(0); + } +} + +const LLUUID& get_folder_uuid(const LLUUID& parentFolderUUID, LLInventoryCollectFunctor& matchFunctor) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendentsIf(parentFolderUUID, cats, items, + LLInventoryModel::EXCLUDE_TRASH, matchFunctor); + + if (cats.count() == 1) + { + return cats.get(0)->getUUID(); + } + + return LLUUID::null; +} + +// LLFriendCardsManager Constructor / Destructor +LLFriendCardsManager::LLFriendCardsManager() +{ + LLAvatarTracker::instance().addObserver(this); +} + +LLFriendCardsManager::~LLFriendCardsManager() +{ + LLAvatarTracker::instance().removeObserver(this); +} + +void LLFriendCardsManager::putAvatarData(const LLUUID& avatarID) +{ + llinfos << "Store avatar data, avatarID: " << avatarID << llendl; + std::pair< avatar_uuid_set_t::iterator, bool > pr; + pr = mBuddyIDSet.insert(avatarID); + if (pr.second == false) + { + llwarns << "Trying to add avatar UUID for the stored avatar: " + << avatarID + << llendl; + } +} + +const LLUUID LLFriendCardsManager::extractAvatarID(const LLUUID& avatarID) +{ + LLUUID rv; + avatar_uuid_set_t::iterator it = mBuddyIDSet.find(avatarID); + if (mBuddyIDSet.end() == it) + { + llwarns << "Call method for non-existent avatar name in the map: " << avatarID << llendl; + } + else + { + rv = (*it); + mBuddyIDSet.erase(it); + } + return rv; +} + +// be sure LLInventoryModel::buildParentChildMap() has been called before it. +// and this method must be called before any actions with friend list +void LLFriendCardsManager::ensureFriendFoldersExist() +{ + LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + if (friendFolderUUID.isNull()) + { + friendFolderUUID = gInventory.createNewCategory(callingCardsFolderID, + LLAssetType::AT_CALLINGCARD, get_friend_folder_name()); + } + + LLUUID friendAllSubfolderUUID = findFriendAllSubfolderUUIDImpl(); + + if (friendAllSubfolderUUID.isNull()) + { + friendAllSubfolderUUID = gInventory.createNewCategory(friendFolderUUID, + LLAssetType::AT_CALLINGCARD, get_friend_all_subfolder_name()); + } +} + + +bool LLFriendCardsManager::isItemInAnyFriendsList(const LLViewerInventoryItem* item) +{ + if (item->getType() != LLAssetType::AT_CALLINGCARD) + return false; + + LLInventoryModel::item_array_t items; + findMatchedFriendCards(item->getCreatorUUID(), items); + + return items.count() > 0; +} + +bool LLFriendCardsManager::isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const +{ + if (NULL == cat) + return false; + return TRUE == gInventory.isObjectDescendentOf(cat->getUUID(), findFriendFolderUUIDImpl()); +} + +void LLFriendCardsManager::syncFriendsFolder() +{ + //lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" if they are absent + LLFriendCardsManager::instance().ensureFriendFoldersExist(); + + LLAvatarTracker::buddy_map_t all_buddies; + LLAvatarTracker::instance().copyBuddyList(all_buddies); + + // 1. Remove Friend Cards for non-friends + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + + gInventory.collectDescendents(findFriendAllSubfolderUUIDImpl(), cats, items, LLInventoryModel::EXCLUDE_TRASH); + + LLInventoryModel::item_array_t::const_iterator it; + for (it = items.begin(); it != items.end(); ++it) + { + lldebugs << "Check if buddy is in list: " << (*it)->getName() << " " << (*it)->getCreatorUUID() << llendl; + if (NULL == get_ptr_in_map(all_buddies, (*it)->getCreatorUUID())) + { + lldebugs << "NONEXISTS, so remove it" << llendl; + removeFriendCardFromInventory((*it)->getCreatorUUID()); + } + } + + // 2. Add missing Friend Cards for friends + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + llinfos << "try to build friends, count: " << all_buddies.size() << llendl; + for(; buddy_it != all_buddies.end(); ++buddy_it) + { + const LLUUID& buddy_id = (*buddy_it).first; + addFriendCardToInventory(buddy_id); + } +} + +void LLFriendCardsManager::collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const +{ + folderBuddiesMap.clear(); + + LLInventoryModel::cat_array_t* listFolders; + LLInventoryModel::item_array_t* items; + + // get folders in the Friend folder. Items should be NULL due to Cards should be in lists. + gInventory.getDirectDescendentsOf(findFriendFolderUUIDImpl(), listFolders, items); + + if (NULL == listFolders) + return; + + LLInventoryModel::cat_array_t::const_iterator itCats; // to iterate Friend Lists (categories) + LLInventoryModel::item_array_t::const_iterator itBuddy; // to iterate Buddies in each List + LLInventoryModel::cat_array_t* fakeCatsArg; + for (itCats = listFolders->begin(); itCats != listFolders->end(); ++itCats) + { + if (items) + items->clear(); + + // *HACK: Only Friends/All content will be shown for now + // *TODO: Remove this hack, implement sorting if it will be needded by spec. + if ((*itCats)->getUUID() != findFriendAllSubfolderUUIDImpl()) + continue; + + gInventory.getDirectDescendentsOf((*itCats)->getUUID(), fakeCatsArg, items); + + if (NULL == items) + continue; + + std::vector buddyUUIDs; + for (itBuddy = items->begin(); itBuddy != items->end(); ++itBuddy) + { + buddyUUIDs.push_back((*itBuddy)->getCreatorUUID()); + } + + folderBuddiesMap.insert(make_pair((*itCats)->getUUID(), buddyUUIDs)); + } +} + + +/************************************************************************/ +/* Private Methods */ +/************************************************************************/ +const LLUUID& LLFriendCardsManager::findFriendFolderUUIDImpl() const +{ + LLUUID callingCardsFolderID = gInventory.findCategoryUUIDForType(LLAssetType::AT_CALLINGCARD); + + std::string friendFolderName = get_friend_folder_name(); + + return findChildFolderUUID(callingCardsFolderID, friendFolderName); +} + +const LLUUID& LLFriendCardsManager::findFriendAllSubfolderUUIDImpl() const +{ + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + std::string friendAllSubfolderName = get_friend_all_subfolder_name(); + + return findChildFolderUUID(friendFolderUUID, friendAllSubfolderName); +} + +const LLUUID& LLFriendCardsManager::findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& folderLabel) const +{ + // mantipov *HACK: get localaized name in the same way like in the LLFolderViewItem::refreshFromListener() method. + // be sure these both methods are synchronized. + // see also get_friend_folder_name() and get_friend_all_subfolder_name() functions + std::string localizedName = LLTrans::getString("InvFolder " + folderLabel); + + LLNameCategoryCollector matchFolderFunctor(localizedName); + + return get_folder_uuid(parentFolderUUID, matchFolderFunctor); +} +const LLUUID& LLFriendCardsManager::findFriendCardInventoryUUIDImpl(const LLUUID& avatarID) +{ + LLUUID friendAllSubfolderUUID = findFriendAllSubfolderUUIDImpl(); + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLInventoryModel::item_array_t::const_iterator it; + + // it is not necessary to check friendAllSubfolderUUID against NULL. It will be processed by collectDescendents + gInventory.collectDescendents(friendAllSubfolderUUID, cats, items, LLInventoryModel::EXCLUDE_TRASH); + for (it = items.begin(); it != items.end(); ++it) + { + if ((*it)->getCreatorUUID() == avatarID) + return (*it)->getUUID(); + } + + return LLUUID::null; +} + +void LLFriendCardsManager::findMatchedFriendCards(const LLUUID& avatarID, LLInventoryModel::item_array_t& items) const +{ + LLInventoryModel::cat_array_t cats; + LLUUID friendFolderUUID = findFriendFolderUUIDImpl(); + + LLParticularBuddyCollector matchFunctor(avatarID); + + LLViewerInventoryCategory* friendFolder = gInventory.getCategory(friendFolderUUID); + + LLInventoryModel::cat_array_t subFolders; + subFolders.push_back(friendFolder); + + while (subFolders.count() > 0) + { + LLViewerInventoryCategory* cat = subFolders.get(0); + subFolders.remove(0); + + gInventory.collectDescendentsIf(cat->getUUID(), cats, items, + LLInventoryModel::EXCLUDE_TRASH, matchFunctor); + + move_from_to_arrays(cats, subFolders); + } +} + +class CreateFriendCardCallback : public LLInventoryCallback +{ +public: + void fire(const LLUUID& inv_item_id) + { + LLViewerInventoryItem* item = gInventory.getItem(inv_item_id); + + if (item) + LLFriendCardsManager::instance().extractAvatarID(item->getCreatorUUID()); + } +}; + +bool LLFriendCardsManager::addFriendCardToInventory(const LLUUID& avatarID) +{ + LLInventoryModel* invModel = &gInventory; + + bool shouldBeAdded = true; + std::string name; + gCacheName->getFullName(avatarID, name); + + lldebugs << "Processing buddy name: " << name + << ", id: " << avatarID + << llendl; + + if (shouldBeAdded && findFriendCardInventoryUUIDImpl(avatarID).notNull()) + { + shouldBeAdded = false; + lldebugs << "is found in Inventory: " << name << llendl; + } + + if (shouldBeAdded && isAvatarDataStored(avatarID)) + { + shouldBeAdded = false; + lldebugs << "is found in sentRequests: " << name << llendl; + } + + LLUUID friendListFolderID = findFriendAllSubfolderUUIDImpl(); + if (shouldBeAdded && !invModel->isCategoryComplete(friendListFolderID)) + { + shouldBeAdded = false; + } + if (shouldBeAdded) + { + putAvatarData(avatarID); + lldebugs << "Sent create_inventory_item for " << avatarID << ", " << name << llendl; + + // TODO: mantipov: Is CreateFriendCardCallback really needed? Probably not + LLPointer cb = new CreateFriendCardCallback(); + + create_inventory_callingcard(avatarID, friendListFolderID, cb); + } + + return shouldBeAdded; +} + +void LLFriendCardsManager::removeFriendCardFromInventory(const LLUUID& avatarID) +{ + LLInventoryModel::item_array_t items; + findMatchedFriendCards(avatarID, items); + + LLInventoryModel::item_array_t::const_iterator it; + for (it = items.begin(); it != items.end(); ++ it) + { + gInventory.removeItem((*it)->getUUID()); + } +} + +void LLFriendCardsManager::onFriendListUpdate(U32 changed_mask) +{ + LLAvatarTracker& at = LLAvatarTracker::instance(); + + switch(changed_mask) { + case LLFriendObserver::ADD: + { + const std::set& changed_items = at.getChangedIDs(); + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + LLFriendCardsManager::instance().addFriendCardToInventory(*id_it); + } + } + break; + case LLFriendObserver::REMOVE: + { + const std::set& changed_items = at.getChangedIDs(); + std::set::const_iterator id_it = changed_items.begin(); + std::set::const_iterator id_end = changed_items.end(); + for (;id_it != id_end; ++id_it) + { + LLFriendCardsManager::instance().removeFriendCardFromInventory(*id_it); + } + } + + default:; + } +} + +// EOF diff --git a/indra/newview/llfriendcard.h b/indra/newview/llfriendcard.h new file mode 100644 index 0000000000..18a6d0ab69 --- /dev/null +++ b/indra/newview/llfriendcard.h @@ -0,0 +1,143 @@ +/** + * @file llfriendcard.h + * @brief Definition of classes to process Friends Cards + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFRIENDCARD_H +#define LL_LLFRIENDCARD_H + + +#include "llcallingcard.h" +#include "llinventorymodel.h" // for LLInventoryModel::item_array_t + +class LLViewerInventoryItem; + +class LLFriendCardsManager + : public LLSingleton + , public LLFriendObserver +{ + LOG_CLASS(LLFriendCardsManager); + + friend class LLSingleton; + friend class CreateFriendCardCallback; + +public: + typedef std::map > folderid_buddies_map_t; + + // LLFriendObserver implementation + void changed(U32 mask) + { + onFriendListUpdate(mask); + } + + /** + * Ensures that all necessary folders are created in Inventory. + * + * For now it processes Calling Card, Calling Card/Friends & Calling Card/Friends/All folders + */ + void ensureFriendFoldersExist(); + + + /** + * Determines if specified Inventory Calling Card exists in any of lists + * in the Calling Card/Friends/ folder (Default, or Custom) + */ + bool isItemInAnyFriendsList(const LLViewerInventoryItem* item); + + /** + * Checks is the specified category is in the Calling Card/Friends folder + */ + bool isCategoryInFriendFolder(const LLViewerInventoryCategory* cat) const; + + /** + * Synchronizes content of the Calling Card/Friends/All Global Inventory folder with Agent's Friend List + */ + void syncFriendsFolder(); + + /*! + * \brief + * Collects folders' IDs with the buddies' IDs in the Inventory Calling Card/Friends folder. + * + * \param folderBuddiesMap + * map into collected data will be put. It will be cleared before adding new data. + * + * Each item in the out map is a pair where first is an LLViewerInventoryCategory UUID, + * second is a vector with UUID of Avatars from this folder. + * + */ + void collectFriendsLists(folderid_buddies_map_t& folderBuddiesMap) const; + +private: + LLFriendCardsManager(); + ~LLFriendCardsManager(); + + + /** + * Stores buddy id to avoid sent create_inventory_callingcard several time for the same Avatar + */ + void putAvatarData(const LLUUID& avatarID); + + /** + * Extracts buddy id of Created Friend Card + */ + const LLUUID extractAvatarID(const LLUUID& avatarID); + + bool isAvatarDataStored(const LLUUID& avatarID) const + { + return (mBuddyIDSet.end() != mBuddyIDSet.find(avatarID)); + } + + const LLUUID& findChildFolderUUID(const LLUUID& parentFolderUUID, const std::string& folderLabel) const; + const LLUUID& findFriendFolderUUIDImpl() const; + const LLUUID& findFriendAllSubfolderUUIDImpl() const; + const LLUUID& findFriendCardInventoryUUIDImpl(const LLUUID& avatarID); + void findMatchedFriendCards(const LLUUID& avatarID, LLInventoryModel::item_array_t& items) const; + + /** + * Adds avatar specified by its UUID into the Calling Card/Friends/All Global Inventory folder + */ + bool addFriendCardToInventory(const LLUUID& avatarID); + + /** + * Removes an avatar specified by its UUID from the Calling Card/Friends/All Global Inventory folder + * and from the all Custom Folders + */ + void removeFriendCardFromInventory(const LLUUID& avatarID); + + void onFriendListUpdate(U32 changed_mask); + + +private: + typedef std::set avatar_uuid_set_t; + + avatar_uuid_set_t mBuddyIDSet; +}; + +#endif // LL_LLFRIENDCARD_H diff --git a/indra/newview/llgesturemgr.cpp b/indra/newview/llgesturemgr.cpp index 2dbff92ba0..59274c8638 100644 --- a/indra/newview/llgesturemgr.cpp +++ b/indra/newview/llgesturemgr.cpp @@ -50,15 +50,13 @@ // newview #include "llagent.h" -#include "llchatbar.h" #include "lldelayedgestureerror.h" #include "llinventorymodel.h" #include "llnotify.h" #include "llviewermessage.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llviewerstats.h" - -LLGestureManager gGestureManager; +#include "llnearbychatbar.h" // Longest time, in seconds, to wait for all animations to stop playing const F32 MAX_WAIT_ANIM_SECS = 30.f; @@ -71,7 +69,9 @@ LLGestureManager::LLGestureManager() mPlaying(), mActive(), mLoadingCount(0) -{ } +{ + gInventory.addObserver(this); +} // We own the data for gestures, so clean them up. @@ -85,6 +85,7 @@ LLGestureManager::~LLGestureManager() delete gesture; gesture = NULL; } + gInventory.removeObserver(this); } @@ -442,7 +443,7 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, LLMultiGesture* new void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_asset_id) { - item_map_t::iterator it = gGestureManager.mActive.find(item_id); + item_map_t::iterator it = LLGestureManager::instance().mActive.find(item_id); if (it == mActive.end()) { llwarns << "replaceGesture for inactive gesture " << item_id << llendl; @@ -451,7 +452,7 @@ void LLGestureManager::replaceGesture(const LLUUID& item_id, const LLUUID& new_a // mActive owns this gesture pointer, so clean up memory. LLMultiGesture* gesture = (*it).second; - gGestureManager.replaceGesture(item_id, gesture, new_asset_id); + LLGestureManager::instance().replaceGesture(item_id, gesture, new_asset_id); } void LLGestureManager::playGesture(LLMultiGesture* gesture) @@ -868,9 +869,11 @@ void LLGestureManager::runStep(LLMultiGesture* gesture, LLGestureStep* step) std::string chat_text = chat_step->mChatText; // Don't animate the nodding, as this might not blend with // other playing animations. + const BOOL animate = FALSE; - gChatBar->sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); + LLNearbyChatBar::getInstance()->sendChatFromViewer(chat_text, CHAT_TYPE_NORMAL, animate); + gesture->mCurrentStep++; break; } @@ -919,7 +922,7 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, delete info; info = NULL; - gGestureManager.mLoadingCount--; + LLGestureManager::instance().mLoadingCount--; if (0 == status) { @@ -941,22 +944,34 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, { if (deactivate_similar) { - gGestureManager.deactivateSimilarGestures(gesture, item_id); + LLGestureManager::instance().deactivateSimilarGestures(gesture, item_id); // Display deactivation message if this was the last of the bunch. - if (gGestureManager.mLoadingCount == 0 - && gGestureManager.mDeactivateSimilarNames.length() > 0) + if (LLGestureManager::instance().mLoadingCount == 0 + && LLGestureManager::instance().mDeactivateSimilarNames.length() > 0) { // we're done with this set of deactivations LLSD args; - args["NAMES"] = gGestureManager.mDeactivateSimilarNames; + args["NAMES"] = LLGestureManager::instance().mDeactivateSimilarNames; LLNotifications::instance().add("DeactivatedGesturesTrigger", args); } } + LLViewerInventoryItem* item = gInventory.getItem(item_id); + if(item) + { + gesture->mName = item->getName(); + } + else + { + // Watch this item and set gesture name when item exists in inventory + LLGestureManager::instance().watchItem(item_id); + } + LLGestureManager::instance().mActive[item_id] = gesture; + // Everything has been successful. Add to the active list. - gGestureManager.mActive[item_id] = gesture; gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); + if (inform_server) { // Inform the database of this change @@ -975,13 +990,13 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, gAgent.sendReliableMessage(); } - gGestureManager.notifyObservers(); + LLGestureManager::instance().notifyObservers(); } else { llwarns << "Unable to load gesture" << llendl; - gGestureManager.mActive.erase(item_id); + LLGestureManager::instance().mActive.erase(item_id); delete gesture; gesture = NULL; @@ -1003,7 +1018,7 @@ void LLGestureManager::onLoadComplete(LLVFS *vfs, llwarns << "Problem loading gesture: " << status << llendl; - gGestureManager.mActive.erase(item_id); + LLGestureManager::instance().mActive.erase(item_id); } } @@ -1131,3 +1146,19 @@ void LLGestureManager::getItemIDs(std::vector* ids) ids->push_back(it->first); } } + +void LLGestureManager::done() +{ + for(item_map_t::iterator it = mActive.begin(); it != mActive.end(); ++it) + { + if(it->second && it->second->mName.empty()) + { + LLViewerInventoryItem* item = gInventory.getItem(it->first); + if(item) + { + it->second->mName = item->getName(); + } + } + } + notifyObservers(); +} diff --git a/indra/newview/llgesturemgr.h b/indra/newview/llgesturemgr.h index f564c17486..947773d66d 100644 --- a/indra/newview/llgesturemgr.h +++ b/indra/newview/llgesturemgr.h @@ -38,6 +38,8 @@ #include #include "llassetstorage.h" // LLAssetType +#include "llinventorymodel.h" +#include "llsingleton.h" #include "llviewerinventory.h" class LLMultiGesture; @@ -52,7 +54,7 @@ public: virtual void changed() = 0; }; -class LLGestureManager +class LLGestureManager : public LLSingleton, public LLInventoryCompletionObserver { public: LLGestureManager(); @@ -133,6 +135,9 @@ protected: // Do a single step in a gesture void runStep(LLMultiGesture* gesture, LLGestureStep* step); + // LLInventoryCompletionObserver trigger + void done(); + // Used by loadGesture static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, @@ -158,6 +163,4 @@ public: std::vector mObservers; }; -extern LLGestureManager gGestureManager; - #endif diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 91beb801ad..3b3ada46a8 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -49,7 +49,7 @@ #include "lltextureentry.h" #include "llviewercamera.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llagent.h" #include "lltoolmgr.h" #include "llselectmgr.h" @@ -58,7 +58,6 @@ #include "llviewerobjectlist.h" #include "lltoolselectrect.h" #include "llviewerwindow.h" -#include "llcompass.h" #include "llsurface.h" #include "llwind.h" #include "llworld.h" @@ -338,127 +337,8 @@ void LLToolSelectRect::handleRectangleSelection(S32 x, S32 y, MASK mask) gViewerWindow->setup3DRender(); } - -const F32 COMPASS_SIZE = 64; -static const F32 COMPASS_RANGE = 0.33f; - -void LLCompass::draw() -{ - glMatrixMode(GL_MODELVIEW); - gGL.pushMatrix(); - - S32 width = 32; - S32 height = 32; - - LLGLSUIDefault gls_ui; - - gGL.translatef( COMPASS_SIZE/2.f, COMPASS_SIZE/2.f, 0.f); - - if (mBkgndTexture) - { - gGL.getTexUnit(0)->bind(mBkgndTexture.get()); - - gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f); - - gGL.begin(LLRender::QUADS); - - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(width, height); - - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(-width, height); - - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(-width, -height); - - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(width, -height); - - gGL.end(); - } - - // rotate subsequent draws to agent rotation - F32 rotation = atan2( gAgent.getFrameAgent().getAtAxis().mV[VX], gAgent.getFrameAgent().getAtAxis().mV[VY] ); - glRotatef( - rotation * RAD_TO_DEG, 0.f, 0.f, -1.f); - - if (mTexture) - { - gGL.getTexUnit(0)->bind(mTexture.get()); - gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f); - - gGL.begin(LLRender::QUADS); - - gGL.texCoord2f(1.f, 1.f); - gGL.vertex2i(width, height); - - gGL.texCoord2f(0.f, 1.f); - gGL.vertex2i(-width, height); - - gGL.texCoord2f(0.f, 0.f); - gGL.vertex2i(-width, -height); - - gGL.texCoord2f(1.f, 0.f); - gGL.vertex2i(width, -height); - - gGL.end(); - } - - gGL.popMatrix(); - -} - - - -void LLHorizontalCompass::draw() -{ - LLGLSUIDefault gls_ui; - - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); - S32 half_width = width / 2; - - if( mTexture ) - { - const LLVector3& at_axis = LLViewerCamera::getInstance()->getAtAxis(); - F32 center = atan2( at_axis.mV[VX], at_axis.mV[VY] ); - - center += F_PI; - center = llclamp( center, 0.0f, F_TWO_PI ); // probably not necessary... - center /= F_TWO_PI; - F32 left = center - COMPASS_RANGE; - F32 right = center + COMPASS_RANGE; - - gGL.getTexUnit(0)->bind(mTexture.get()); - gGL.color4f(1.0f, 1.0f, 1.0f, 1.0f ); - gGL.begin( LLRender::QUADS ); - - gGL.texCoord2f(right, 1.f); - gGL.vertex2i(width, height); - - gGL.texCoord2f(left, 1.f); - gGL.vertex2i(0, height); - - gGL.texCoord2f(left, 0.f); - gGL.vertex2i(0, 0); - - gGL.texCoord2f(right, 0.f); - gGL.vertex2i(width, 0); - - gGL.end(); - } - - // Draw the focus line - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( mFocusColor.mV ); - gl_line_2d( half_width, 0, half_width, height ); - } -} - - const F32 WIND_ALTITUDE = 180.f; - void LLWind::renderVectors() { // Renders the wind as vectors (used for debug) @@ -1008,8 +888,6 @@ void LLViewerObjectList::renderObjectBeacons() return; } - //const LLFontGL *font = LLResMgr::getInstance()->getRes(LLFONT_SANSSERIF); - LLGLSUIDefault gls_ui; { diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp new file mode 100644 index 0000000000..10a17476d9 --- /dev/null +++ b/indra/newview/llgroupactions.cpp @@ -0,0 +1,283 @@ +/** + * @file llgroupactions.cpp + * @brief Group-related actions (join, leave, new, delete, etc) + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llgroupactions.h" + +#include "llagent.h" +#include "llfloaterreg.h" +#include "llgroupmgr.h" +#include "llimview.h" // for gIMMgr +#include "llsidetray.h" + +#include "llcommandhandler.h" + +// +// Globals +// + +class LLGroupHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLGroupHandler() : LLCommandHandler("group", true) { } + bool handle(const LLSD& tokens, const LLSD& query_map, + LLMediaCtrl* web) + { + if (tokens.size() < 1) + { + return false; + } + + if (tokens[0].asString() == "create") + { + LLGroupActions::createGroup(); + return true; + } + + if (tokens.size() < 2) + { + return false; + } + + if (tokens[0].asString() == "list") + { + if (tokens[1].asString() == "show") + { + LLFloaterReg::showInstance("contacts", "groups"); + return true; + } + return false; + } + + LLUUID group_id; + if (!group_id.set(tokens[0], FALSE)) + { + return false; + } + + if (tokens[1].asString() == "about") + { + if (group_id.isNull()) + return true; + + LLGroupActions::show(group_id); + + return true; + } + return false; + } +}; +LLGroupHandler gGroupHandler; + +// static +void LLGroupActions::search() +{ + LLFloaterReg::showInstance("search", LLSD().insert("panel", "group")); +} + +// static +void LLGroupActions::leave(const LLUUID& group_id) +{ + if (group_id.isNull()) + return; + + S32 count = gAgent.mGroups.count(); + S32 i; + for (i = 0; i < count; ++i) + { + if(gAgent.mGroups.get(i).mID == group_id) + break; + } + if (i < count) + { + LLSD args; + args["GROUP"] = gAgent.mGroups.get(i).mName; + LLSD payload; + payload["group_id"] = group_id; + LLNotifications::instance().add("GroupLeaveConfirmMember", args, payload, onLeaveGroup); + } +} + +// static +void LLGroupActions::activate(const LLUUID& group_id) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ActivateGroup); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addUUIDFast(_PREHASH_GroupID, group_id); + gAgent.sendReliableMessage(); +} + +bool isGroupUIVisible() +{ + LLPanel* panel = LLSideTray::getInstance()->findChild("panel_group_info_sidetray"); + if(!panel) + return false; + return panel->getVisible(); +} + +// static +void LLGroupActions::show(const LLUUID& group_id) +{ + if (group_id.isNull()) + return; + + LLSD params; + params["group_id"] = group_id; + params["open_tab_name"] = "panel_group_info_sidetray"; + + LLSideTray::getInstance()->showPanel("panel_group_info_sidetray", params); +} + +void LLGroupActions::refresh_notices() +{ + if(!isGroupUIVisible()) + return; + + LLSD params; + params["group_id"] = LLUUID::null; + params["open_tab_name"] = "panel_group_info_sidetray"; + params["action"] = "refresh_notices"; + + LLSideTray::getInstance()->showPanel("panel_group_info_sidetray", params); +} + +//static +void LLGroupActions::refresh(const LLUUID& group_id) +{ + if(!isGroupUIVisible()) + return; + + LLSD params; + params["group_id"] = group_id; + params["open_tab_name"] = "panel_group_info_sidetray"; + params["action"] = "refresh"; + + LLSideTray::getInstance()->showPanel("panel_group_info_sidetray", params); +} + +//static +void LLGroupActions::createGroup() +{ + LLSD params; + params["group_id"] = LLUUID::null; + params["open_tab_name"] = "panel_group_info_sidetray"; + params["action"] = "create"; + + LLSideTray::getInstance()->showPanel("panel_group_info_sidetray", params); + +} +//static +void LLGroupActions::closeGroup(const LLUUID& group_id) +{ + if(!isGroupUIVisible()) + return; + + LLSD params; + params["group_id"] = group_id; + params["open_tab_name"] = "panel_group_info_sidetray"; + params["action"] = "close"; + + LLSideTray::getInstance()->showPanel("panel_group_info_sidetray", params); +} + + +// static +void LLGroupActions::startChat(const LLUUID& group_id) +{ + if (group_id.isNull()) + return; + + LLGroupData group_data; + if (gAgent.getGroupData(group_id, group_data)) + { + gIMMgr->addSession( + group_data.mName, + IM_SESSION_GROUP_START, + group_id); + make_ui_sound("UISndStartIM"); + } + else + { + // this should never happen, as starting a group IM session + // relies on you belonging to the group and hence having the group data + make_ui_sound("UISndInvalidOp"); + } +} + +// static +bool LLGroupActions::isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id) +{ + if(group_id.isNull() || avatar_id.isNull()) + { + return false; + } + + LLGroupMgrGroupData* group_data = LLGroupMgr::getInstance()->getGroupData(group_id); + if(!group_data) + { + return false; + } + + if(group_data->mMembers.end() == group_data->mMembers.find(avatar_id)) + { + return false; + } + + return true; +} + +//-- Private methods ---------------------------------------------------------- + +// static +bool LLGroupActions::onLeaveGroup(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + LLUUID group_id = notification["payload"]["group_id"].asUUID(); + if(option == 0) + { + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LeaveGroupRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_GroupData); + msg->addUUIDFast(_PREHASH_GroupID, group_id); + gAgent.sendReliableMessage(); + } + return false; +} diff --git a/indra/newview/llgroupactions.h b/indra/newview/llgroupactions.h new file mode 100644 index 0000000000..9fe1da8af2 --- /dev/null +++ b/indra/newview/llgroupactions.h @@ -0,0 +1,103 @@ +/** + * @file llgroupactions.h + * @brief Group-related actions (join, leave, new, delete, etc) + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGROUPACTIONS_H +#define LL_LLGROUPACTIONS_H + +#include "llsd.h" +#include "lluuid.h" + +/** + * Group-related actions (join, leave, new, delete, etc) + */ +class LLGroupActions +{ +public: + /** + * Invokes group search floater. + */ + static void search(); + + /** + * Invokes "Leave Group" floater. + */ + static void leave(const LLUUID& group_id); + + /** + * Activate group. + */ + static void activate(const LLUUID& group_id); + + /** + * Show group information panel. + */ + static void show(const LLUUID& group_id); + + /** + * Refresh group information panel. + */ + static void refresh(const LLUUID& group_id); + + /** + * Refresh group notices panel. + */ + static void refresh_notices(); + + /** + * Refresh group information panel. + */ + static void createGroup(); + + /** + * Close group information panel. + */ + static void closeGroup (const LLUUID& group_id); + + /** + * Start group instant messaging session. + */ + static void startChat(const LLUUID& group_id); + + /** + * Returns true if avatar is in group. + * + * Note that data about group members is loaded from server. + * If data has not been loaded yet, function will return inaccurate result. + * See LLGroupMgr::sendGroupMembersRequest + */ + static bool isAvatarMemberOfGroup(const LLUUID& group_id, const LLUUID& avatar_id); + +private: + static bool onLeaveGroup(const LLSD& notification, const LLSD& response); +}; + +#endif // LL_LLGROUPACTIONS_H diff --git a/indra/newview/llgrouplist.cpp b/indra/newview/llgrouplist.cpp new file mode 100644 index 0000000000..278fd5b9f6 --- /dev/null +++ b/indra/newview/llgrouplist.cpp @@ -0,0 +1,90 @@ +/** + * @file llgrouplist.cpp + * @brief List of the groups the agent belongs to. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llgrouplist.h" + +// libs +#include "lltrans.h" + +// newview +#include "llagent.h" + +static LLDefaultChildRegistry::Register r("group_list"); + +LLGroupList::Params::Params() +{ + // Prevent the active group from being always first in the list. + online_go_first = false; +} + +LLGroupList::LLGroupList(const Params& p) +: LLAvatarList(p) +{ +} + +static bool findInsensitive(std::string haystack, const std::string& needle_upper) +{ + LLStringUtil::toUpper(haystack); + return haystack.find(needle_upper) != std::string::npos; +} + +BOOL LLGroupList::update(const std::string& name_filter) +{ + LLCtrlListInterface *group_list = getListInterface(); + const LLUUID& highlight_id = gAgent.getGroupID(); + S32 count = gAgent.mGroups.count(); + LLUUID id; + + group_list->operateOnAll(LLCtrlListInterface::OP_DELETE); + + for(S32 i = 0; i < count; ++i) + { + // *TODO: check powers mask? + id = gAgent.mGroups.get(i).mID; + const LLGroupData& group_data = gAgent.mGroups.get(i); + if (name_filter != LLStringUtil::null && !findInsensitive(group_data.mName, name_filter)) + continue; + addItem(id, group_data.mName, highlight_id == id, ADD_BOTTOM); + } + + // add "none" to list at top + { + std::string loc_none = LLTrans::getString("GroupsNone"); + if (name_filter == LLStringUtil::null || findInsensitive(loc_none, name_filter)) + addItem(LLUUID::null, loc_none, highlight_id.isNull(), ADD_TOP); + } + + group_list->selectByValue(highlight_id); + return TRUE; +} diff --git a/indra/newview/llgrouplist.h b/indra/newview/llgrouplist.h new file mode 100644 index 0000000000..e893313f4b --- /dev/null +++ b/indra/newview/llgrouplist.h @@ -0,0 +1,54 @@ +/** + * @file llgrouplist.h + * @brief List of the groups the agent belongs to. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGROUPLIST_H +#define LL_LLGROUPLIST_H + +#include + +#include "llavatarlist.h" + +// *TODO: derive from ListView when it's ready. +class LLGroupList: public LLAvatarList +{ + LOG_CLASS(LLGroupList); +public: + struct Params : public LLInitParam::Block + { + Params(); + }; + + LLGroupList(const Params&); + BOOL update(const std::string& name_filter = LLStringUtil::null); +}; + +#endif // LL_LLGROUPLIST_H diff --git a/indra/newview/llgroupmgr.cpp b/indra/newview/llgroupmgr.cpp index 003a02c3cd..5e50fad008 100644 --- a/indra/newview/llgroupmgr.cpp +++ b/indra/newview/llgroupmgr.cpp @@ -51,7 +51,8 @@ #include "lleconomy.h" #include "llviewerwindow.h" #include "llfloaterdirectory.h" -#include "llfloatergroupinfo.h" +#include "llpanelgroup.h" +#include "llgroupactions.h" #include "lluictrlfactory.h" #include @@ -808,7 +809,7 @@ static void formatDateString(std::string &date_string) std::string day = result[2]; // ISO 8601 date format - date_string = llformat("%04s-%02s-%02s", year.c_str(), month.c_str(), day.c_str()); + date_string = llformat("%02s/%02s/%04s", month.c_str(), day.c_str(), year.c_str()); } } @@ -1210,7 +1211,7 @@ void LLGroupMgr::processEjectGroupMemberReply(LLMessageSystem* msg, void ** data // If we had a failure, the group panel needs to be updated. if (!success) { - LLFloaterGroupInfo::refreshGroup(group_id); + LLGroupActions::refresh(group_id); } } @@ -1230,7 +1231,7 @@ void LLGroupMgr::processJoinGroupReply(LLMessageSystem* msg, void ** data) LLGroupMgr::getInstance()->clearGroupData(group_id); // refresh the floater for this group, if any. - LLFloaterGroupInfo::refreshGroup(group_id); + LLGroupActions::refresh(group_id); // refresh the group panel of the search window, if necessary. LLFloaterDirectory::refreshGroup(group_id); } @@ -1252,7 +1253,7 @@ void LLGroupMgr::processLeaveGroupReply(LLMessageSystem* msg, void ** data) LLGroupMgr::getInstance()->clearGroupData(group_id); // close the floater for this group, if any. - LLFloaterGroupInfo::closeGroup(group_id); + LLGroupActions::closeGroup(group_id); // refresh the group panel of the search window, if necessary. LLFloaterDirectory::refreshGroup(group_id); } @@ -1288,12 +1289,14 @@ void LLGroupMgr::processCreateGroupReply(LLMessageSystem* msg, void ** data) gAgent.mGroups.push_back(gd); - LLFloaterGroupInfo::closeCreateGroup(); - LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab"); + LLPanelGroup::refreshCreatedGroup(group_id); + //FIXME + //LLFloaterGroupInfo::closeCreateGroup(); + //LLFloaterGroupInfo::showFromUUID(group_id,"roles_tab"); } else { - // *TODO:translate + // *TODO: Translate LLSD args; args["MESSAGE"] = message; LLNotifications::instance().add("UnableToCreateGroup", args); diff --git a/indra/newview/llhomelocationresponder.cpp b/indra/newview/llhomelocationresponder.cpp index 3ef58e7561..df478a0a04 100644 --- a/indra/newview/llhomelocationresponder.cpp +++ b/indra/newview/llhomelocationresponder.cpp @@ -103,7 +103,7 @@ void LLHomeLocationResponder::result( const LLSD& content ) } } -void LLHomeLocationResponder::error( const LLSD& content ) +void LLHomeLocationResponder::error( U32 status, const std::string& reason ) { - llinfos << "received error(" << ll_pretty_print_sd( content ) << ")" << llendl; + llinfos << "received error(" << reason << ")" << llendl; } diff --git a/indra/newview/llhomelocationresponder.h b/indra/newview/llhomelocationresponder.h index 1e222cd5b2..3a1d8ebfed 100644 --- a/indra/newview/llhomelocationresponder.h +++ b/indra/newview/llhomelocationresponder.h @@ -42,7 +42,7 @@ class LLHomeLocationResponder : public LLHTTPClient::Responder { virtual void result( const LLSD& content ); - virtual void error( const LLSD& content ); + virtual void error( U32 status, const std::string& reason ); }; #endif diff --git a/indra/newview/llhudeffect.cpp b/indra/newview/llhudeffect.cpp index c1d46f98d4..bfd62805a1 100644 --- a/indra/newview/llhudeffect.cpp +++ b/indra/newview/llhudeffect.cpp @@ -38,7 +38,6 @@ #include "llgl.h" #include "llagent.h" #include "llrendersphere.h" -#include "llimagegl.h" #include "llviewerobjectlist.h" #include "lldrawable.h" diff --git a/indra/newview/llhudeffect.h b/indra/newview/llhudeffect.h index 954cda7c8d..781e57fa6a 100644 --- a/indra/newview/llhudeffect.h +++ b/indra/newview/llhudeffect.h @@ -37,9 +37,6 @@ #include "lluuid.h" #include "v4coloru.h" -#include "llinterp.h" -#include "llframetimer.h" -#include "llmemory.h" const F32 LL_HUD_DUR_SHORT = 1.f; diff --git a/indra/newview/llhudeffectbeam.cpp b/indra/newview/llhudeffectbeam.cpp index 6cb3bef751..43a8dd1d81 100644 --- a/indra/newview/llhudeffectbeam.cpp +++ b/indra/newview/llhudeffectbeam.cpp @@ -43,7 +43,6 @@ #include "llgl.h" #include "llglheaders.h" #include "llhudrender.h" -#include "llimagegl.h" #include "llrendersphere.h" #include "llviewercamera.h" #include "llvoavatar.h" diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp index 3a5bec2be0..e366340a10 100644 --- a/indra/newview/llhudeffectlookat.cpp +++ b/indra/newview/llhudeffectlookat.cpp @@ -610,7 +610,9 @@ bool LLHUDEffectLookAt::calcTargetPosition() } LLVOAvatar* source_avatar = (LLVOAvatar*)(LLViewerObject*)mSourceObject; - + if (!source_avatar->isBuilt()) + return false; + if (target_obj && target_obj->mDrawable.notNull()) { LLQuaternion target_rot; diff --git a/indra/newview/llhudeffectpointat.h b/indra/newview/llhudeffectpointat.h index 81db3da1c7..278c69fe2b 100644 --- a/indra/newview/llhudeffectpointat.h +++ b/indra/newview/llhudeffectpointat.h @@ -33,6 +33,7 @@ #ifndef LL_LLHUDEFFECTPOINTAT_H #define LL_LLHUDEFFECTPOINTAT_H +#include "llframetimer.h" #include "llhudeffect.h" class LLViewerObject; diff --git a/indra/newview/llhudeffecttrail.cpp b/indra/newview/llhudeffecttrail.cpp index 0ade6810ba..786491211d 100644 --- a/indra/newview/llhudeffecttrail.cpp +++ b/indra/newview/llhudeffecttrail.cpp @@ -35,14 +35,13 @@ #include "llhudeffecttrail.h" #include "llviewercontrol.h" -#include "llimagegl.h" #include "message.h" #include "llagent.h" #include "llbox.h" #include "lldrawable.h" #include "llhudrender.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerpartsim.h" #include "llviewerpartsource.h" diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp index 3535fe185c..eda1d3fc55 100644 --- a/indra/newview/llhudicon.cpp +++ b/indra/newview/llhudicon.cpp @@ -40,7 +40,7 @@ #include "llviewerobject.h" #include "lldrawable.h" #include "llviewercamera.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llviewerwindow.h" //----------------------------------------------------------------------------- @@ -144,7 +144,7 @@ void LLHUDIcon::renderIcon(BOOL for_select) alpha_factor *= clamp_rescale(time_elapsed, MAX_VISIBLE_TIME - FADE_OUT_TIME, MAX_VISIBLE_TIME, 1.f, 0.f); } - F32 image_aspect = (F32)mImagep->mFullWidth / (F32)mImagep->mFullHeight; + F32 image_aspect = (F32)mImagep->getFullWidth() / (F32)mImagep->getFullHeight() ; LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeight() * mScale * scale_factor * x_pixel_vec; LLVector3 y_scale = (F32)gViewerWindow->getWindowHeight() * mScale * scale_factor * y_pixel_vec; @@ -164,7 +164,7 @@ void LLHUDIcon::renderIcon(BOOL for_select) LLColor4 icon_color = LLColor4::white; icon_color.mV[VALPHA] = alpha_factor; gGL.color4fv(icon_color.mV); - gGL.getTexUnit(0)->bind(mImagep.get()); + gGL.getTexUnit(0)->bind(mImagep); } gGL.begin(LLRender::QUADS); @@ -181,7 +181,7 @@ void LLHUDIcon::renderIcon(BOOL for_select) gGL.end(); } -void LLHUDIcon::setImage(LLViewerImage* imagep) +void LLHUDIcon::setImage(LLViewerTexture* imagep) { mImagep = imagep; mImagep->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -260,7 +260,7 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en return FALSE; } - F32 image_aspect = (F32)mImagep->mFullWidth / (F32)mImagep->mFullHeight; + F32 image_aspect = (F32)mImagep->getFullWidth() / (F32)mImagep->getFullHeight() ; LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeight() * mScale * scale_factor * x_pixel_vec; LLVector3 y_scale = (F32)gViewerWindow->getWindowHeight() * mScale * scale_factor * y_pixel_vec; diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h index 154e6df518..770e3bbcd0 100644 --- a/indra/newview/llhudicon.h +++ b/indra/newview/llhudicon.h @@ -33,7 +33,7 @@ #ifndef LL_LLHUDICON_H #define LL_LLHUDICON_H -#include "llmemory.h" +#include "llpointer.h" #include "lldarrayptr.h" #include "llhudobject.h" @@ -61,7 +61,7 @@ public: /*virtual*/ void markDead(); /*virtual*/ F32 getDistance() const { return mDistance; } - void setImage(LLViewerImage* imagep); + void setImage(LLViewerTexture* imagep); void setScale(F32 fraction_of_fov); void restartLifeTimer() { mLifeTimer.reset(); } @@ -88,7 +88,7 @@ protected: void renderIcon(BOOL for_select); // common render code private: - LLPointer mImagep; + LLPointer mImagep; LLFrameTimer mAnimTimer; LLFrameTimer mLifeTimer; F32 mDistance; diff --git a/indra/newview/llhudmanager.cpp b/indra/newview/llhudmanager.cpp index 955d786187..bdb8dadfb4 100644 --- a/indra/newview/llhudmanager.cpp +++ b/indra/newview/llhudmanager.cpp @@ -40,6 +40,7 @@ #include "llagent.h" #include "llhudeffect.h" #include "pipeline.h" +#include "llui.h" #include "llviewercontrol.h" #include "llviewerobjectlist.h" @@ -52,19 +53,20 @@ LLColor4 LLHUDManager::sChildColor; LLHUDManager::LLHUDManager() { - LLHUDManager::sParentColor = gColors.getColor("FocusColor"); + LLHUDManager::sParentColor = LLUIColorTable::instance().getColor("FocusColor"); // rdw commented out since it's not used. Also removed from colors_base.xml - //LLHUDManager::sChildColor = gColors.getColor("FocusSecondaryColor"); + //LLHUDManager::sChildColor =LLUIColorTable::instance().getColor("FocusSecondaryColor"); } LLHUDManager::~LLHUDManager() { } +static LLFastTimer::DeclareTimer FTM_HUD_EFFECTS("Hud Effects"); void LLHUDManager::updateEffects() { - LLFastTimer ftm(LLFastTimer::FTM_HUD_EFFECTS); + LLFastTimer ftm(FTM_HUD_EFFECTS); S32 i; for (i = 0; i < mHUDEffects.count(); i++) { diff --git a/indra/newview/llhudmanager.h b/indra/newview/llhudmanager.h index 615eb93a27..b2b4ffb559 100644 --- a/indra/newview/llhudmanager.h +++ b/indra/newview/llhudmanager.h @@ -36,7 +36,7 @@ // Responsible for managing all HUD elements. #include "llhudobject.h" -#include "lldarray.h" +#include "lldarrayptr.h" class LLViewerObject; class LLHUDEffect; diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp index bdff492948..dc55aba0db 100644 --- a/indra/newview/llhudobject.cpp +++ b/indra/newview/llhudobject.cpp @@ -254,10 +254,12 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type) return hud_objectp; } +static LLFastTimer::DeclareTimer FTM_HUD_UPDATE("Update Hud"); + // static void LLHUDObject::updateAll() { - LLFastTimer ftm(LLFastTimer::FTM_HUD_UPDATE); + LLFastTimer ftm(FTM_HUD_UPDATE); LLHUDText::updateAll(); LLHUDIcon::updateAll(); sortObjects(); diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h index 2cd8abf886..d304ac41af 100644 --- a/indra/newview/llhudobject.h +++ b/indra/newview/llhudobject.h @@ -37,7 +37,7 @@ * Base class and manager for in-world 2.5D non-interactive objects */ -#include "llmemory.h" +#include "llpointer.h" #include "v4color.h" #include "v3math.h" diff --git a/indra/newview/llhudrender.cpp b/indra/newview/llhudrender.cpp index 95b8442ec7..886fe3da07 100644 --- a/indra/newview/llhudrender.cpp +++ b/indra/newview/llhudrender.cpp @@ -40,24 +40,26 @@ #include "v3math.h" #include "llquaternion.h" #include "llfontgl.h" -#include "llimagegl.h" #include "llglheaders.h" #include "llviewerwindow.h" +#include "llui.h" void hud_render_utf8text(const std::string &str, const LLVector3 &pos_agent, const LLFontGL &font, const U8 style, + const LLFontGL::ShadowType shadow, const F32 x_offset, const F32 y_offset, const LLColor4& color, const BOOL orthographic) { LLWString wstr(utf8str_to_wstring(str)); - hud_render_text(wstr, pos_agent, font, style, x_offset, y_offset, color, orthographic); + hud_render_text(wstr, pos_agent, font, style, shadow, x_offset, y_offset, color, orthographic); } void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, const LLFontGL &font, const U8 style, + const LLFontGL::ShadowType shadow, const F32 x_offset, const F32 y_offset, const LLColor4& color, const BOOL orthographic) @@ -75,8 +77,8 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, LLVector3 up_axis; if (orthographic) { - right_axis.setVec(0.f, -1.f / gViewerWindow->getWindowHeight(), 0.f); - up_axis.setVec(0.f, 0.f, 1.f / gViewerWindow->getWindowHeight()); + right_axis.setVec(0.f, -1.f / gViewerWindow->getWorldViewWidth(), 0.f); + up_axis.setVec(0.f, 0.f, 1.f / gViewerWindow->getWorldViewHeight()); } else { @@ -104,26 +106,36 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, //get the render_pos in screen space F64 winX, winY, winZ; + LLRect world_view_rect = gViewerWindow->getWorldViewRect(); + S32 viewport[4]; + viewport[0] = world_view_rect.mLeft; + viewport[1] = world_view_rect.mBottom; + viewport[2] = world_view_rect.getWidth(); + viewport[3] = world_view_rect.getHeight(); gluProject(render_pos.mV[0], render_pos.mV[1], render_pos.mV[2], - gGLModelView, gGLProjection, (GLint*) gGLViewport, + gGLModelView, gGLProjection, (GLint*) viewport, &winX, &winY, &winZ); - //fonts all render orthographically, set up projection + //fonts all render orthographically, set up projection`` glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); LLUI::pushMatrix(); - gViewerWindow->setup2DRender(); + gl_state_for_2d(world_view_rect.getWidth(), world_view_rect.getHeight()); + gViewerWindow->setup3DViewport(); + //gViewerWindow->setup2DRender(); + winX -= world_view_rect.mLeft; + winY -= world_view_rect.mBottom; LLUI::loadIdentity(); LLUI::translate((F32) winX*1.0f/LLFontGL::sScaleX, (F32) winY*1.0f/(LLFontGL::sScaleY), -(((F32) winZ*2.f)-1.f)); //glRotatef(angle * RAD_TO_DEG, axis.mV[VX], axis.mV[VY], axis.mV[VZ]); //glScalef(right_scale, up_scale, 1.f); F32 right_x; - font.render(wstr, 0, 0, 0, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, wstr.length(), 1000, &right_x); + font.render(wstr, 0, 0, 0, color, LLFontGL::LEFT, LLFontGL::BASELINE, style, shadow, wstr.length(), 1000, &right_x); LLUI::popMatrix(); glMatrixMode(GL_PROJECTION); diff --git a/indra/newview/llhudrender.h b/indra/newview/llhudrender.h index 5ca865737f..93de89f7b0 100644 --- a/indra/newview/llhudrender.h +++ b/indra/newview/llhudrender.h @@ -43,6 +43,7 @@ void hud_render_text(const LLWString &wstr, const LLVector3 &pos_agent, const LLFontGL &font, const U8 style, + const LLFontGL::ShadowType, const F32 x_offset, const F32 y_offset, const LLColor4& color, @@ -53,6 +54,7 @@ void hud_render_utf8text(const std::string &str, const LLVector3 &pos_agent, const LLFontGL &font, const U8 style, + const LLFontGL::ShadowType, const F32 x_offset, const F32 y_offset, const LLColor4& color, diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp index 20140073f4..8086400493 100644 --- a/indra/newview/llhudtext.cpp +++ b/indra/newview/llhudtext.cpp @@ -39,16 +39,14 @@ #include "llagent.h" #include "llviewercontrol.h" -#include "llchatbar.h" #include "llcriticaldamp.h" #include "lldrawable.h" #include "llfontgl.h" #include "llglheaders.h" #include "llhudrender.h" -#include "llimagegl.h" #include "llui.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobject.h" #include "llvovolume.h" #include "llviewerwindow.h" @@ -113,7 +111,6 @@ LLHUDText::LLHUDText(const U8 type) : mRadius = 0.1f; LLPointer ptr(this); sTextObjects.insert(ptr); - //LLDebugVarMessageBox::show("max width", &HUD_TEXT_MAX_WIDTH, 500.f, 1.f); } LLHUDText::~LLHUDText() @@ -293,7 +290,7 @@ void LLHUDText::renderText(BOOL for_select) LLUIImagePtr imagep = LLUI::getUIImage("rounded_square.tga"); // *TODO: make this a per-text setting - LLColor4 bg_color = gSavedSettings.getColor4("BackgroundChatColor"); + LLColor4 bg_color = LLUIColorTable::instance().getColor("BackgroundChatColor"); bg_color.setAlpha(gSavedSettings.getF32("ChatBubbleOpacity") * alpha_factor); const S32 border_height = 16; @@ -319,8 +316,8 @@ void LLHUDText::renderText(BOOL for_select) if (mOnHUDAttachment) { - x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWindowWidth(); - y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWindowHeight(); + x_pixel_vec = LLVector3::y_axis / (F32)gViewerWindow->getWorldViewWidth(); + y_pixel_vec = LLVector3::z_axis / (F32)gViewerWindow->getWorldViewHeight(); } else { @@ -509,7 +506,7 @@ void LLHUDText::renderText(BOOL for_select) LLColor4 label_color(0.f, 0.f, 0.f, 1.f); label_color.mV[VALPHA] = alpha_factor; - hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, x_offset, y_offset, label_color, mOnHUDAttachment); + hud_render_text(segment_iter->getText(), render_position, *fontp, segment_iter->mStyle, LLFontGL::NO_SHADOW, x_offset, y_offset, label_color, mOnHUDAttachment); } } @@ -535,9 +532,10 @@ void LLHUDText::renderText(BOOL for_select) y_offset -= fontp->getLineHeight(); U8 style = segment_iter->mStyle; + LLFontGL::ShadowType shadow = LLFontGL::NO_SHADOW; if (mDropShadow) { - style |= LLFontGL::DROP_SHADOW; + shadow = LLFontGL::DROP_SHADOW; } F32 x_offset; @@ -553,7 +551,7 @@ void LLHUDText::renderText(BOOL for_select) text_color = segment_iter->mColor; text_color.mV[VALPHA] *= alpha_factor; - hud_render_text(segment_iter->getText(), render_position, *fontp, style, x_offset, y_offset, text_color, mOnHUDAttachment); + hud_render_text(segment_iter->getText(), render_position, *fontp, style, shadow, x_offset, y_offset, text_color, mOnHUDAttachment); } } /// Reset the default color to white. The renderer expects this to be the default. @@ -797,44 +795,22 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset) if (!LLViewerCamera::getInstance()->projectPosAgentToScreen(world_pos, screen_pos, FALSE) && mVisibleOffScreen) { // bubble off-screen, so find a spot for it along screen edge - LLVector2 window_center(gViewerWindow->getWindowDisplayWidth() * 0.5f, gViewerWindow->getWindowDisplayHeight() * 0.5f); - LLVector2 delta_from_center(screen_pos.mX - window_center.mV[VX], - screen_pos.mY - window_center.mV[VY]); - delta_from_center.normVec(); + LLViewerCamera::getInstance()->projectPosAgentToScreenEdge(world_pos, screen_pos); + } - F32 camera_aspect = LLViewerCamera::getInstance()->getAspect(); - F32 delta_aspect = llabs(delta_from_center.mV[VX] / delta_from_center.mV[VY]); - if (camera_aspect / llmax(delta_aspect, 0.001f) > 1.f) - { - // camera has wider aspect ratio than offset vector, so clamp to height - delta_from_center *= llabs(window_center.mV[VY] / delta_from_center.mV[VY]); - } - else - { - // camera has narrower aspect ratio than offset vector, so clamp to width - delta_from_center *= llabs(window_center.mV[VX] / delta_from_center.mV[VX]); - } + screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); - screen_pos_vec = window_center + delta_from_center; - } - else - { - screen_pos_vec.setVec((F32)screen_pos.mX, (F32)screen_pos.mY); - } - S32 bottom = STATUS_BAR_HEIGHT; - if (gChatBar->getVisible()) - { - bottom += CHAT_BAR_HEIGHT; - } + LLRect world_rect = gViewerWindow->getVirtualWorldViewRect(); + S32 bottom = world_rect.mBottom + STATUS_BAR_HEIGHT; LLVector2 screen_center; - screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], mWidth * 0.5f, (F32)gViewerWindow->getWindowDisplayWidth() - mWidth * 0.5f); + screen_center.mV[VX] = llclamp((F32)screen_pos_vec.mV[VX], (F32)world_rect.mLeft + mWidth * 0.5f, (F32)world_rect.mRight - mWidth * 0.5f); if(mVertAlignment == ALIGN_VERT_TOP) { screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], (F32)bottom, - (F32)gViewerWindow->getWindowDisplayHeight() - mHeight - (F32)MENU_BAR_HEIGHT); + (F32)world_rect.mTop - mHeight - (F32)MENU_BAR_HEIGHT); mSoftScreenRect.setLeftTopAndSize(screen_center.mV[VX] - (mWidth + BUFFER_SIZE) * 0.5f, screen_center.mV[VY] + (mHeight + BUFFER_SIZE), mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); } @@ -842,7 +818,7 @@ LLVector2 LLHUDText::updateScreenPos(LLVector2 &offset) { screen_center.mV[VY] = llclamp((F32)screen_pos_vec.mV[VY], (F32)bottom + mHeight * 0.5f, - (F32)gViewerWindow->getWindowDisplayHeight() - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT); + (F32)world_rect.mTop - mHeight * 0.5f - (F32)MENU_BAR_HEIGHT); mSoftScreenRect.setCenterAndSize(screen_center.mV[VX], screen_center.mV[VY], mWidth + BUFFER_SIZE, mHeight + BUFFER_SIZE); } @@ -981,7 +957,7 @@ void LLHUDText::updateAll() { continue; } - if (src_textp->mSoftScreenRect.rectInRect(&dst_textp->mSoftScreenRect)) + if (src_textp->mSoftScreenRect.overlaps(dst_textp->mSoftScreenRect)) { LLRectf intersect_rect = src_textp->mSoftScreenRect; intersect_rect.intersectWith(dst_textp->mSoftScreenRect); diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h index 645cbc2698..dc14a8c764 100644 --- a/indra/newview/llhudtext.h +++ b/indra/newview/llhudtext.h @@ -33,7 +33,7 @@ #ifndef LL_LLHUDTEXT_H #define LL_LLHUDTEXT_H -#include "llmemory.h" +#include "llpointer.h" #include "lldarrayptr.h" #include "llhudobject.h" diff --git a/indra/newview/llhudview.cpp b/indra/newview/llhudview.cpp index 198514ce0c..027cd2ab07 100644 --- a/indra/newview/llhudview.cpp +++ b/indra/newview/llhudview.cpp @@ -39,31 +39,36 @@ #include "llcoord.h" // viewer includes -#include "llagent.h" #include "llcallingcard.h" -#include "llcolorscheme.h" #include "llviewercontrol.h" #include "llfloaterworldmap.h" #include "llworldmapview.h" #include "lltracker.h" #include "llviewercamera.h" #include "llui.h" +#include "lluictrlfactory.h" LLHUDView *gHUDView = NULL; const S32 HUD_ARROW_SIZE = 32; -LLHUDView::LLHUDView() -: LLPanel() -{ } + + +LLHUDView::LLHUDView(const LLRect& r) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_hud.xml"); + setShape(r, true); +} LLHUDView::~LLHUDView() -{ } +{ +} // virtual void LLHUDView::draw() { LLTracker::drawHUDArrow(); + LLView::draw(); } @@ -89,4 +94,3 @@ BOOL LLHUDView::handleMouseDown(S32 x, S32 y, MASK mask) } return LLView::handleMouseDown(x, y, mask); } - diff --git a/indra/newview/llhudview.h b/indra/newview/llhudview.h index 7859e7f8be..05ff9c8596 100644 --- a/indra/newview/llhudview.h +++ b/indra/newview/llhudview.h @@ -42,7 +42,7 @@ class LLHUDView : public LLPanel { public: - LLHUDView(); + LLHUDView(const LLRect& rect); virtual ~LLHUDView(); virtual void draw(); diff --git a/indra/newview/llimhandler.cpp b/indra/newview/llimhandler.cpp new file mode 100644 index 0000000000..0262e40803 --- /dev/null +++ b/indra/newview/llimhandler.cpp @@ -0,0 +1,127 @@ +/** + * @file llimhandler.cpp + * @brief Notification Handler Class for IM notifications + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llnotificationhandler.h" + +#include "llbottomtray.h" +#include "llviewercontrol.h" +#include "lltoastimpanel.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLIMHandler::LLIMHandler() +{ + + // getting a Chiclet and creating params for a channel + LLBottomTray* tray = LLBottomTray::getInstance(); + mChiclet = tray->getSysWell(); + + LLChannelManager::Params p; + // *TODO: createNotificationChannel method + p.id = LLUUID(gSavedSettings.getString("NotificationChannelUUID")); + p.channel_right_bound = tray->getRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); + p.channel_width = gSavedSettings.getS32("NotifyBoxWidth"); + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); + +} + +//-------------------------------------------------------------------------- +LLIMHandler::~LLIMHandler() +{ +} + +//-------------------------------------------------------------------------- +void LLIMHandler::processNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if(!notification) + return; + + if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") + { + LLSD substitutions = notification->getSubstitutions(); + + LLToastIMPanel::Params im_p; + im_p.notification = notification; + im_p.avatar_id = substitutions["FROM_ID"].asUUID(); + im_p.from = substitutions["FROM"].asString(); + im_p.time = substitutions["TIME"].asString(); + im_p.message = substitutions["MESSAGE"].asString(); + im_p.session_id = substitutions["SESSION_ID"].asUUID(); + + LLToastIMPanel* im_box = new LLToastIMPanel(im_p); + + LLToast::Params p; + p.id = notification->getID(); + p.notification = notification; + p.panel = im_box; + p.can_be_stored = false; + p.on_toast_destroy = boost::bind(&LLIMHandler::onToastDestroy, this, _1); + mChannel->addToast(p); + + + static_cast(mChiclet)->updateUreadIMNotifications(); + } + else if (notify["sigtype"].asString() == "delete") + { + mChannel->killToastByNotificationID(notification->getID()); + } +} + +//-------------------------------------------------------------------------- +void LLIMHandler::onToastDestroy(LLToast* toast) +{ + toast->closeFloater(); + static_cast(mChiclet)->updateUreadIMNotifications(); +} + +//-------------------------------------------------------------------------- +void LLIMHandler::onChicletClick(void) +{ +} + +//-------------------------------------------------------------------------- +void LLIMHandler::onChicletClose(void) +{ +} + +//-------------------------------------------------------------------------- + + + diff --git a/indra/newview/llimpanel.cpp b/indra/newview/llimpanel.cpp index 0586409283..9cf3e57e22 100644 --- a/indra/newview/llimpanel.cpp +++ b/indra/newview/llimpanel.cpp @@ -35,6 +35,7 @@ #include "llimpanel.h" #include "indra_constants.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llfontgl.h" #include "llrect.h" @@ -45,22 +46,29 @@ #include "llagent.h" #include "llbutton.h" +#include "llbottomtray.h" #include "llcallingcard.h" #include "llchat.h" +#include "llchiclet.h" #include "llconsole.h" +#include "llgroupactions.h" #include "llfloater.h" -#include "llfloatergroupinfo.h" +#include "llfloatercall.h" +#include "llavataractions.h" #include "llimview.h" #include "llinventory.h" #include "llinventorymodel.h" -#include "llinventoryview.h" -#include "llfloateractivespeakers.h" -#include "llfloateravatarinfo.h" +#include "llfloaterinventory.h" #include "llfloaterchat.h" +#include "lliconctrl.h" +#include "llimview.h" // for LLIMModel to get other avatar id in chat #include "llkeyboard.h" #include "lllineeditor.h" #include "llnotify.h" +#include "llpanelimcontrolpanel.h" +#include "llrecentpeople.h" #include "llresmgr.h" +#include "lltrans.h" #include "lltabcontainer.h" #include "llviewertexteditor.h" #include "llviewermessage.h" @@ -69,7 +77,6 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "lllogchat.h" -#include "llfloaterhtml.h" #include "llweb.h" #include "llhttpclient.h" #include "llmutelist.h" @@ -98,190 +105,7 @@ LLVoiceChannel* LLVoiceChannel::sSuspendedVoiceChannel = NULL; BOOL LLVoiceChannel::sSuspended = FALSE; -void session_starter_helper( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - EInstantMessage im_type) -{ - LLMessageSystem *msg = gMessageSystem; - msg->newMessageFast(_PREHASH_ImprovedInstantMessage); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - - msg->nextBlockFast(_PREHASH_MessageBlock); - msg->addBOOLFast(_PREHASH_FromGroup, FALSE); - msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); - msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); - msg->addU8Fast(_PREHASH_Dialog, im_type); - msg->addUUIDFast(_PREHASH_ID, temp_session_id); - msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary - - std::string name; - gAgent.buildFullname(name); - - msg->addStringFast(_PREHASH_FromAgentName, name); - msg->addStringFast(_PREHASH_Message, LLStringUtil::null); - msg->addU32Fast(_PREHASH_ParentEstateID, 0); - msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); - msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); -} - -void start_deprecated_conference_chat( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) -{ - U8* bucket; - U8* pos; - S32 count; - S32 bucket_size; - - // *FIX: this could suffer from endian issues - count = agents_to_invite.size(); - bucket_size = UUID_BYTES * count; - bucket = new U8[bucket_size]; - pos = bucket; - - for(S32 i = 0; i < count; ++i) - { - LLUUID agent_id = agents_to_invite[i].asUUID(); - - memcpy(pos, &agent_id, UUID_BYTES); - pos += UUID_BYTES; - } - - session_starter_helper( - temp_session_id, - other_participant_id, - IM_SESSION_CONFERENCE_START); - - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - bucket, - bucket_size); - - gAgent.sendReliableMessage(); - - delete[] bucket; -} - -class LLStartConferenceChatResponder : public LLHTTPClient::Responder -{ -public: - LLStartConferenceChatResponder( - const LLUUID& temp_session_id, - const LLUUID& creator_id, - const LLUUID& other_participant_id, - const LLSD& agents_to_invite) - { - mTempSessionID = temp_session_id; - mCreatorID = creator_id; - mOtherParticipantID = other_participant_id; - mAgents = agents_to_invite; - } - - virtual void error(U32 statusNum, const std::string& reason) - { - //try an "old school" way. - if ( statusNum == 400 ) - { - start_deprecated_conference_chat( - mTempSessionID, - mCreatorID, - mOtherParticipantID, - mAgents); - } - - //else throw an error back to the client? - //in theory we should have just have these error strings - //etc. set up in this file as opposed to the IMMgr, - //but the error string were unneeded here previously - //and it is not worth the effort switching over all - //the possible different language translations - } - -private: - LLUUID mTempSessionID; - LLUUID mCreatorID; - LLUUID mOtherParticipantID; - - LLSD mAgents; -}; - -// Returns true if any messages were sent, false otherwise. -// Is sort of equivalent to "does the server need to do anything?" -bool send_start_session_messages( - const LLUUID& temp_session_id, - const LLUUID& other_participant_id, - const LLDynamicArray& ids, - EInstantMessage dialog) -{ - if ( dialog == IM_SESSION_GROUP_START ) - { - session_starter_helper( - temp_session_id, - other_participant_id, - dialog); - - switch(dialog) - { - case IM_SESSION_GROUP_START: - gMessageSystem->addBinaryDataFast( - _PREHASH_BinaryBucket, - EMPTY_BINARY_BUCKET, - EMPTY_BINARY_BUCKET_SIZE); - break; - default: - break; - } - gAgent.sendReliableMessage(); - - return true; - } - else if ( dialog == IM_SESSION_CONFERENCE_START ) - { - LLSD agents; - for (int i = 0; i < (S32) ids.size(); i++) - { - agents.append(ids.get(i)); - } - - //we have a new way of starting conference calls now - LLViewerRegion* region = gAgent.getRegion(); - if (region) - { - std::string url = region->getCapability( - "ChatSessionRequest"); - LLSD data; - data["method"] = "start conference"; - data["session-id"] = temp_session_id; - - data["params"] = agents; - - LLHTTPClient::post( - url, - data, - new LLStartConferenceChatResponder( - temp_session_id, - gAgent.getID(), - other_participant_id, - data["params"])); - } - else - { - start_deprecated_conference_chat( - temp_session_id, - gAgent.getID(), - other_participant_id, - agents); - } - } - - return false; -} class LLVoiceCallCapResponder : public LLHTTPClient::Responder { @@ -587,7 +411,6 @@ LLVoiceChannel* LLVoiceChannel::getChannelByURI(std::string uri) } } - void LLVoiceChannel::updateSessionID(const LLUUID& new_session_id) { sVoiceChannelMap.erase(sVoiceChannelMap.find(mSessionID)); @@ -622,6 +445,21 @@ void LLVoiceChannel::setState(EState state) mState = state; } +void LLVoiceChannel::toggleCallWindowIfNeeded(EState state) +{ + if (state == STATE_CONNECTED) + { + LLFloaterReg::showInstance("voice_call", mSessionID); + } + // By checking that current state is CONNECTED we make sure that the call window + // has been shown, hence there's something to hide. This helps when user presses + // the "End call" button right after initiating the call. + // *TODO: move this check to LLFloaterCall? + else if (state == STATE_HUNG_UP && mState == STATE_CONNECTED) + { + LLFloaterReg::hideInstance("voice_call", mSessionID); + } +} //static void LLVoiceChannel::initClass() @@ -693,6 +531,15 @@ void LLVoiceChannelGroup::activate() LLVoiceClient::getInstance()->setNonSpatialChannel( mURI, mCredentials); + +#if 0 // *TODO + if (!gAgent.isInGroup(mSessionID)) // ad-hoc channel + { + // Add the party to the list of people with which we've recently interacted. + for (/*people in the chat*/) + LLRecentPeople::instance().add(buddy_id); + } +#endif } } @@ -814,6 +661,9 @@ void LLVoiceChannelGroup::handleError(EStatusType status) void LLVoiceChannelGroup::setState(EState state) { + // HACK: Open/close the call window if needed. + toggleCallWindowIfNeeded(state); + switch(state) { case STATE_RINGING: @@ -999,6 +849,9 @@ void LLVoiceChannelP2P::activate() // using the session handle invalidates it. Clear it out here so we can't reuse it by accident. mSessionHandle.clear(); } + + // Add the party to the list of people with which we've recently interacted. + LLRecentPeople::instance().add(mOtherUserID); } } @@ -1056,6 +909,9 @@ void LLVoiceChannelP2P::setSessionHandle(const std::string& handle, const std::s void LLVoiceChannelP2P::setState(EState state) { + // HACK: Open/close the call window if needed. + toggleCallWindowIfNeeded(state); + // you only "answer" voice invites in p2p mode // so provide a special purpose message here if (mReceivedCall && state == STATE_RINGING) @@ -1071,20 +927,23 @@ void LLVoiceChannelP2P::setState(EState state) // // LLFloaterIMPanel // -LLFloaterIMPanel::LLFloaterIMPanel( - const std::string& session_label, - const LLUUID& session_id, - const LLUUID& other_participant_id, - EInstantMessage dialog) : - LLFloater(session_label, LLRect(), session_label), + +LLFloaterIMPanel::LLFloaterIMPanel(const std::string& session_label, + const LLUUID& session_id, + const LLUUID& other_participant_id, + const std::vector& ids, + EInstantMessage dialog) +: LLFloater(session_id), mInputEditor(NULL), mHistoryEditor(NULL), mSessionUUID(session_id), + mSessionLabel(session_label), mVoiceChannel(NULL), mSessionInitialized(FALSE), mSessionStartMsgPos(0), mOtherParticipantUUID(other_participant_id), mDialog(dialog), + mSessionInitialTargetIDs(ids), mTyping(FALSE), mOtherTyping(FALSE), mTypingLineStartIndex(0), @@ -1100,47 +959,6 @@ LLFloaterIMPanel::LLFloaterIMPanel( mFirstKeystrokeTimer(), mLastKeystrokeTimer() { - init(session_label); -} - -LLFloaterIMPanel::LLFloaterIMPanel( - const std::string& session_label, - const LLUUID& session_id, - const LLUUID& other_participant_id, - const LLDynamicArray& ids, - EInstantMessage dialog) : - LLFloater(session_label, LLRect(), session_label), - mInputEditor(NULL), - mHistoryEditor(NULL), - mSessionUUID(session_id), - mVoiceChannel(NULL), - mSessionInitialized(FALSE), - mSessionStartMsgPos(0), - mOtherParticipantUUID(other_participant_id), - mDialog(dialog), - mTyping(FALSE), - mOtherTyping(FALSE), - mTypingLineStartIndex(0), - mSentTypingState(TRUE), - mShowSpeakersOnConnect(TRUE), - mAutoConnect(FALSE), - mTextIMPossible(TRUE), - mProfileButtonEnabled(TRUE), - mCallBackEnabled(TRUE), - mSpeakers(NULL), - mSpeakerPanel(NULL), - mFirstKeystrokeTimer(), - mLastKeystrokeTimer() -{ - mSessionInitialTargetIDs = ids; - init(session_label); -} - - -void LLFloaterIMPanel::init(const std::string& session_label) -{ - mSessionLabel = session_label; - std::string xml_filename; switch(mDialog) { @@ -1188,11 +1006,10 @@ void LLFloaterIMPanel::init(const std::string& session_label) } mSpeakers = new LLIMSpeakerMgr(mVoiceChannel); + // All participants will be added to the list of people we've recently interacted with. + mSpeakers->addListener(&LLRecentPeople::instance(), "add"); - LLUICtrlFactory::getInstance()->buildFloater(this, - xml_filename, - &getFactoryMap(), - FALSE); + LLUICtrlFactory::getInstance()->buildFloater(this, xml_filename, NULL); setTitle(mSessionLabel); mInputEditor->setMaxTextLength(1023); @@ -1208,7 +1025,7 @@ void LLFloaterIMPanel::init(const std::string& session_label) if ( !mSessionInitialized ) { - if ( !send_start_session_messages( + if ( !LLIMModel::instance().sendStartSession( mSessionUUID, mOtherParticipantUUID, mSessionInitialTargetIDs, @@ -1230,7 +1047,7 @@ void LLFloaterIMPanel::init(const std::string& session_label) addHistoryLine( session_start, - gSavedSettings.getColor4("SystemChatColor"), + LLUIColorTable::instance().getColor("SystemChatColor"), false); } } @@ -1275,67 +1092,62 @@ LLFloaterIMPanel::~LLFloaterIMPanel() BOOL LLFloaterIMPanel::postBuild() { - requires("chat_editor"); - requires("im_history"); + mCloseSignal.connect(boost::bind(&LLFloaterIMPanel::onClose, this)); + + mVisibleSignal.connect(boost::bind(&LLFloaterIMPanel::onVisibilityChange, this, _2)); + + mInputEditor = getChild("chat_editor"); + mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); + mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); + mInputEditor->setCommitCallback( onCommitChat, this ); + mInputEditor->setCommitOnFocusLost( FALSE ); + mInputEditor->setRevertOnEsc( FALSE ); + mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); - if (checkRequirements()) + childSetAction("profile_callee_btn", onClickProfile, this); + childSetAction("group_info_btn", onClickGroupInfo, this); + + childSetAction("start_call_btn", onClickStartCall, this); + childSetAction("end_call_btn", onClickEndCall, this); + childSetAction("send_btn", onClickSend, this); + childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); + + childSetAction("moderator_kick_speaker", onKickSpeaker, this); + //LLButton* close_btn = getChild("close_btn"); + //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this); + + mHistoryEditor = getChild("im_history"); + mHistoryEditor->setParseHTML(TRUE); + mHistoryEditor->setParseHighlights(TRUE); + + if ( IM_SESSION_GROUP_START == mDialog ) { - mInputEditor = getChild("chat_editor"); - mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); - mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); - mInputEditor->setKeystrokeCallback( onInputEditorKeystroke ); - mInputEditor->setCommitCallback( onCommitChat ); - mInputEditor->setCallbackUserData(this); - mInputEditor->setCommitOnFocusLost( FALSE ); - mInputEditor->setRevertOnEsc( FALSE ); - mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); - - childSetAction("profile_callee_btn", onClickProfile, this); - childSetAction("group_info_btn", onClickGroupInfo, this); - - childSetAction("start_call_btn", onClickStartCall, this); - childSetAction("end_call_btn", onClickEndCall, this); - childSetAction("send_btn", onClickSend, this); - childSetAction("toggle_active_speakers_btn", onClickToggleActiveSpeakers, this); - - childSetAction("moderator_kick_speaker", onKickSpeaker, this); - //LLButton* close_btn = getChild("close_btn"); - //close_btn->setClickedCallback(&LLFloaterIMPanel::onClickClose, this); - - mHistoryEditor = getChild("im_history"); - mHistoryEditor->setParseHTML(TRUE); - mHistoryEditor->setParseHighlights(TRUE); - - if ( IM_SESSION_GROUP_START == mDialog ) - { - childSetEnabled("profile_btn", FALSE); - } - - if(!mProfileButtonEnabled) - { - childSetEnabled("profile_callee_btn", FALSE); - } - - sTitleString = getString("title_string"); - sTypingStartString = getString("typing_start_string"); - sSessionStartString = getString("session_start_string"); - - if (mSpeakerPanel) - { - mSpeakerPanel->refreshSpeakers(); - } - - if (mDialog == IM_NOTHING_SPECIAL) - { - childSetAction("mute_btn", onClickMuteVoice, this); - childSetCommitCallback("speaker_volume", onVolumeChange, this); - } - - setDefaultBtn("send_btn"); - return TRUE; + childSetEnabled("profile_btn", FALSE); + } + + if(!mProfileButtonEnabled) + { + childSetEnabled("profile_callee_btn", FALSE); } - return FALSE; + sTitleString = getString("title_string"); + sTypingStartString = getString("typing_start_string"); + sSessionStartString = getString("session_start_string"); + + if (mSpeakerPanel) + { + mSpeakerPanel->refreshSpeakers(); + } + + if (mDialog == IM_NOTHING_SPECIAL) + { + childSetAction("mute_btn", onClickMuteVoice, this); + childSetCommitCallback("speaker_volume", onVolumeChange, this); + } + + setDefaultBtn("send_btn"); + return TRUE; } void* LLFloaterIMPanel::createSpeakersPanel(void* data) @@ -1479,7 +1291,7 @@ private: LLUUID mSessionID; }; -BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) +BOOL LLFloaterIMPanel::inviteToSession(const std::vector& ids) { LLViewerRegion* region = gAgent.getRegion(); if (!region) @@ -1487,7 +1299,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) return FALSE; } - S32 count = ids.count(); + S32 count = ids.size(); if( isInviteAllowed() && (count > 0) ) { @@ -1500,7 +1312,7 @@ BOOL LLFloaterIMPanel::inviteToSession(const LLDynamicArray& ids) data["params"] = LLSD::emptyArray(); for (int i = 0; i < count; i++) { - data["params"].append(ids.get(i)); + data["params"].append(ids[i]); } data["method"] = "invite"; @@ -1551,34 +1363,41 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 prepend_newline = false; } + std::string separator_string(": "); + // 'name' is a sender name that we want to hotlink so that clicking on it opens a profile. if (!name.empty()) // If name exists, then add it to the front of the message. { // Don't hotlink any messages from the system (e.g. "Second Life:"), so just add those in plain text. if (name == SYSTEM_FROM) { - mHistoryEditor->appendColoredText(name,false,prepend_newline,color); + mHistoryEditor->appendColoredText(name + separator_string, false, prepend_newline, color); } else { // Convert the name to a hotlink and add to message. - const LLStyleSP &source_style = LLStyleMap::instance().lookupAgent(source); - mHistoryEditor->appendStyledText(name,false,prepend_newline,source_style); + mHistoryEditor->appendStyledText(name + separator_string, false, prepend_newline, LLStyleMap::instance().lookupAgent(source)); } prepend_newline = false; } mHistoryEditor->appendColoredText(utf8msg, false, prepend_newline, color); - - if (log_to_file - && gSavedPerAccountSettings.getBOOL("LogInstantMessages") ) + S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions"); + if (log_to_file && (im_log_option!=LOG_CHAT)) { std::string histstr; - if (gSavedPerAccountSettings.getBOOL("IMLogTimestamp")) - histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + name + utf8msg; + if (gSavedPerAccountSettings.getBOOL("LogTimestamp")) + histstr = LLLogChat::timestamp(gSavedPerAccountSettings.getBOOL("LogTimestampDate")) + name + separator_string + utf8msg; else - histstr = name + utf8msg; + histstr = name + separator_string + utf8msg; - LLLogChat::saveHistory(getTitle(),histstr); + if(im_log_option==LOG_BOTH_TOGETHER) + { + LLLogChat::saveHistory(std::string("chat"),histstr); + } + else + { + LLLogChat::saveHistory(getTitle(),histstr); + } } if (!isInVisibleChain()) @@ -1594,24 +1413,6 @@ void LLFloaterIMPanel::addHistoryLine(const std::string &utf8msg, const LLColor4 } -void LLFloaterIMPanel::setVisible(BOOL b) -{ - LLPanel::setVisible(b); - - LLMultiFloater* hostp = getHost(); - if( b && hostp ) - { - hostp->setFloaterFlashing(this, FALSE); - - /* Don't change containing floater title - leave it "Instant Message" JC - LLUIString title = sTitleString; - title.setArg("[NAME]", mSessionLabel); - hostp->setTitle( title ); - */ - } -} - - void LLFloaterIMPanel::setInputFocus( BOOL b ) { mInputEditor->setFocus( b ); @@ -1629,7 +1430,6 @@ void LLFloaterIMPanel::selectNone() mInputEditor->deselect(); } - BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) { BOOL handled = FALSE; @@ -1637,24 +1437,11 @@ BOOL LLFloaterIMPanel::handleKeyHere( KEY key, MASK mask ) { sendMsg(); handled = TRUE; - - // Close talk panels on hitting return - // but not shift-return or control-return - if ( !gSavedSettings.getBOOL("PinTalkViewOpen") && !(mask & MASK_CONTROL) && !(mask & MASK_SHIFT) ) - { - gIMMgr->toggle(NULL); - } } else if ( KEY_ESCAPE == key ) { handled = TRUE; gFocusMgr.setKeyboardFocus(NULL); - - // Close talk panel with escape - if( !gSavedSettings.getBOOL("PinTalkViewOpen") ) - { - gIMMgr->toggle(NULL); - } } // May need to call base class LLPanel::handleKeyHere if not handled @@ -1705,8 +1492,8 @@ BOOL LLFloaterIMPanel::dropCallingCard(LLInventoryItem* item, BOOL drop) { if(drop) { - LLDynamicArray ids; - ids.put(item->getCreatorUUID()); + std::vector ids; + ids.push_back(item->getCreatorUUID()); inviteToSession(ids); } } @@ -1738,10 +1525,11 @@ BOOL LLFloaterIMPanel::dropCategory(LLInventoryCategory* category, BOOL drop) } else if(drop) { - LLDynamicArray ids; + std::vector ids; + ids.reserve(count); for(S32 i = 0; i < count; ++i) { - ids.put(items.get(i)->getCreatorUUID()); + ids.push_back(items.get(i)->getCreatorUUID()); } inviteToSession(ids); } @@ -1771,9 +1559,9 @@ void LLFloaterIMPanel::onClickProfile( void* userdata ) // Bring up the Profile window LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - if (self->mOtherParticipantUUID.notNull()) + if (self->getOtherParticipantID().notNull()) { - LLFloaterAvatarInfo::showFromDirectory(self->getOtherParticipantID()); + LLAvatarActions::showProfile(self->getOtherParticipantID()); } } @@ -1783,7 +1571,8 @@ void LLFloaterIMPanel::onClickGroupInfo( void* userdata ) // Bring up the Profile window LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; - LLFloaterGroupInfo::showFromUUID(self->mSessionUUID); + LLGroupActions::show(self->mSessionUUID); + } // static @@ -1792,7 +1581,7 @@ void LLFloaterIMPanel::onClickClose( void* userdata ) LLFloaterIMPanel* self = (LLFloaterIMPanel*) userdata; if(self) { - self->close(); + self->closeFloater(); } } @@ -1864,108 +1653,29 @@ void LLFloaterIMPanel::onInputEditorKeystroke(LLLineEditor* caller, void* userda } } -void LLFloaterIMPanel::onClose(bool app_quitting) +void LLFloaterIMPanel::onClose() { setTyping(FALSE); - if(mSessionUUID.notNull()) - { - std::string name; - gAgent.buildFullname(name); - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - mOtherParticipantUUID, - name, - LLStringUtil::null, - IM_ONLINE, - IM_SESSION_LEAVE, - mSessionUUID); - gAgent.sendReliableMessage(); - } + LLIMModel::instance().sendLeaveSession(mSessionUUID, mOtherParticipantUUID); + gIMMgr->removeSession(mSessionUUID); - destroy(); + // *HACK hide the voice floater + LLFloaterReg::hideInstance("voice_call", mSessionUUID); } -void LLFloaterIMPanel::onVisibilityChange(BOOL new_visibility) +void LLFloaterIMPanel::onVisibilityChange(const LLSD& new_visibility) { - if (new_visibility) + if (new_visibility.asBoolean()) { mNumUnreadMessages = 0; } -} - -void deliver_message(const std::string& utf8_text, - const LLUUID& im_session_id, - const LLUUID& other_participant_id, - EInstantMessage dialog) -{ - std::string name; - bool sent = false; - gAgent.buildFullname(name); - - const LLRelationship* info = NULL; - info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); - U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; - - if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) - { - // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. - sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text); - } - - if(!sent) - { - // Send message normally. - - // default to IM_SESSION_SEND unless it's nothing special - in - // which case it's probably an IM to everyone. - U8 new_dialog = dialog; - - if ( dialog != IM_NOTHING_SPECIAL ) - { - new_dialog = IM_SESSION_SEND; - } - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - other_participant_id, - name.c_str(), - utf8_text.c_str(), - offline, - (EInstantMessage)new_dialog, - im_session_id); - gAgent.sendReliableMessage(); - } - - // If there is a mute list and this is not a group chat... - if ( LLMuteList::getInstance() ) - { - // ... the target should not be in our mute list for some message types. - // Auto-remove them if present. - switch( dialog ) - { - case IM_NOTHING_SPECIAL: - case IM_GROUP_INVITATION: - case IM_INVENTORY_OFFERED: - case IM_SESSION_INVITE: - case IM_SESSION_P2P_INVITE: - case IM_SESSION_CONFERENCE_START: - case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. - case IM_LURE_USER: - case IM_GODLIKE_LURE_USER: - case IM_FRIENDSHIP_OFFERED: - LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); - break; - default: ; // do nothing - } - } + if (new_visibility.asBoolean() && mVoiceChannel->getState() == LLVoiceChannel::STATE_CONNECTED) + LLFloaterReg::showInstance("voice_call", mSessionUUID); + else + LLFloaterReg::hideInstance("voice_call", mSessionUUID); } void LLFloaterIMPanel::sendMsg() @@ -1989,40 +1699,11 @@ void LLFloaterIMPanel::sendMsg() if ( mSessionInitialized ) { - deliver_message(utf8_text, + LLIMModel::sendMessage(utf8_text, mSessionUUID, mOtherParticipantUUID, mDialog); - // local echo - if((mDialog == IM_NOTHING_SPECIAL) && - (mOtherParticipantUUID.notNull())) - { - std::string history_echo; - gAgent.buildFullname(history_echo); - - // Look for IRC-style emotes here. - std::string prefix = utf8_text.substr(0, 4); - if (prefix == "/me " || prefix == "/me'") - { - utf8_text.replace(0,3,""); - } - else - { - history_echo += ": "; - } - history_echo += utf8_text; - - BOOL other_was_typing = mOtherTyping; - - addHistoryLine(history_echo, gSavedSettings.getColor("IMChatColor"), true, gAgent.getID()); - - if (other_was_typing) - { - addTypingIndicator(mOtherTypingName); - } - - } } else { @@ -2095,7 +1776,7 @@ void LLFloaterIMPanel::sessionInitReplyReceived(const LLUUID& session_id) iter != mQueuedMsgsForInit.endArray(); ++iter) { - deliver_message( + LLIMModel::sendMessage( iter->asString(), mSessionUUID, mOtherParticipantUUID, @@ -2146,23 +1827,10 @@ void LLFloaterIMPanel::sendTypingState(BOOL typing) // much network traffic. Only send in person-to-person IMs. if (mDialog != IM_NOTHING_SPECIAL) return; - std::string name; - gAgent.buildFullname(name); - - pack_instant_message( - gMessageSystem, - gAgent.getID(), - FALSE, - gAgent.getSessionID(), - mOtherParticipantUUID, - name, - std::string("typing"), - IM_ONLINE, - (typing ? IM_TYPING_START : IM_TYPING_STOP), - mSessionUUID); - gAgent.sendReliableMessage(); + LLIMModel::instance().sendTypingState(mSessionUUID, mOtherParticipantUUID, typing); } + void LLFloaterIMPanel::processIMTyping(const LLIMInfo* im_info, BOOL typing) { if (typing) @@ -2186,7 +1854,7 @@ void LLFloaterIMPanel::addTypingIndicator(const std::string &name) mTypingLineStartIndex = mHistoryEditor->getWText().length(); LLUIString typing_start = sTypingStartString; typing_start.setArg("[NAME]", name); - addHistoryLine(typing_start, gSavedSettings.getColor4("SystemChatColor"), false); + addHistoryLine(typing_start, LLUIColorTable::instance().getColor("SystemChatColor"), false); mOtherTypingName = name; mOtherTyping = TRUE; } @@ -2217,21 +1885,21 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string { LLFloaterIMPanel* self = (LLFloaterIMPanel*)userdata; std::string message = line; - + S32 im_log_option = gSavedPerAccountSettings.getS32("IMLogOptions"); switch (type) { case LLLogChat::LOG_EMPTY: // add warning log enabled message - if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) + if (im_log_option!=LOG_CHAT) { - message = LLFloaterChat::getInstance()->getString("IM_logging_string"); + message = LLTrans::getString("IM_logging_string"); } break; case LLLogChat::LOG_END: // add log end message - if (gSavedPerAccountSettings.getBOOL("LogInstantMessages")) + if (im_log_option!=LOG_CHAT) { - message = LLFloaterChat::getInstance()->getString("IM_logging_string"); + message = LLTrans::getString("IM_logging_string"); } break; case LLLogChat::LOG_LINE: @@ -2243,7 +1911,7 @@ void LLFloaterIMPanel::chatFromLogFile(LLLogChat::ELogLineType type, std::string } //self->addHistoryLine(line, LLColor4::grey, FALSE); - self->mHistoryEditor->appendColoredText(message, false, true, LLColor4::grey); + self->mHistoryEditor->appendColoredText(message, false, true, LLUIColorTable::instance().getColor("ChatHistoryTextColor")); } void LLFloaterIMPanel::showSessionStartError( @@ -2325,9 +1993,340 @@ bool LLFloaterIMPanel::onConfirmForceCloseError(const LLSD& notification, const LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession( session_id); - if ( floaterp ) floaterp->close(FALSE); + if ( floaterp ) floaterp->closeFloater(FALSE); } return false; } + + +LLIMFloater::LLIMFloater(const LLUUID& session_id) + : LLFloater(session_id), + mControlPanel(NULL), + mSessionID(session_id), + mLastMessageIndex(-1), + mLastFromName(), + mDialog(IM_NOTHING_SPECIAL), + mHistoryEditor(NULL), + mInputEditor(NULL), + mPositioned(false) +{ + LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); + if(session) + { + mDialog = session->mType; + } + + if (mDialog == IM_NOTHING_SPECIAL) + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelIMControl, this); + } + else + { + mFactoryMap["panel_im_control_panel"] = LLCallbackMap(createPanelGroupControl, this); + } +// LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im_session.xml"); +} + +/* static */ +void LLIMFloater::newIMCallback(const LLSD& data){ + + if (data["num_unread"].asInteger() > 0) + { + LLUUID session_id = data["session_id"].asUUID(); + + LLIMFloater* floater = LLFloaterReg::findTypedInstance("impanel", session_id); + if (floater == NULL) + { + llwarns << "new_im_callback for non-existent session_id " << session_id << llendl; + return; + } + + // update if visible, otherwise will be updated when opened + if (floater->getVisible()) + { + floater->updateMessages(); + } + } +} + +void LLIMFloater::onSendMsg( LLUICtrl* ctrl, void* userdata ) +{ + LLIMFloater* self = (LLIMFloater*) userdata; + self->sendMsg(); +} + +void LLIMFloater::sendMsg() +{ + if (!gAgent.isGodlike() + && (mDialog == IM_NOTHING_SPECIAL) + && mOtherParticipantUUID.isNull()) + { + llinfos << "Cannot send IM to everyone unless you're a god." << llendl; + return; + } + + if (mInputEditor) + { + LLWString text = mInputEditor->getConvertedText(); + if(!text.empty()) + { + // Truncate and convert to UTF8 for transport + std::string utf8_text = wstring_to_utf8str(text); + utf8_text = utf8str_truncate(utf8_text, MAX_MSG_BUF_SIZE - 1); + + LLIMModel::sendMessage(utf8_text, + mSessionID, + mOtherParticipantUUID, + mDialog); + + mInputEditor->setText(LLStringUtil::null); + + updateMessages(); + } + } +} + +LLIMFloater::~LLIMFloater() +{ +} + +//virtual +BOOL LLIMFloater::postBuild() +{ + LLIMModel::LLIMSession* session = get_if_there(LLIMModel::instance().sSessionsMap, mSessionID, (LLIMModel::LLIMSession*)NULL); + if(session) + { + mOtherParticipantUUID = session->mOtherParticipantID; + mControlPanel->setID(session->mOtherParticipantID); + } + + LLButton* slide_left = getChild("slide_left_btn"); + slide_left->setVisible(mControlPanel->getVisible()); + slide_left->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this)); + + LLButton* slide_right = getChild("slide_right_btn"); + slide_right->setVisible(!mControlPanel->getVisible()); + slide_right->setClickedCallback(boost::bind(&LLIMFloater::onSlide, this)); + + mInputEditor = getChild("chat_editor"); + mInputEditor->setMaxTextLength(1023); + // enable line history support for instant message bar + mInputEditor->setEnableLineHistory(TRUE); + + mInputEditor->setFocusReceivedCallback( onInputEditorFocusReceived, this ); + mInputEditor->setFocusLostCallback( onInputEditorFocusLost, this ); + mInputEditor->setKeystrokeCallback( onInputEditorKeystroke, this ); + mInputEditor->setCommitOnFocusLost( FALSE ); + mInputEditor->setRevertOnEsc( FALSE ); + mInputEditor->setReplaceNewlinesWithSpaces( FALSE ); + + childSetCommitCallback("chat_editor", onSendMsg, this); + + mHistoryEditor = getChild("im_text"); + + setTitle(LLIMModel::instance().getName(mSessionID)); + setDocked(true); + + mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); + + return TRUE; +} + + + +// static +void* LLIMFloater::createPanelIMControl(void* userdata) +{ + LLIMFloater *self = (LLIMFloater*)userdata; + self->mControlPanel = new LLPanelIMControlPanel(); + self->mControlPanel->setXMLFilename("panel_im_control_panel.xml"); + return self->mControlPanel; +} + + +// static +void* LLIMFloater::createPanelGroupControl(void* userdata) +{ + LLIMFloater *self = (LLIMFloater*)userdata; + self->mControlPanel = new LLPanelGroupControlPanel(); + self->mControlPanel->setXMLFilename("panel_group_control_panel.xml"); + return self->mControlPanel; +} + + +const U32 UNDOCK_LEAP_HEIGHT = 12; +const U32 DOCK_ICON_HEIGHT = 6; + +//virtual +void LLIMFloater::onFocusLost() +{ + // spec says close if docked to bottom tray and user has clicked away + // (hence we are no longer focused) + if (isDocked()) + { + LLIMFloater* floater = LLFloaterReg::getTypedInstance("impanel", mSessionID); + if (floater) + { + floater->setVisible(false); + } + } +} + + + +//virtual +void LLIMFloater::setDocked(bool docked, bool pop_on_undock) +{ + LLFloater::setDocked(docked); + + if (!docked && pop_on_undock) + { + // visually pop up a little bit to emphasize the undocking + translate(0, UNDOCK_LEAP_HEIGHT); + } +} + +void LLIMFloater::onSlide() +{ + LLPanel* im_control_panel = getChild("panel_im_control_panel"); + im_control_panel->setVisible(!im_control_panel->getVisible()); + + getChild("slide_left_btn")->setVisible(im_control_panel->getVisible()); + getChild("slide_right_btn")->setVisible(!im_control_panel->getVisible()); +} + +//static +LLIMFloater* LLIMFloater::show(const LLUUID& session_id) +{ + //hide all + LLFloaterReg::const_instance_list_t& inst_list = LLFloaterReg::getFloaterList("impanel"); + for (LLFloaterReg::const_instance_list_t::const_iterator iter = inst_list.begin(); + iter != inst_list.end(); ++iter) + { + LLIMFloater* floater = dynamic_cast(*iter); + if (floater && floater->isDocked()) + { + floater->setVisible(false); + } + } + + LLIMFloater* floater = LLFloaterReg::showTypedInstance("impanel", session_id); + + floater->updateMessages(); + floater->mInputEditor->setFocus(TRUE); + return floater; +} + +//static +bool LLIMFloater::toggle(const LLUUID& session_id) +{ + LLIMFloater* floater = LLFloaterReg::findTypedInstance("impanel", session_id); + if (floater && floater->getVisible()) + { + // clicking on chiclet to close floater just hides it to maintain existing + // scroll/text entry state + floater->setVisible(false); + return false; + } + else + { + // ensure the list of messages is updated when floater is made visible + show(session_id); + // update number of unread notifications in the SysWell + LLBottomTray::getInstance()->getSysWell()->updateUreadIMNotifications(); + return true; + } +} + +void LLIMFloater::updateMessages() +{ + std::list messages = LLIMModel::instance().getMessages(mSessionID, mLastMessageIndex+1); + + if (messages.size()) + { + LLUIColor divider_color = LLUIColorTable::instance().getColor("LtGray_50"); + LLUIColor chat_color = LLUIColorTable::instance().getColor("IMChatColor"); + + std::ostringstream message; + std::list::const_reverse_iterator iter = messages.rbegin(); + std::list::const_reverse_iterator iter_end = messages.rend(); + for (; iter != iter_end; ++iter) + { + LLSD msg = *iter; + + const bool prepend_newline = true; + std::string from = msg["from"].asString(); + if (mLastFromName != from) + { + message << from << " ----- " << msg["time"].asString(); + mHistoryEditor->appendColoredText(message.str(), false, + prepend_newline, divider_color); + message.str(""); + mLastFromName = from; + } + + message << msg["message"].asString(); + mHistoryEditor->appendColoredText(message.str(), false, + prepend_newline, chat_color); + message.str(""); + + mLastMessageIndex = msg["index"].asInteger(); + } + + mHistoryEditor->setCursorAndScrollToEnd(); + } +} + +// static +void LLIMFloater::onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ) +{ + LLIMFloater* self= (LLIMFloater*) userdata; + self->mHistoryEditor->setCursorAndScrollToEnd(); +} + +// static +void LLIMFloater::onInputEditorFocusLost(LLFocusableElement* caller, void* userdata) +{ + LLIMFloater* self = (LLIMFloater*) userdata; + self->setTyping(FALSE); +} + +// static +void LLIMFloater::onInputEditorKeystroke(LLLineEditor* caller, void* userdata) +{ + LLIMFloater* self = (LLIMFloater*)userdata; + std::string text = self->mInputEditor->getText(); + if (!text.empty()) + { + self->setTyping(TRUE); + } + else + { + // Deleting all text counts as stopping typing. + self->setTyping(FALSE); + } +} + + +//just a stub for now +void LLIMFloater::setTyping(BOOL typing) +{ +} + + +void LLIMFloater::draw() +{ + //if we are docked, make sure we've been positioned by the chiclet + if (!isDocked() || mPositioned) + { + LLFloater::draw(); + + if (isDocked()) + { + mDockTongue->draw( (getRect().getWidth()/2) - mDockTongue->getWidth()/2, -mDockTongue->getHeight()); + } + } +} + diff --git a/indra/newview/llimpanel.h b/indra/newview/llimpanel.h index 8b3ca202c7..284a486b0f 100644 --- a/indra/newview/llimpanel.h +++ b/indra/newview/llimpanel.h @@ -47,6 +47,7 @@ class LLInventoryItem; class LLInventoryCategory; class LLIMSpeakerMgr; class LLPanelActiveSpeakers; +class LLPanelChatControlPanel; class LLVoiceChannel : public LLVoiceClientStatusObserver { @@ -77,6 +78,7 @@ public: virtual void getChannelInfo(); virtual BOOL isActive(); virtual BOOL callStarted(); + const std::string& getSessionName() const { return mSessionName; } const LLUUID getSessionID() { return mSessionID; } EState getState() { return mState; } @@ -94,6 +96,7 @@ public: protected: virtual void setState(EState state); + void toggleCallWindowIfNeeded(EState state); void setURI(std::string uri); std::string mURI; @@ -185,11 +188,7 @@ public: LLFloaterIMPanel(const std::string& session_label, const LLUUID& session_id, const LLUUID& target_id, - EInstantMessage dialog); - LLFloaterIMPanel(const std::string& session_label, - const LLUUID& session_id, - const LLUUID& target_id, - const LLDynamicArray& ids, + const std::vector& ids, EInstantMessage dialog); virtual ~LLFloaterIMPanel(); @@ -197,12 +196,13 @@ public: // Check typing timeout timer. /*virtual*/ void draw(); - /*virtual*/ void onClose(bool app_quitting = FALSE); - /*virtual*/ void onVisibilityChange(BOOL new_visibility); + + void onClose(); + void onVisibilityChange(const LLSD& new_visibility); // add target ids to the session. // Return TRUE if successful, otherwise FALSE. - BOOL inviteToSession(const LLDynamicArray& agent_ids); + BOOL inviteToSession(const std::vector& agent_ids); void addHistoryLine(const std::string &utf8msg, const LLColor4& color = LLColor4::white, @@ -214,7 +214,6 @@ public: void selectAll(); void selectNone(); - void setVisible(BOOL b); S32 getNumUnreadMessages() { return mNumUnreadMessages; } @@ -246,11 +245,13 @@ public: const LLUUID& getSessionID() const { return mSessionUUID; } const LLUUID& getOtherParticipantID() const { return mOtherParticipantUUID; } + LLIMSpeakerMgr* getSpeakerManager() const { return mSpeakers; } void updateSpeakersList(const LLSD& speaker_updates); void processSessionUpdate(const LLSD& update); void setSpeakers(const LLSD& speaker_list); LLVoiceChannel* getVoiceChannel() { return mVoiceChannel; } EInstantMessage getDialogType() const { return mDialog; } + void setDialogType(EInstantMessage dialog) { mDialog = dialog; } void requestAutoConnect(); @@ -270,9 +271,6 @@ public: static bool onConfirmForceCloseError(const LLSD& notification, const LLSD& response); private: - // called by constructors - void init(const std::string& session_label); - // Called by UI methods. void sendMsg(); @@ -318,7 +316,7 @@ private: // inventory folder ==> first target id in list // 911 ==> sender LLUUID mOtherParticipantUUID; - LLDynamicArray mSessionInitialTargetIDs; + std::vector mSessionInitialTargetIDs; EInstantMessage mDialog; @@ -360,10 +358,78 @@ private: LLFrameTimer mLastKeystrokeTimer; void disableWhileSessionStarting(); - - typedef std::map styleMap; - static styleMap mStyleMap; }; +// Individual IM window that appears at the bottom of the screen, +// optionally "docked" to the bottom tray. +class LLIMFloater : public LLFloater +{ +public: + LLIMFloater(const LLUUID& session_id); + + virtual ~LLIMFloater(); + + // LLView overrides + /*virtual*/ BOOL postBuild(); + + // LLView overrides for drawing dock tongue + /*virtual*/ + void draw(); + + // Floater should close when user clicks away to other UI area, + // hence causing focus loss. + /*virtual*/ void onFocusLost(); + + // LLFloater overrides + /*virtual*/ void setDocked(bool docked, bool pop_on_undock = true); + + // Make IM conversion visible and update the message history + static LLIMFloater* show(const LLUUID& session_id); + + // Toggle panel specified by session_id + // Returns true iff panel became visible + static bool toggle(const LLUUID& session_id); + + // get new messages from LLIMModel + void updateMessages(); + static void onSendMsg( LLUICtrl*, void*); + void sendMsg(); + + // callback for LLIMModel on new messages + // route to specific floater if it is visible + static void newIMCallback(const LLSD& data); + + // called when docked floater's position has been set by chiclet + void setPositioned(bool b) { mPositioned = b; }; + + + +private: + + static void onInputEditorFocusReceived( LLFocusableElement* caller, void* userdata ); + static void onInputEditorFocusLost(LLFocusableElement* caller, void* userdata); + static void onInputEditorKeystroke(LLLineEditor* caller, void* userdata); + void setTyping(BOOL typing); + void onSlide(); + static void* createPanelIMControl(void* userdata); + static void* createPanelGroupControl(void* userdata); + + LLPanelChatControlPanel* mControlPanel; + LLUUID mSessionID; + S32 mLastMessageIndex; + // username of last user who added text to this conversation, used to + // suppress duplicate username divider bars + std::string mLastFromName; + EInstantMessage mDialog; + LLUUID mOtherParticipantUUID; + LLViewerTextEditor* mHistoryEditor; + LLLineEditor* mInputEditor; + bool mPositioned; + LLUIImagePtr mDockTongue; +}; + + + + #endif // LL_IMPANEL_H diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp index 5b3f3952c9..5272bc2165 100644 --- a/indra/newview/llimview.cpp +++ b/indra/newview/llimview.cpp @@ -34,6 +34,7 @@ #include "llimview.h" +#include "llfloaterreg.h" #include "llfontgl.h" #include "llrect.h" #include "llerror.h" @@ -44,12 +45,13 @@ #include "lluictrlfactory.h" #include "llagent.h" +#include "llavatariconctrl.h" #include "llcallingcard.h" #include "llchat.h" #include "llresmgr.h" #include "llfloaterchat.h" #include "llfloaterchatterbox.h" -#include "llfloaternewim.h" +#include "llavataractions.h" #include "llhttpnode.h" #include "llimpanel.h" #include "llresizebar.h" @@ -67,8 +69,10 @@ #include "llviewerwindow.h" #include "llnotify.h" #include "llviewerregion.h" +#include "lltrans.h" #include "llfirstuse.h" +#include "llagentui.h" // // Globals @@ -88,16 +92,531 @@ std::map LLFloaterIM::sEventStringsMap; std::map LLFloaterIM::sErrorStringsMap; std::map LLFloaterIM::sForceCloseSessionMap; +std::map LLIMModel::sSessionsMap; + + + +void toast_callback(const LLSD& msg){ + + //we send notifications to reset counter also + if (msg["num_unread"].asInteger()) + { + LLSD args; + args["MESSAGE"] = msg["message"]; + args["TIME"] = msg["time"]; + args["FROM"] = msg["from"]; + args["FROM_ID"] = msg["from_id"]; + args["SESSION_ID"] = msg["session_id"]; + + LLNotifications::instance().add("IMToast", args, LLSD(), boost::bind(&LLFloaterChatterBox::onOpen, LLFloaterChatterBox::getInstance(), msg["session_id"].asUUID())); + } +} + +LLIMModel::LLIMModel() +{ + addChangedCallback(toast_callback); + addChangedCallback(LLIMFloater::newIMCallback); +} + + +void LLIMModel::testMessages() +{ + LLUUID bot1_id("d0426ec6-6535-4c11-a5d9-526bb0c654d9"); + LLUUID bot1_session_id; + std::string from = "IM Tester"; + + bot1_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot1_id); + newSession(bot1_session_id, from, IM_NOTHING_SPECIAL, bot1_id); + addMessage(bot1_session_id, from, bot1_id, "Test Message: Hi from testerbot land!"); + + LLUUID bot2_id; + std::string firstname[] = {"Roflcopter", "Joe"}; + std::string lastname[] = {"Linden", "Tester", "Resident", "Schmoe"}; + + S32 rand1 = ll_rand(sizeof firstname)/(sizeof firstname[0]); + S32 rand2 = ll_rand(sizeof lastname)/(sizeof lastname[0]); + + from = firstname[rand1] + " " + lastname[rand2]; + bot2_id.generate(from); + LLUUID bot2_session_id = LLIMMgr::computeSessionID(IM_NOTHING_SPECIAL, bot2_id); + newSession(bot2_session_id, from, IM_NOTHING_SPECIAL, bot2_id); + addMessage(bot2_session_id, from, bot2_id, "Test Message: Can I haz bear? "); + addMessage(bot2_session_id, from, bot2_id, "Test Message: OMGWTFBBQ."); +} + + +bool LLIMModel::newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id) +{ + if (is_in_map(sSessionsMap, session_id)) + { + llwarns << "IM Session " << session_id << " already exists" << llendl; + return false; + } + + LLIMSession* session = new LLIMSession(name, type, other_participant_id); + sSessionsMap[session_id] = session; + + LLIMMgr::getInstance()->notifyObserverSessionAdded(session_id, name, other_participant_id); + + return true; + +} + +bool LLIMModel::clearSession(LLUUID session_id) +{ + if (sSessionsMap.find(session_id) == sSessionsMap.end()) return false; + delete (sSessionsMap[session_id]); + sSessionsMap.erase(session_id); + return true; +} + +std::list LLIMModel::getMessages(LLUUID session_id, int start_index) +{ + std::list return_list; + + LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return return_list; + } + + int i = session->mMsgs.size() - start_index; + + for (std::list::iterator iter = session->mMsgs.begin(); + iter != session->mMsgs.end() && i > 0; + iter++) + { + LLSD msg; + msg = *iter; + return_list.push_back(*iter); + i--; + } + + session->mNumUnread = 0; + + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = 0; + mChangedSignal(arg); + + // TODO: in the future is there a more efficient way to return these + return return_list; + +} + +bool LLIMModel::addToHistory(LLUUID session_id, std::string from, std::string utf8_text) { + + LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return false; + } + + LLSD message; + message["from"] = from; + message["message"] = utf8_text; + message["time"] = LLLogChat::timestamp(false); //might want to add date separately + message["index"] = (LLSD::Integer)session->mMsgs.size(); + + session->mMsgs.push_front(message); + + return true; + +} + + +bool LLIMModel::addMessage(LLUUID session_id, std::string from, LLUUID from_id, std::string utf8_text) { + + LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return false; + } + + addToHistory(session_id, from, utf8_text); + + std::string agent_name; + LLAgentUI::buildFullname(agent_name); + + session->mNumUnread++; + + // notify listeners + LLSD arg; + arg["session_id"] = session_id; + arg["num_unread"] = session->mNumUnread; + arg["message"] = utf8_text; + arg["from"] = from; + arg["from_id"] = from_id; + arg["time"] = LLLogChat::timestamp(false); + mChangedSignal(arg); + + return true; +} + + +const std::string& LLIMModel::getName(LLUUID session_id) +{ + LLIMSession* session = get_if_there(sSessionsMap, session_id, (LLIMSession*)NULL); + + if (!session) + { + llwarns << "session " << session_id << "does not exist " << llendl; + return LLStringUtil::null; + } + + return session->mName; +} + + +// TODO get rid of other participant ID +void LLIMModel::sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing) +{ + std::string name; + LLAgentUI::buildFullname(name); + + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + std::string("typing"), + IM_ONLINE, + (typing ? IM_TYPING_START : IM_TYPING_STOP), + session_id); + gAgent.sendReliableMessage(); +} + +void LLIMModel::sendLeaveSession(LLUUID session_id, LLUUID other_participant_id) +{ + if(session_id.notNull()) + { + std::string name; + LLAgentUI::buildFullname(name); + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name, + LLStringUtil::null, + IM_ONLINE, + IM_SESSION_LEAVE, + session_id); + gAgent.sendReliableMessage(); + } +} + + + +void LLIMModel::sendMessage(const std::string& utf8_text, + const LLUUID& im_session_id, + const LLUUID& other_participant_id, + EInstantMessage dialog) +{ + std::string name; + bool sent = false; + LLAgentUI::buildFullname(name); + + const LLRelationship* info = NULL; + info = LLAvatarTracker::instance().getBuddyInfo(other_participant_id); + + U8 offline = (!info || info->isOnline()) ? IM_ONLINE : IM_OFFLINE; + + if((offline == IM_OFFLINE) && (LLVoiceClient::getInstance()->isOnlineSIP(other_participant_id))) + { + // User is online through the OOW connector, but not with a regular viewer. Try to send the message via SLVoice. + sent = gVoiceClient->sendTextMessage(other_participant_id, utf8_text); + } + + if(!sent) + { + // Send message normally. + + // default to IM_SESSION_SEND unless it's nothing special - in + // which case it's probably an IM to everyone. + U8 new_dialog = dialog; + + if ( dialog != IM_NOTHING_SPECIAL ) + { + new_dialog = IM_SESSION_SEND; + } + pack_instant_message( + gMessageSystem, + gAgent.getID(), + FALSE, + gAgent.getSessionID(), + other_participant_id, + name.c_str(), + utf8_text.c_str(), + offline, + (EInstantMessage)new_dialog, + im_session_id); + gAgent.sendReliableMessage(); + } + + // If there is a mute list and this is not a group chat... + if ( LLMuteList::getInstance() ) + { + // ... the target should not be in our mute list for some message types. + // Auto-remove them if present. + switch( dialog ) + { + case IM_NOTHING_SPECIAL: + case IM_GROUP_INVITATION: + case IM_INVENTORY_OFFERED: + case IM_SESSION_INVITE: + case IM_SESSION_P2P_INVITE: + case IM_SESSION_CONFERENCE_START: + case IM_SESSION_SEND: // This one is marginal - erring on the side of hearing. + case IM_LURE_USER: + case IM_GODLIKE_LURE_USER: + case IM_FRIENDSHIP_OFFERED: + LLMuteList::getInstance()->autoRemove(other_participant_id, LLMuteList::AR_IM); + break; + default: ; // do nothing + } + } + + if((dialog == IM_NOTHING_SPECIAL) && + (other_participant_id.notNull())) + { + // Do we have to replace the /me's here? + std::string from; + LLAgentUI::buildFullname(from); + LLIMModel::instance().addToHistory(im_session_id, from, utf8_text); + + //local echo for the legacy communicate panel + std::string history_echo; + std::string utf8_copy = utf8_text; + LLAgentUI::buildFullname(history_echo); + + // Look for IRC-style emotes here. + + std::string prefix = utf8_copy.substr(0, 4); + if (prefix == "/me " || prefix == "/me'") + { + utf8_copy.replace(0,3,""); + } + else + { + history_echo += ": "; + } + history_echo += utf8_copy; + + LLFloaterIMPanel* floater = gIMMgr->findFloaterBySession(im_session_id); + if (floater) floater->addHistoryLine(history_echo, LLUIColorTable::instance().getColor("IMChatColor"), true, gAgent.getID()); + + } + + // Add the recipient to the recent people list. + LLRecentPeople::instance().add(other_participant_id); +} + +boost::signals2::connection LLIMModel::addChangedCallback( boost::function cb ) +{ + return mChangedSignal.connect(cb); +} + +void session_starter_helper( + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + EInstantMessage im_type) +{ + LLMessageSystem *msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_ImprovedInstantMessage); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + + msg->nextBlockFast(_PREHASH_MessageBlock); + msg->addBOOLFast(_PREHASH_FromGroup, FALSE); + msg->addUUIDFast(_PREHASH_ToAgentID, other_participant_id); + msg->addU8Fast(_PREHASH_Offline, IM_ONLINE); + msg->addU8Fast(_PREHASH_Dialog, im_type); + msg->addUUIDFast(_PREHASH_ID, temp_session_id); + msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary + + std::string name; + LLAgentUI::buildFullname(name); + + msg->addStringFast(_PREHASH_FromAgentName, name); + msg->addStringFast(_PREHASH_Message, LLStringUtil::null); + msg->addU32Fast(_PREHASH_ParentEstateID, 0); + msg->addUUIDFast(_PREHASH_RegionID, LLUUID::null); + msg->addVector3Fast(_PREHASH_Position, gAgent.getPositionAgent()); +} + +void start_deprecated_conference_chat( + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) +{ + U8* bucket; + U8* pos; + S32 count; + S32 bucket_size; + + // *FIX: this could suffer from endian issues + count = agents_to_invite.size(); + bucket_size = UUID_BYTES * count; + bucket = new U8[bucket_size]; + pos = bucket; + + for(S32 i = 0; i < count; ++i) + { + LLUUID agent_id = agents_to_invite[i].asUUID(); + + memcpy(pos, &agent_id, UUID_BYTES); + pos += UUID_BYTES; + } + + session_starter_helper( + temp_session_id, + other_participant_id, + IM_SESSION_CONFERENCE_START); + + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + bucket, + bucket_size); + + gAgent.sendReliableMessage(); + + delete[] bucket; +} + +class LLStartConferenceChatResponder : public LLHTTPClient::Responder +{ +public: + LLStartConferenceChatResponder( + const LLUUID& temp_session_id, + const LLUUID& creator_id, + const LLUUID& other_participant_id, + const LLSD& agents_to_invite) + { + mTempSessionID = temp_session_id; + mCreatorID = creator_id; + mOtherParticipantID = other_participant_id; + mAgents = agents_to_invite; + } + + virtual void error(U32 statusNum, const std::string& reason) + { + //try an "old school" way. + if ( statusNum == 400 ) + { + start_deprecated_conference_chat( + mTempSessionID, + mCreatorID, + mOtherParticipantID, + mAgents); + } + + //else throw an error back to the client? + //in theory we should have just have these error strings + //etc. set up in this file as opposed to the IMMgr, + //but the error string were unneeded here previously + //and it is not worth the effort switching over all + //the possible different language translations + } + +private: + LLUUID mTempSessionID; + LLUUID mCreatorID; + LLUUID mOtherParticipantID; + + LLSD mAgents; +}; + +// Returns true if any messages were sent, false otherwise. +// Is sort of equivalent to "does the server need to do anything?" +bool LLIMModel::sendStartSession( + const LLUUID& temp_session_id, + const LLUUID& other_participant_id, + const std::vector& ids, + EInstantMessage dialog) +{ + if ( dialog == IM_SESSION_GROUP_START ) + { + session_starter_helper( + temp_session_id, + other_participant_id, + dialog); + + switch(dialog) + { + case IM_SESSION_GROUP_START: + gMessageSystem->addBinaryDataFast( + _PREHASH_BinaryBucket, + EMPTY_BINARY_BUCKET, + EMPTY_BINARY_BUCKET_SIZE); + break; + default: + break; + } + gAgent.sendReliableMessage(); + + return true; + } + else if ( dialog == IM_SESSION_CONFERENCE_START ) + { + LLSD agents; + for (int i = 0; i < (S32) ids.size(); i++) + { + agents.append(ids[i]); + } + + //we have a new way of starting conference calls now + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + std::string url = region->getCapability( + "ChatSessionRequest"); + LLSD data; + data["method"] = "start conference"; + data["session-id"] = temp_session_id; + + data["params"] = agents; + + LLHTTPClient::post( + url, + data, + new LLStartConferenceChatResponder( + temp_session_id, + gAgent.getID(), + other_participant_id, + data["params"])); + } + else + { + start_deprecated_conference_chat( + temp_session_id, + gAgent.getID(), + other_participant_id, + agents); + } + } + + return false; +} + + + // // Helper Functions // -// returns true if a should appear before b -//static BOOL group_dictionary_sort( LLGroupData* a, LLGroupData* b ) -//{ -// return (LLStringUtil::compareDict( a->mName, b->mName ) < 0); -//} - class LLViewerChatterBoxInvitationAcceptResponder : public LLHTTPClient::Responder { @@ -145,11 +664,11 @@ public: floaterp->requestAutoConnect(); LLFloaterIMPanel::onClickStartCall(floaterp); // always open IM window when connecting to voice - LLFloaterChatterBox::showInstance(TRUE); + LLFloaterReg::showInstance("communicate", LLSD(), TRUE); } else if ( mInvitiationType == LLIMMgr::INVITATION_TYPE_IMMEDIATE ) { - LLFloaterChatterBox::showInstance(TRUE); + LLFloaterReg::showInstance("communicate", LLSD(), TRUE); } } @@ -234,14 +753,15 @@ LLUUID LLIMMgr::computeSessionID( // LLFloaterIM //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LLFloaterIM::LLFloaterIM() +LLFloaterIM::LLFloaterIM() + : LLMultiFloater(LLSD()) { // autoresize=false is necessary to avoid resizing of the IM window whenever // a session is opened or closed (it would otherwise resize the window to match // the size of the im-sesssion when they were created. This happens in // LLMultiFloater::resizeToContents() when called through LLMultiFloater::addFloater()) - this->mAutoResize = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im.xml"); + mAutoResize = FALSE; + LLUICtrlFactory::getInstance()->buildFloater(this, "floater_im.xml", NULL); } BOOL LLFloaterIM::postBuild() @@ -324,6 +844,172 @@ BOOL LLFloaterIM::postBuild() return TRUE; } +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIncomingCallDialog +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) : + LLModalDialog(payload), + mPayload(payload) +{ +} + +BOOL LLIncomingCallDialog::postBuild() +{ + LLSD caller_id = mPayload["caller_id"]; + EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); + + std::string call_type = getString("VoiceInviteP2P"); + std::string caller_name = mPayload["caller_name"].asString(); + if (caller_name == "anonymous") + { + caller_name = getString("anonymous"); + } + + setTitle(caller_name + " " + call_type); + + // If it is not a P2P invite, then it's an AdHoc invite + if ( type != IM_SESSION_P2P_INVITE ) + { + call_type = getString("VoiceInviteAdHoc"); + } + + LLUICtrl* caller_name_widget = getChild("caller name"); + caller_name_widget->setValue(caller_name + " " + call_type); + LLAvatarIconCtrl* icon = getChild("avatar_icon"); + icon->setValue(caller_id); + + childSetAction("Accept", onAccept, this); + childSetAction("Reject", onReject, this); + childSetAction("Start IM", onStartIM, this); + childSetFocus("Accept"); + + return TRUE; +} + +//static +void LLIncomingCallDialog::onAccept(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(0); + self->closeFloater(); +} + +//static +void LLIncomingCallDialog::onReject(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(1); + self->closeFloater(); +} + +//static +void LLIncomingCallDialog::onStartIM(void* user_data) +{ + LLIncomingCallDialog* self = (LLIncomingCallDialog*)user_data; + self->processCallResponse(2); + self->closeFloater(); +} + +void LLIncomingCallDialog::processCallResponse(S32 response) +{ + LLUUID session_id = mPayload["session_id"].asUUID(); + EInstantMessage type = (EInstantMessage)mPayload["type"].asInteger(); + LLIMMgr::EInvitationType inv_type = (LLIMMgr::EInvitationType)mPayload["inv_type"].asInteger(); + bool voice = true; + switch(response) + { + case 2: // start IM: just don't start the voice chat + { + voice = false; + /* FALLTHROUGH */ + } + case 0: // accept + { + if (type == IM_SESSION_P2P_INVITE) + { + // create a normal IM session + session_id = gIMMgr->addP2PSession( + mPayload["session_name"].asString(), + mPayload["caller_id"].asUUID(), + mPayload["session_handle"].asString()); + + if (voice) + { + LLFloaterIMPanel* im_floater = + gIMMgr->findFloaterBySession( + session_id); + + if (im_floater) + { + im_floater->requestAutoConnect(); + LLFloaterIMPanel::onClickStartCall(im_floater); + } + } + + // always open IM window when connecting to voice + LLFloaterReg::showInstance("communicate", session_id); + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } + else + { + gIMMgr->addSession( + mPayload["session_name"].asString(), + type, + session_id); + + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + if (voice) + { + LLSD data; + data["method"] = "accept invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + new LLViewerChatterBoxInvitationAcceptResponder( + session_id, + inv_type)); + } + } + if (voice) + { + break; + } + } + case 1: // decline + { + if (type == IM_SESSION_P2P_INVITE) + { + if(gVoiceClient) + { + std::string s = mPayload["session_handle"].asString(); + gVoiceClient->declineInvite(s); + } + } + else + { + std::string url = gAgent.getRegion()->getCapability( + "ChatSessionRequest"); + + LLSD data; + data["method"] = "decline invitation"; + data["session-id"] = session_id; + LLHTTPClient::post( + url, + data, + NULL); + } + } + + gIMMgr->clearPendingAgentListUpdates(session_id); + gIMMgr->clearPendingInvitation(session_id); + } +} + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIMViewFriendObserver // @@ -375,7 +1061,7 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) im_floater->requestAutoConnect(); LLFloaterIMPanel::onClickStartCall(im_floater); // always open IM window when connecting to voice - LLFloaterChatterBox::showInstance(session_id); + LLFloaterReg::showInstance("communicate", session_id, TRUE); } gIMMgr->clearPendingAgentListUpdates(session_id); @@ -447,74 +1133,6 @@ bool inviteUserResponse(const LLSD& notification, const LLSD& response) return false; } -// -// Public Static Member Functions -// - -// This is a helper function to determine what kind of im session -// should be used for the given agent. -// static -EInstantMessage LLIMMgr::defaultIMTypeForAgent(const LLUUID& agent_id) -{ - EInstantMessage type = IM_NOTHING_SPECIAL; - if(is_agent_friend(agent_id)) - { - if(LLAvatarTracker::instance().isBuddyOnline(agent_id)) - { - type = IM_SESSION_CONFERENCE_START; - } - } - return type; -} - -// static -//void LLIMMgr::onPinButton(void*) -//{ -// BOOL state = gSavedSettings.getBOOL( "PinTalkViewOpen" ); -// gSavedSettings.setBOOL( "PinTalkViewOpen", !state ); -//} - -// static -void LLIMMgr::toggle(void*) -{ - static BOOL return_to_mouselook = FALSE; - - // Hide the button and show the floater or vice versa. - llassert( gIMMgr ); - BOOL old_state = gIMMgr->getFloaterOpen(); - - // If we're in mouselook and we triggered the Talk View, we want to talk. - if( gAgent.cameraMouselook() && old_state ) - { - return_to_mouselook = TRUE; - gAgent.changeCameraToDefault(); - return; - } - - BOOL new_state = !old_state; - - if (new_state) - { - // ...making visible - if ( gAgent.cameraMouselook() ) - { - return_to_mouselook = TRUE; - gAgent.changeCameraToDefault(); - } - } - else - { - // ...hiding - if ( gAgent.cameraThirdPerson() && return_to_mouselook ) - { - gAgent.changeCameraToMouselook(); - } - return_to_mouselook = FALSE; - } - - gIMMgr->setFloaterOpen( new_state ); -} - // // Member Functions // @@ -523,6 +1141,13 @@ LLIMMgr::LLIMMgr() : mFriendObserver(NULL), mIMReceived(FALSE) { + static bool registered_dialog = false; + if (!registered_dialog) + { + LLFloaterReg::add("incoming_call", "floater_incoming_call.xml.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + registered_dialog = true; + } + mFriendObserver = new LLIMViewFriendObserver(this); LLAvatarTracker::instance().addObserver(mFriendObserver); @@ -614,10 +1239,10 @@ void LLIMMgr::addMessage( { // *TODO:translate (low priority, god ability) std::ostringstream bonus_info; - bonus_info << "*** parent estate: " + bonus_info << LLTrans::getString("***")+ " "+ LLTrans::getString("IMParentEstate") + ":" + " " << parent_estate_id - << ((parent_estate_id == 1) ? ", mainland" : "") - << ((parent_estate_id == 5) ? ", teen" : ""); + << ((parent_estate_id == 1) ? "," + LLTrans::getString("IMMainland") : "") + << ((parent_estate_id == 5) ? "," + LLTrans::getString ("IMTeen") : ""); // once we have web-services (or something) which returns // information about a region id, we can print this out @@ -625,7 +1250,8 @@ void LLIMMgr::addMessage( //<< "*** region_id: " << region_id << std::endl //<< "*** position: " << position << std::endl; - floater->addHistoryLine(bonus_info.str(), gSavedSettings.getColor4("SystemChatColor")); + floater->addHistoryLine(bonus_info.str(), LLUIColorTable::instance().getColor("SystemChatColor")); + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, bonus_info.str()); } make_ui_sound("UISndNewIncomingIMSession"); @@ -634,8 +1260,8 @@ void LLIMMgr::addMessage( // now add message to floater bool is_from_system = target_id.isNull() || (from == SYSTEM_FROM); const LLColor4& color = ( is_from_system ? - gSavedSettings.getColor4("SystemChatColor") : - gSavedSettings.getColor("IMChatColor")); + LLUIColorTable::instance().getColor("SystemChatColor") : + LLUIColorTable::instance().getColor("IMChatColor")); if ( !link_name ) { floater->addHistoryLine(msg,color); // No name to prepend, so just add the message normally @@ -645,10 +1271,12 @@ void LLIMMgr::addMessage( floater->addHistoryLine(msg, color, true, other_participant_id, from); // Insert linked name to front of message } - LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(LLSD()); + LLIMModel::instance().addMessage(new_session_id, from, other_participant_id, msg); - if( !chat_floater->getVisible() && !floater->getVisible()) + if( !LLFloaterReg::instanceVisible("communicate") && !floater->getVisible()) { + LLFloaterChatterBox* chat_floater = LLFloaterChatterBox::getInstance(); + //if the IM window is not open and the floater is not visible (i.e. not torn off) LLFloater* previouslyActiveFloater = chat_floater->getActiveFloater(); @@ -675,14 +1303,12 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess // null session id means near me (chat history) if (session_id.isNull()) { - LLFloaterChat* floaterp = LLFloaterChat::getInstance(); - - message = floaterp->getString(message_name); + message = LLTrans::getString(message_name); message.setArgs(args); LLChat chat(message); chat.mSourceType = CHAT_SOURCE_SYSTEM; - LLFloaterChat::getInstance()->addChatHistory(chat); + LLFloaterChat::addChatHistory(chat); } else // going to IM session { @@ -699,12 +1325,25 @@ void LLIMMgr::addSystemMessage(const LLUUID& session_id, const std::string& mess void LLIMMgr::notifyNewIM() { - if(!gIMMgr->getFloaterOpen()) + if(!LLFloaterReg::instanceVisible("communicate")) { mIMReceived = TRUE; } } +S32 LLIMMgr::getNumberOfUnreadIM() +{ + std::map::iterator it; + + S32 num = 0; + for(it = LLIMModel::sSessionsMap.begin(); it != LLIMModel::sSessionsMap.end(); ++it) + { + num += (*it).second->mNumUnread; + } + + return num; +} + void LLIMMgr::clearNewIMNotification() { mIMReceived = FALSE; @@ -750,39 +1389,9 @@ LLUUID LLIMMgr::addSession( EInstantMessage dialog, const LLUUID& other_participant_id) { - LLUUID session_id = computeSessionID(dialog, other_participant_id); - - LLFloaterIMPanel* floater = findFloaterBySession(session_id); - if(!floater) - { - LLDynamicArray ids; - ids.put(other_participant_id); - - floater = createFloater( - session_id, - other_participant_id, - name, - ids, - dialog, - TRUE); - - noteOfflineUsers(floater, ids); - LLFloaterChatterBox::showInstance(session_id); - - // Only warn for regular IMs - not group IMs - if( dialog == IM_NOTHING_SPECIAL ) - { - noteMutedUsers(floater, ids); - } - LLFloaterChatterBox::getInstance(LLSD())->showFloater(floater); - } - else - { - floater->open(); - } - //mTabContainer->selectTabPanel(panel); - floater->setInputFocus(TRUE); - return floater->getSessionID(); + LLDynamicArray ids; + ids.put(other_participant_id); + return addSession(name, dialog, other_participant_id, ids); } // Adds a session using the given session_id. If the session already exists @@ -798,9 +1407,7 @@ LLUUID LLIMMgr::addSession( return LLUUID::null; } - LLUUID session_id = computeSessionID( - dialog, - other_participant_id); + LLUUID session_id = computeSessionID(dialog,other_participant_id); LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(!floater) @@ -811,14 +1418,13 @@ LLUUID LLIMMgr::addSession( session_id, other_participant_id, name, - ids, dialog, - TRUE); + TRUE, + ids); if ( !floater ) return LLUUID::null; noteOfflineUsers(floater, ids); - LLFloaterChatterBox::showInstance(session_id); // Only warn for regular IMs - not group IMs if( dialog == IM_NOTHING_SPECIAL ) @@ -828,27 +1434,39 @@ LLUUID LLIMMgr::addSession( } else { - floater->open(); + // *TODO: Remove this? Otherwise old communicate window opens on + // second initiation of IM session from People panel? + // floater->openFloater(); } //mTabContainer->selectTabPanel(panel); floater->setInputFocus(TRUE); + LLIMFloater::show(session_id); + notifyObserverSessionAdded(floater->getSessionID(), name, other_participant_id); return floater->getSessionID(); } // This removes the panel referenced by the uuid, and then restores -// internal consistency. The internal pointer is not deleted. +// internal consistency. The internal pointer is not deleted? Did you mean +// a pointer to the corresponding LLIMSession? Session data is cleared now. void LLIMMgr::removeSession(const LLUUID& session_id) { LLFloaterIMPanel* floater = findFloaterBySession(session_id); if(floater) { mFloaters.erase(floater->getHandle()); - LLFloaterChatterBox::getInstance(LLSD())->removeFloater(floater); + LLFloaterChatterBox::getInstance()->removeFloater(floater); //mTabContainer->removeTabPanel(floater); clearPendingInvitation(session_id); clearPendingAgentListUpdates(session_id); } + notifyObserverSessionRemoved(session_id); + + //if we don't clear session data on removing the session + //we can't use LLBottomTray as observer of session creation/delettion and + //creating chiclets only on session created even, we need to handle chiclets creation + //the same way as LLFloaterIMPanels were managed. + LLIMModel::getInstance()->clearSession(session_id); } void LLIMMgr::inviteToSession( @@ -932,66 +1550,55 @@ void LLIMMgr::inviteToSession( { if (caller_name.empty()) { - BOOL is_group = FALSE; // Inviter must be a person - gCacheName->getNameFromUUID(caller_id, is_group, onInviteNameLookup, new LLSD(payload)); + gCacheName->get(caller_id, FALSE, boost::bind(&LLIMMgr::onInviteNameLookup, payload, _1, _2, _3, _4)); } else { - LLSD args; - args["NAME"] = caller_name; - args["GROUP"] = session_name; - - LLNotifications::instance().add(notify_box_type, - args, - payload, - &inviteUserResponse); + if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") + { + LLFloaterReg::showInstance("incoming_call", payload, TRUE); + } + else + { + LLSD args; + args["NAME"] = caller_name; + args["GROUP"] = session_name; + LLNotifications::instance().add(notify_box_type, args, payload, &inviteUserResponse); + } } mPendingInvitations[session_id.asString()] = LLSD(); } } -//static -void LLIMMgr::onInviteNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* userdata) +void LLIMMgr::onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) { - LLSD payload = *(LLSD*)userdata; - delete (LLSD*)userdata; - payload["caller_name"] = first + " " + last; payload["session_name"] = payload["caller_name"].asString(); - LLSD args; - args["NAME"] = payload["caller_name"].asString(); + std::string notify_box_type = payload["notify_box_type"].asString(); - LLNotifications::instance().add( - payload["notify_box_type"].asString(), - args, - payload, - &inviteUserResponse); + if (notify_box_type == "VoiceInviteP2P" || notify_box_type == "VoiceInviteAdHoc") + { + LLFloaterReg::showInstance("incoming_call", payload, TRUE); + } + else + { + LLSD args; + args["NAME"] = payload["caller_name"].asString(); + + LLNotifications::instance().add( + payload["notify_box_type"].asString(), + args, + payload, + &inviteUserResponse); + } } void LLIMMgr::refresh() { } -void LLIMMgr::setFloaterOpen(BOOL set_open) -{ - if (set_open) - { - LLFloaterChatterBox::showInstance(); - } - else - { - LLFloaterChatterBox::hideInstance(); - } -} - - -BOOL LLIMMgr::getFloaterOpen() -{ - return LLFloaterChatterBox::instanceVisible(LLSD()); -} - void LLIMMgr::disconnectAllSessions() { LLFloaterIMPanel* floater = NULL; @@ -1008,7 +1615,7 @@ void LLIMMgr::disconnectAllSessions() if (floater) { floater->setEnabled(FALSE); - floater->close(TRUE); + floater->closeFloater(TRUE); } } } @@ -1129,6 +1736,32 @@ void LLIMMgr::clearPendingAgentListUpdates(const LLUUID& session_id) } } +void LLIMMgr::notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionAdded(session_id, name, other_participant_id); + } +} + +void LLIMMgr::notifyObserverSessionRemoved(const LLUUID& session_id) +{ + for (session_observers_list_t::iterator it = mSessionObservers.begin(); it != mSessionObservers.end(); it++) + { + (*it)->sessionRemoved(session_id); + } +} + +void LLIMMgr::addSessionObserver(LLIMSessionObserver *observer) +{ + mSessionObservers.push_back(observer); +} + +void LLIMMgr::removeSessionObserver(LLIMSessionObserver *observer) +{ + mSessionObservers.remove(observer); +} + // create a floater and update internal representation for // consistency. Returns the pointer, caller (the class instance since // it is a private method) is not responsible for deleting the @@ -1138,32 +1771,8 @@ LLFloaterIMPanel* LLIMMgr::createFloater( const LLUUID& other_participant_id, const std::string& session_label, EInstantMessage dialog, - BOOL user_initiated) -{ - if (session_id.isNull()) - { - llwarns << "Creating LLFloaterIMPanel with null session ID" << llendl; - } - - llinfos << "LLIMMgr::createFloater: from " << other_participant_id - << " in session " << session_id << llendl; - LLFloaterIMPanel* floater = new LLFloaterIMPanel(session_label, - session_id, - other_participant_id, - dialog); - LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; - LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt); - mFloaters.insert(floater->getHandle()); - return floater; -} - -LLFloaterIMPanel* LLIMMgr::createFloater( - const LLUUID& session_id, - const LLUUID& other_participant_id, - const std::string& session_label, - const LLDynamicArray& ids, - EInstantMessage dialog, - BOOL user_initiated) + BOOL user_initiated, + const LLDynamicArray& ids) { if (session_id.isNull()) { @@ -1178,8 +1787,9 @@ LLFloaterIMPanel* LLIMMgr::createFloater( ids, dialog); LLTabContainer::eInsertionPoint i_pt = user_initiated ? LLTabContainer::RIGHT_OF_CURRENT : LLTabContainer::END; - LLFloaterChatterBox::getInstance(LLSD())->addFloater(floater, FALSE, i_pt); + LLFloaterChatterBox::getInstance()->addFloater(floater, FALSE, i_pt); mFloaters.insert(floater->getHandle()); + LLIMModel::instance().newSession(session_id, session_label, dialog, other_participant_id); return floater; } @@ -1190,7 +1800,7 @@ void LLIMMgr::noteOfflineUsers( S32 count = ids.count(); if(count == 0) { - floater->addHistoryLine(sOnlyUserMessage, gSavedSettings.getColor4("SystemChatColor")); + floater->addHistoryLine(sOnlyUserMessage, LLUIColorTable::instance().getColor("SystemChatColor")); } else { @@ -1206,7 +1816,7 @@ void LLIMMgr::noteOfflineUsers( LLUIString offline = sOfflineMessage; offline.setArg("[FIRST]", first); offline.setArg("[LAST]", last); - floater->addHistoryLine(offline, gSavedSettings.getColor4("SystemChatColor")); + floater->addHistoryLine(offline, LLUIColorTable::instance().getColor("SystemChatColor")); } } } @@ -1268,11 +1878,6 @@ void LLIMMgr::updateFloaterSessionID( } } -LLFloaterChatterBox* LLIMMgr::getFloater() -{ - return LLFloaterChatterBox::getInstance(LLSD()); -} - class LLViewerChatterBoxSessionStartReply : public LLHTTPNode { public: @@ -1515,7 +2120,7 @@ public: { saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); } - std::string buffer = separator_string + saved + message.substr(message_offset); + std::string buffer = saved + message.substr(message_offset); BOOL is_this_agent = FALSE; if(from_id == gAgentID) diff --git a/indra/newview/llimview.h b/indra/newview/llimview.h index a4e419694d..ce6f0394dd 100644 --- a/indra/newview/llimview.h +++ b/indra/newview/llimview.h @@ -33,9 +33,12 @@ #ifndef LL_LLIMVIEW_H #define LL_LLIMVIEW_H -#include "llfloater.h" +#include "lldarray.h" +#include "llmodaldialog.h" #include "llinstantmessage.h" #include "lluuid.h" +#include "llmultifloater.h" +#include "llrecentpeople.h" class LLFloaterChatterBox; class LLUUID; @@ -43,8 +46,61 @@ class LLFloaterIMPanel; class LLFriendObserver; class LLFloaterIM; +class LLIMModel : public LLSingleton +{ +public: + + struct LLIMSession + { + LLIMSession(std::string name, EInstantMessage type, LLUUID other_participant_id) + :mName(name), mType(type), mNumUnread(0), mOtherParticipantID(other_participant_id) {} + + std::string mName; + EInstantMessage mType; + LLUUID mOtherParticipantID; + S32 mNumUnread; + std::list mMsgs; + }; + + + LLIMModel(); + + static std::map sSessionsMap; //mapping session_id to session + boost::signals2::signal mChangedSignal; + boost::signals2::connection addChangedCallback( boost::function cb ); + + bool newSession(LLUUID session_id, std::string name, EInstantMessage type, LLUUID other_participant_id); + bool clearSession(LLUUID session_id); + std::list getMessages(LLUUID session_id, int start_index = 0); + bool addMessage(LLUUID session_id, std::string from, LLUUID other_participant_id, std::string utf8_text); + bool addToHistory(LLUUID session_id, std::string from, std::string utf8_text); + //used to get the name of the session, for use as the title + //currently just the other avatar name + const std::string& getName(LLUUID session_id); + + static void sendLeaveSession(LLUUID session_id, LLUUID other_participant_id); + static bool sendStartSession(const LLUUID& temp_session_id, const LLUUID& other_participant_id, + const std::vector& ids, EInstantMessage dialog); + static void sendTypingState(LLUUID session_id, LLUUID other_participant_id, BOOL typing); + static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, + const LLUUID& other_participant_id, EInstantMessage dialog); + + void testMessages(); +}; + +class LLIMSessionObserver +{ +public: + virtual ~LLIMSessionObserver() {} + virtual void sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id) = 0; + virtual void sessionRemoved(const LLUUID& session_id) = 0; +}; + + class LLIMMgr : public LLSingleton { + friend class LLIMModel; + public: enum EInvitationType { @@ -134,10 +190,8 @@ public: // IM received that you haven't seen yet BOOL getIMReceived() const; - void setFloaterOpen(BOOL open); /*Flawfinder: ignore*/ - BOOL getFloaterOpen(); - - LLFloaterChatterBox* getFloater(); + // Calc number of unread IMs + S32 getNumberOfUnreadIM(); // This method is used to go through all active sessions and // disable all of them. This method is usally called when you are @@ -145,8 +199,6 @@ public: // good connection. void disconnectAllSessions(); - static void toggle(void*); - // This is a helper function to determine what kind of im session // should be used for the given agent. static EInstantMessage defaultIMTypeForAgent(const LLUUID& agent_id); @@ -171,6 +223,9 @@ public: //HACK: need a better way of enumerating existing session, or listening to session create/destroy events const std::set >& getIMFloaterHandles() { return mFloaters; } + void addSessionObserver(LLIMSessionObserver *); + void removeSessionObserver(LLIMSessionObserver *); + private: // create a panel and update internal representation for // consistency. Returns the pointer, caller (the class instance @@ -180,14 +235,8 @@ private: const LLUUID& target_id, const std::string& name, EInstantMessage dialog, - BOOL user_initiated = FALSE); - - LLFloaterIMPanel* createFloater(const LLUUID& session_id, - const LLUUID& target_id, - const std::string& name, - const LLDynamicArray& ids, - EInstantMessage dialog, - BOOL user_initiated = FALSE); + BOOL user_initiated = FALSE, + const LLDynamicArray& ids = LLDynamicArray()); // This simple method just iterates through all of the ids, and // prints a simple message if they are not online. Used to help @@ -198,12 +247,18 @@ private: void processIMTypingCore(const LLIMInfo* im_info, BOOL typing); - static void onInviteNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* userdata); + static void onInviteNameLookup(LLSD payload, const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); + + void notifyObserverSessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id); + void notifyObserverSessionRemoved(const LLUUID& session_id); private: std::set > mFloaters; LLFriendObserver* mFriendObserver; + typedef std::list session_observers_list_t; + session_observers_list_t mSessionObservers; + // An IM has been received that you haven't seen yet. BOOL mIMReceived; @@ -223,6 +278,23 @@ public: static std::map sForceCloseSessionMap; }; +class LLIncomingCallDialog : public LLModalDialog +{ +public: + LLIncomingCallDialog(const LLSD& payload); + + /*virtual*/ BOOL postBuild(); + + static void onAccept(void* user_data); + static void onReject(void* user_data); + static void onStartIM(void* user_data); + +private: + void processCallResponse(S32 response); + + LLSD mPayload; +}; + // Globals extern LLIMMgr *gIMMgr; diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp new file mode 100644 index 0000000000..5bb96f0469 --- /dev/null +++ b/indra/newview/llinspectavatar.cpp @@ -0,0 +1,127 @@ +/** + * @file llinspectavatar.cpp + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llinspectavatar.h" + +// viewer files +#include "llagentdata.h" +#include "llavataractions.h" +#include "llcallingcard.h" + +// linden libraries +#include "lluictrl.h" + + +LLInspectAvatar::LLInspectAvatar(const LLSD& avatar_id) +: LLFloater(avatar_id), + mAvatarID( avatar_id.asUUID() ), + mFirstName(), + mLastName() +{ +} + +LLInspectAvatar::~LLInspectAvatar() +{ +} + +/*virtual*/ +BOOL LLInspectAvatar::postBuild(void) +{ + getChild("add_friend_btn")->setCommitCallback( + boost::bind(&LLInspectAvatar::onClickAddFriend, this) ); + + getChild("view_profile_btn")->setCommitCallback( + boost::bind(&LLInspectAvatar::onClickViewProfile, this) ); + + // can't call from constructor as widgets are not built yet + refresh(); + + return TRUE; +} + +void LLInspectAvatar::setAvatarID(const LLUUID &avatar_id) +{ + mAvatarID = avatar_id; + refresh(); +} + +void LLInspectAvatar::refresh() +{ + // *HACK: Don't stomp data when spawning from login screen + if (mAvatarID.isNull()) return; + + // You can't re-add someone as a friend if they are already your friend + bool is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; + bool is_self = (mAvatarID == gAgentID); + childSetEnabled("add_friend_btn", !is_friend && !is_self); + + // *TODO: replace with generic + // LLAvatarPropertiesProcessor::getInstance()->addObserver() + // ->sendDataRequest() + childSetValue("avatar_icon", LLSD(mAvatarID) ); + + gCacheName->get(mAvatarID, FALSE, + boost::bind(&LLInspectAvatar::nameUpdatedCallback, + this, _1, _2, _3, _4)); +} + +void LLInspectAvatar::nameUpdatedCallback( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group) +{ + // Possibly a request for an older inspector + if (id != mAvatarID) return; + + mFirstName = first; + mLastName = last; + std::string name = first + " " + last; + + childSetValue("user_name", LLSD(name) ); +} + +void LLInspectAvatar::onClickAddFriend() +{ + std::string name; + name.assign(getFirstName()); + name.append(" "); + name.append(getLastName()); + + LLAvatarActions::requestFriendshipDialog(getAvatarID(), name); +} + +void LLInspectAvatar::onClickViewProfile() +{ + LLAvatarActions::showProfile(getAvatarID()); +} diff --git a/indra/newview/llinspectavatar.h b/indra/newview/llinspectavatar.h new file mode 100644 index 0000000000..05b0d6fe20 --- /dev/null +++ b/indra/newview/llinspectavatar.h @@ -0,0 +1,80 @@ +/** + * @file llinspectavatar.h + * @brief Avatar Inspector, a small information window used when clicking + * on avatar names in the 2D UI and in the ambient inspector widget for + * the 3D world. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLINSPECTAVATAR_H +#define LLINSPECTAVATAR_H + +#include "llfloater.h" + +class LLInspectAvatar : public LLFloater +{ + friend class LLFloaterReg; + +public: + // key is the UUID of avatar for whom to show information + // *TODO: Needs to take a spawn location + LLInspectAvatar(const LLSD& avatar_id); + virtual ~LLInspectAvatar(); + + /*virtual*/ BOOL postBuild(void); + + void setAvatarID(const LLUUID &avatar_id); + + const LLUUID& getAvatarID() const { return mAvatarID; } + const std::string& getFirstName() const { return mFirstName; } + const std::string& getLastName() const { return mLastName; } + +private: + // Update widgets, including avatar name, buttons enabled, etc. + // Used after avatar id changes. + void refresh(); + + void onClickAddFriend(); + void onClickViewProfile(); + + void nameUpdatedCallback( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group); + +private: + LLUUID mAvatarID; + // Need avatar name information to spawn friend add request + std::string mFirstName; + std::string mLastName; +}; + + +#endif diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d96bcf5bbf..789e628b67 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -34,14 +34,16 @@ #include // for std::pair<> -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llinventorybridge.h" #include "message.h" #include "llagent.h" +#include "llagentwearables.h" #include "llcallingcard.h" #include "llcheckboxctrl.h" // for radio buttons +#include "llfloaterreg.h" #include "llradiogroup.h" #include "llspinctrl.h" #include "lltextbox.h" @@ -49,13 +51,15 @@ #include "llviewercontrol.h" #include "llfirstuse.h" -#include "llfloateravatarinfo.h" +#include "llfoldertype.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterproperties.h" #include "llfloaterworldmap.h" #include "llfocusmgr.h" #include "llfolderview.h" +#include "llfriendcard.h" +#include "llavataractions.h" #include "llgesturemgr.h" #include "lliconctrl.h" #include "llinventorymodel.h" @@ -64,7 +68,6 @@ #include "llmenugl.h" #include "llpreviewanim.h" #include "llpreviewgesture.h" -#include "llpreviewlandmark.h" #include "llpreviewnotecard.h" #include "llpreviewscript.h" #include "llpreviewsound.h" @@ -73,7 +76,7 @@ #include "llscrollcontainer.h" #include "llimview.h" #include "lltooldraganddrop.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" #include "llviewerwindow.h" @@ -82,10 +85,13 @@ #include "llwearablelist.h" #include "llviewermessage.h" #include "llviewerregion.h" +#include "llvoavatarself.h" #include "lltabcontainer.h" #include "lluictrlfactory.h" #include "llselectmgr.h" +#include "llsidetray.h" #include "llfloateropenobject.h" +#include "lltrans.h" using namespace LLOldEvents; @@ -106,12 +112,13 @@ void dec_busy_count() // Function declarations struct LLWearableHoldingPattern; +void wear_add_inventory_item_on_avatar(LLInventoryItem* item); void wear_inventory_category_on_avatar(LLInventoryCategory* category, BOOL append); -void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata); +void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links); void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void*); void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, BOOL append); void remove_inventory_category_from_avatar(LLInventoryCategory* category); -void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata); +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id); bool move_task_inventory_callback(const LLSD& notification, const LLSD& response, LLMoveInv*); bool confirm_replace_attachment_rez(const LLSD& notification, const LLSD& response); @@ -144,23 +151,38 @@ std::string ICON_NAME[ICON_NAME_COUNT] = "inv_item_undershirt.tga", "inv_item_underpants.tga", "inv_item_skirt.tga", + "inv_item_alpha.tga", + "inv_item_tattoo.tga", "inv_item_animation.tga", "inv_item_gesture.tga", -}; -struct LLWearInfo -{ - LLUUID mCategoryID; - BOOL mAppend; + "inv_item_linkitem.tga", + "inv_item_linkfolder.tga" }; BOOL gAddToOutfit = FALSE; + +// +=================================================+ +// | LLInventoryPanelObserver | +// +=================================================+ +void LLInventoryPanelObserver::changed(U32 mask) +{ + mIP->modelChanged(mask); +} + + // +=================================================+ // | LLInvFVBridge | // +=================================================+ +LLInvFVBridge::LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : +mUUID(uuid), mInvType(LLInventoryType::IT_NONE) +{ + mInventoryPanel = inventory->getHandle(); +} + const std::string& LLInvFVBridge::getName() const { LLInventoryObject* obj = getInventoryObject(); @@ -183,6 +205,13 @@ PermissionMask LLInvFVBridge::getPermissionMask() const return PERM_ALL; } +// virtual +LLAssetType::EType LLInvFVBridge::getPreferredType() const +{ + return LLAssetType::AT_NONE; +} + + // Folders don't have creation dates. time_t LLInvFVBridge::getCreationDate() const { @@ -192,15 +221,47 @@ time_t LLInvFVBridge::getCreationDate() const // Can be destoryed (or moved to trash) BOOL LLInvFVBridge::isItemRemovable() { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; - if(model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID())) + if(model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) { return TRUE; } return FALSE; } +// Sends an update to all link items that point to the base item. +void LLInvFVBridge::renameLinkedItems(const LLUUID &item_id, const std::string& new_name) +{ + LLInventoryModel* model = getInventoryModel(); + if(!model) return; + + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + if (itemp->getIsLinkType()) + { + return; + } + + LLInventoryModel::item_array_t item_array; + model->collectLinkedItems(item_id, item_array); + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + if (linked_item->getUUID() == item_id) continue; + + LLPointer new_item = new LLViewerInventoryItem(linked_item); + new_item->rename(new_name); + new_item->updateServer(FALSE); + model->updateItem(new_item); + // model->addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + } + model->notifyObservers(); +} + // Can be moved to another folder BOOL LLInvFVBridge::isItemMovable() { @@ -210,14 +271,14 @@ BOOL LLInvFVBridge::isItemMovable() // *TODO: make sure this does the right thing void LLInvFVBridge::showProperties() { - LLShowProps::showProperties(mUUID); + LLFloaterReg::showInstance("properties", mUUID); } void LLInvFVBridge::removeBatch(LLDynamicArray& batch) { // Deactivate gestures when moving them into Trash LLInvFVBridge* bridge; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); LLViewerInventoryItem* item = NULL; LLViewerInventoryCategory* cat = NULL; LLInventoryModel::cat_array_t descendent_categories; @@ -233,7 +294,7 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc { if(LLAssetType::AT_GESTURE == item->getType()) { - gGestureManager.deactivateGesture(item->getUUID()); + LLGestureManager::instance().deactivateGesture(item->getUUID()); } } } @@ -249,7 +310,7 @@ void LLInvFVBridge::removeBatch(LLDynamicArray& batc { if(LLAssetType::AT_GESTURE == descendent_items[j]->getType()) { - gGestureManager.deactivateGesture(descendent_items[j]->getUUID()); + LLGestureManager::instance().deactivateGesture(descendent_items[j]->getUUID()); } } } @@ -265,7 +326,7 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArraygetModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; LLMessageSystem* msg = gMessageSystem; LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); @@ -369,20 +430,76 @@ void LLInvFVBridge::removeBatchNoCheck(LLDynamicArraygetModel(); - if(!model) return FALSE; - BOOL is_agent_inventory = model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()); - - if(LLInventoryClipboard::instance().hasContents() && is_agent_inventory) + if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) { - return TRUE; + return FALSE; } - return FALSE; + LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return FALSE; + } + + const LLUUID &agent_id = gAgent.getID(); + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + const LLUUID &item_id = objects.get(i); + + // Can't paste folders + const LLInventoryCategory *cat = model->getCategory(item_id); + if (cat) + { + return FALSE; + } + + const LLInventoryItem *item = model->getItem(item_id); + if (item) + { + if (!item->getPermissions().allowCopyBy(agent_id)) + { + return FALSE; + } + } + } + return TRUE; +} + +BOOL LLInvFVBridge::isClipboardPasteableAsLink() const +{ + if (!LLInventoryClipboard::instance().hasContents() || !isAgentInventory()) + { + return FALSE; + } + LLInventoryModel* model = getInventoryModel(); + if (!model) + { + return FALSE; + } + + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + for(S32 i = 0; i < count; i++) + { + LLInventoryItem *item = model->getItem(objects.get(i)); + if (item) + { + if (!LLAssetType::lookupCanLink(item->getActualType())) + { + return FALSE; + } + } + } + return TRUE; } void hideContextEntries(LLMenuGL& menu, - const std::vector &entries_to_show, - const std::vector &disabled_entries) + const std::vector &entries_to_show, + const std::vector &disabled_entries) { const LLView::child_list_t *list = menu.getChildList(); @@ -426,10 +543,10 @@ void hideContextEntries(LLMenuGL& menu, } // Helper for commonly-used entries -void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector &items, - std::vector &disabled_items, U32 flags) +void LLInvFVBridge::getClipboardEntries(bool show_asset_id, + std::vector &items, + std::vector &disabled_items, U32 flags) { - // *TODO: Translate items.push_back(std::string("Rename")); if (!isItemRenameable() || (flags & FIRST_SELECTED_ITEM) == 0) { @@ -460,6 +577,11 @@ void LLInvFVBridge::getClipboardEntries(bool show_asset_id, std::vector items; std::vector disabled_items; if(isInTrash()) { - items.push_back(std::string("Purge Item")); + items.push_back(std::string("PurgeItem")); if (!isItemRemovable()) { - disabled_items.push_back(std::string("Purge Item")); + disabled_items.push_back(std::string("PurgeItem")); } - items.push_back(std::string("Restore Item")); + items.push_back(std::string("RestoreItem")); } else { @@ -503,7 +624,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const if(obj) { - *type = LLAssetType::lookupDragAndDropType(obj->getType()); + *type = LLAssetType::lookupDragAndDropType(obj->getActualType()); if(*type == DAD_NONE) { return FALSE; @@ -526,7 +647,7 @@ BOOL LLInvFVBridge::startDrag(EDragAndDropType* type, LLUUID* id) const LLInventoryObject* LLInvFVBridge::getInventoryObject() const { LLInventoryObject* obj = NULL; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(model) { obj = (LLInventoryObject*)model->getObject(mUUID); @@ -534,20 +655,41 @@ LLInventoryObject* LLInvFVBridge::getInventoryObject() const return obj; } +LLInventoryModel* LLInvFVBridge::getInventoryModel() const +{ + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + return panel ? panel->getModel() : NULL; +} + BOOL LLInvFVBridge::isInTrash() const { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; - LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); + const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); return model->isObjectDescendentOf(mUUID, trash_id); } +BOOL LLInvFVBridge::isLinkedObjectInTrash() const +{ + if (isInTrash()) return TRUE; + + LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryModel* model = getInventoryModel(); + if(!model) return FALSE; + const LLUUID& trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); + return model->isObjectDescendentOf(obj->getLinkedUUID(), trash_id); + } + return FALSE; +} + BOOL LLInvFVBridge::isAgentInventory() const { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; - if(gAgent.getInventoryRootID() == mUUID) return TRUE; - return model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID()); + if(gInventory.getRootFolderID() == mUUID) return TRUE; + return model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); } BOOL LLInvFVBridge::isItemPermissive() const @@ -613,112 +755,125 @@ const std::string safe_inv_type_lookup(LLInventoryType::EType inv_type) } LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, - LLInventoryType::EType inv_type, - LLInventoryPanel* inventory, - const LLUUID& uuid, - U32 flags) + LLAssetType::EType actual_asset_type, + LLInventoryType::EType inv_type, + LLInventoryPanel* inventory, + const LLUUID& uuid, + U32 flags) { LLInvFVBridge* new_listener = NULL; switch(asset_type) { - case LLAssetType::AT_TEXTURE: - if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLTextureBridge(inventory, uuid, inv_type); - break; + case LLAssetType::AT_TEXTURE: + if(!(inv_type == LLInventoryType::IT_TEXTURE || inv_type == LLInventoryType::IT_SNAPSHOT)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLTextureBridge(inventory, uuid, inv_type); + break; - case LLAssetType::AT_SOUND: - if(!(inv_type == LLInventoryType::IT_SOUND)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLSoundBridge(inventory, uuid); - break; + case LLAssetType::AT_SOUND: + if(!(inv_type == LLInventoryType::IT_SOUND)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLSoundBridge(inventory, uuid); + break; - case LLAssetType::AT_LANDMARK: - if(!(inv_type == LLInventoryType::IT_LANDMARK)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLandmarkBridge(inventory, uuid, flags); - break; + case LLAssetType::AT_LANDMARK: + if(!(inv_type == LLInventoryType::IT_LANDMARK)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLLandmarkBridge(inventory, uuid, flags); + break; - case LLAssetType::AT_CALLINGCARD: - if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLCallingCardBridge(inventory, uuid); - break; + case LLAssetType::AT_CALLINGCARD: + if(!(inv_type == LLInventoryType::IT_CALLINGCARD)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLCallingCardBridge(inventory, uuid); + break; - case LLAssetType::AT_SCRIPT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLScriptBridge(inventory, uuid); - break; + case LLAssetType::AT_SCRIPT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLScriptBridge(inventory, uuid); + break; - case LLAssetType::AT_OBJECT: - if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); - break; + case LLAssetType::AT_OBJECT: + if(!(inv_type == LLInventoryType::IT_OBJECT || inv_type == LLInventoryType::IT_ATTACHMENT)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLObjectBridge(inventory, uuid, inv_type, flags); + break; - case LLAssetType::AT_NOTECARD: - if(!(inv_type == LLInventoryType::IT_NOTECARD)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLNotecardBridge(inventory, uuid); - break; + case LLAssetType::AT_NOTECARD: + if(!(inv_type == LLInventoryType::IT_NOTECARD)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLNotecardBridge(inventory, uuid); + break; - case LLAssetType::AT_ANIMATION: - if(!(inv_type == LLInventoryType::IT_ANIMATION)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLAnimationBridge(inventory, uuid); - break; + case LLAssetType::AT_ANIMATION: + if(!(inv_type == LLInventoryType::IT_ANIMATION)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLAnimationBridge(inventory, uuid); + break; - case LLAssetType::AT_GESTURE: - if(!(inv_type == LLInventoryType::IT_GESTURE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLGestureBridge(inventory, uuid); - break; + case LLAssetType::AT_GESTURE: + if(!(inv_type == LLInventoryType::IT_GESTURE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLGestureBridge(inventory, uuid); + break; - case LLAssetType::AT_LSL_TEXT: - if(!(inv_type == LLInventoryType::IT_LSL)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLLSLTextBridge(inventory, uuid); - break; + case LLAssetType::AT_LSL_TEXT: + if(!(inv_type == LLInventoryType::IT_LSL)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLLSLTextBridge(inventory, uuid); + break; - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_BODYPART: - if(!(inv_type == LLInventoryType::IT_WEARABLE)) - { - llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; - } - new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); - break; - - case LLAssetType::AT_CATEGORY: - case LLAssetType::AT_ROOT_CATEGORY: - new_listener = new LLFolderBridge(inventory, uuid); - break; - - default: - llinfos << "Unhandled asset type (llassetstorage.h): " - << (S32)asset_type << llendl; - break; + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + if(!(inv_type == LLInventoryType::IT_WEARABLE)) + { + llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl; + } + new_listener = new LLWearableBridge(inventory, uuid, asset_type, inv_type, (EWearableType)flags); + break; + case LLAssetType::AT_CATEGORY: + case LLAssetType::AT_ROOT_CATEGORY: + if (actual_asset_type == LLAssetType::AT_LINK_FOLDER) + { + // Create a link folder handler instead. + new_listener = new LLLinkFolderBridge(inventory, uuid); + break; + } + new_listener = new LLFolderBridge(inventory, uuid); + break; + case LLAssetType::AT_LINK: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; + case LLAssetType::AT_LINK_FOLDER: + // Only should happen for broken links. + new_listener = new LLLinkItemBridge(inventory, uuid); + break; + default: + llinfos << "Unhandled asset type (llassetstorage.h): " + << (S32)asset_type << llendl; + break; } if (new_listener) @@ -729,41 +884,56 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type, return new_listener; } +void LLInvFVBridge::purgeItem(LLInventoryModel *model, const LLUUID &uuid) +{ + LLInventoryCategory* cat = model->getCategory(uuid); + if (cat) + { + model->purgeDescendentsOf(uuid); + model->notifyObservers(); + } + LLInventoryObject* obj = model->getObject(uuid); + if (obj) + { + model->purgeObject(uuid); + model->notifyObservers(); + } +} + // +=================================================+ // | LLItemBridge | // +=================================================+ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { + if ("goto" == action) + { + gotoItem(folder); + } if ("open" == action) { openItem(); + return; } else if ("properties" == action) { showProperties(); + return; } else if ("purge" == action) { - LLInventoryCategory* cat = model->getCategory(mUUID); - if(cat) - { - model->purgeDescendentsOf(mUUID); - } - LLInventoryObject* obj = model->getObject(mUUID); - if(!obj) return; - obj->removeFromServer(); - LLPreview::hide(mUUID); - model->deleteObject(mUUID); - model->notifyObservers(); + purgeItem(model, mUUID); + return; } else if ("restoreToWorld" == action) { restoreToWorld(); + return; } else if ("restore" == action) { restoreItem(); + return; } else if ("copy_uuid" == action) { @@ -794,6 +964,18 @@ void LLItemBridge::performAction(LLFolderView* folder, LLInventoryModel* model, folder_view_itemp->getListener()->pasteFromClipboard(); return; } + else if ("paste_link" == action) + { + // Single item only + LLInventoryItem* itemp = model->getItem(mUUID); + if (!itemp) return; + + LLFolderViewItem* folder_view_itemp = folder->getItemByID(itemp->getParentUUID()); + if (!folder_view_itemp) return; + + folder_view_itemp->getListener()->pasteLinkFromClipboard(); + return; + } } void LLItemBridge::selectItem() @@ -810,7 +992,7 @@ void LLItemBridge::restoreItem() LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); if(item) { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); LLUUID new_parent = model->findCategoryUUIDForType(item->getType()); // do not restamp on restore. LLInvFVBridge::changeItemParent(model, item, new_parent, FALSE); @@ -858,6 +1040,19 @@ void LLItemBridge::restoreToWorld() } } +void LLItemBridge::gotoItem(LLFolderView *folder) +{ + LLInventoryObject *obj = getInventoryObject(); + if (obj && obj->getIsLinkType()) + { + LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); + if (active_panel) + { + active_panel->setSelection(obj->getLinkedUUID(), TAKE_FOCUS_NO); + } + } +} + LLUIImagePtr LLItemBridge::getIcon() const { return LLUI::getUIImage(ICON_NAME[OBJECT_ICON_NAME]); @@ -881,7 +1076,7 @@ PermissionMask LLItemBridge::getPermissionMask() const } return perm_mask; } - + const std::string& LLItemBridge::getDisplayName() const { if(mDisplayName.empty()) @@ -903,8 +1098,33 @@ void LLItemBridge::buildDisplayName(LLInventoryItem* item, std::string& name) } } +LLFontGL::StyleFlags LLItemBridge::getLabelStyle() const +{ + U8 font = LLFontGL::NORMAL; + + if( gAgentWearables.isWearingItem( mUUID ) ) + { + // llinfos << "BOLD" << llendl; + font |= LLFontGL::BOLD; + } + + const LLViewerInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + font |= LLFontGL::ITALIC; + } + return (LLFontGL::StyleFlags)font; +} + std::string LLItemBridge::getLabelSuffix() const { + // String table is loaded before login screen and inventory items are + // loaded after login, so LLTrans should be ready. + static std::string NO_COPY =LLTrans::getString("no_copy"); + static std::string NO_MOD = LLTrans::getString("no_modify"); + static std::string NO_XFER = LLTrans::getString("no_transfer"); + static std::string LINK = LLTrans::getString("link"); + static std::string BROKEN_LINK = LLTrans::getString("broken_link"); std::string suffix; LLInventoryItem* item = getItem(); if(item) @@ -913,25 +1133,28 @@ std::string LLItemBridge::getLabelSuffix() const if(LLAssetType::AT_CALLINGCARD != item->getType() && item->getPermissions().getOwner() == gAgent.getID()) { + BOOL broken_link = LLAssetType::lookupIsLinkType(item->getType()); + if (broken_link) return BROKEN_LINK; + + BOOL link = item->getIsLinkType(); + if (link) return LINK; + BOOL copy = item->getPermissions().allowCopyBy(gAgent.getID()); + if (!copy) + { + suffix += NO_COPY; + } BOOL mod = item->getPermissions().allowModifyBy(gAgent.getID()); + if (!mod) + { + suffix += NO_MOD; + } BOOL xfer = item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()); - // *TODO: Translate - const char* EMPTY = ""; - const char* NO_COPY = " (no copy)"; - const char* NO_MOD = " (no modify)"; - const char* NO_XFER = " (no transfer)"; - const char* scopy; - if(copy) scopy = EMPTY; - else scopy = NO_COPY; - const char* smod; - if(mod) smod = EMPTY; - else smod = NO_MOD; - const char* sxfer; - if(xfer) sxfer = EMPTY; - else sxfer = NO_XFER; - suffix = llformat("%s%s%s",scopy,smod,sxfer); + if (!xfer) + { + suffix += NO_XFER; + } } } return suffix; @@ -953,6 +1176,12 @@ BOOL LLItemBridge::isItemRenameable() const LLViewerInventoryItem* item = getItem(); if(item) { + // (For now) Don't allow calling card rename since that may confuse users as to + // what the calling card points to. + if (item->getInventoryType() == LLInventoryType::IT_CALLINGCARD) + { + return FALSE; + } return (item->getPermissions().allowModifyBy(gAgent.getID())); } return FALSE; @@ -960,10 +1189,12 @@ BOOL LLItemBridge::isItemRenameable() const BOOL LLItemBridge::renameItem(const std::string& new_name) { - if(!isItemRenameable()) return FALSE; - LLPreview::rename(mUUID, getPrefix() + new_name); - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; + if(!isItemRenameable()) + return FALSE; + LLPreview::dirty(mUUID); + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; LLViewerInventoryItem* item = getItem(); if(item && (item->getName() != new_name)) { @@ -972,6 +1203,8 @@ BOOL LLItemBridge::renameItem(const std::string& new_name) buildDisplayName(new_item, mDisplayName); new_item->updateServer(FALSE); model->updateItem(new_item); + model->updateLinkedObjects(item->getUUID()); + model->notifyObservers(); } // return FALSE because we either notified observers (& therefore @@ -988,7 +1221,7 @@ BOOL LLItemBridge::removeItem() } // move it to the trash LLPreview::hide(mUUID, TRUE); - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); LLViewerInventoryItem* item = getItem(); @@ -1014,19 +1247,25 @@ BOOL LLItemBridge::isItemCopyable() const if (item) { // can't copy worn objects. DEV-15183 - LLVOAvatar *avatarp = gAgent.getAvatarObject(); + LLVOAvatarSelf *avatarp = gAgent.getAvatarObject(); if( !avatarp ) { return FALSE; } - if( avatarp->isWearingAttachment( mUUID ) ) + if( avatarp->isWearingAttachment( mUUID, TRUE ) ) { return FALSE; } - - - return (item->getPermissions().allowCopyBy(gAgent.getID())); + + // All items can be copied, not all can be pasted. + // The only time an item can't be copied is if it's a link + // return (item->getPermissions().allowCopyBy(gAgent.getID())); + if (item->getIsLinkType()) + { + return FALSE; + } + return TRUE; } return FALSE; } @@ -1043,7 +1282,7 @@ BOOL LLItemBridge::copyToClipboard() const LLViewerInventoryItem* LLItemBridge::getItem() const { LLViewerInventoryItem* item = NULL; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(model) { item = (LLViewerInventoryItem*)model->getItem(mUUID); @@ -1077,7 +1316,7 @@ BOOL LLFolderBridge::isItemMovable() LLInventoryObject* obj = getInventoryObject(); if(obj) { - return (LLAssetType::AT_NONE == ((LLInventoryCategory*)obj)->getPreferredType()); + return (!LLAssetType::lookupIsProtectedCategoryType(((LLInventoryCategory*)obj)->getPreferredType())); } return FALSE; } @@ -1090,18 +1329,18 @@ void LLFolderBridge::selectItem() // Can be destroyed (or moved to trash) BOOL LLFolderBridge::isItemRemovable() { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) { return FALSE; } - if(!model->isObjectDescendentOf(mUUID, gAgent.getInventoryRootID())) + if(!model->isObjectDescendentOf(mUUID, gInventory.getRootFolderID())) { return FALSE; } - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( !avatar ) { return FALSE; @@ -1113,7 +1352,7 @@ BOOL LLFolderBridge::isItemRemovable() return FALSE; } - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { return FALSE; } @@ -1126,7 +1365,7 @@ BOOL LLFolderBridge::isItemRemovable() for( i = 0; i < descendent_categories.count(); i++ ) { LLInventoryCategory* category = descendent_categories[i]; - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { return FALSE; } @@ -1138,7 +1377,7 @@ BOOL LLFolderBridge::isItemRemovable() if( (item->getType() == LLAssetType::AT_CLOTHING) || (item->getType() == LLAssetType::AT_BODYPART) ) { - if( gAgent.isWearingItem( item->getUUID() ) ) + if( gAgentWearables.isWearingItem( item->getUUID(), TRUE ) ) { return FALSE; } @@ -1146,7 +1385,7 @@ BOOL LLFolderBridge::isItemRemovable() else if( item->getType() == LLAssetType::AT_OBJECT ) { - if( avatar->isWearingAttachment( item->getUUID() ) ) + if( avatar->isWearingAttachment( item->getUUID(), TRUE ) ) { return FALSE; } @@ -1158,7 +1397,7 @@ BOOL LLFolderBridge::isItemRemovable() BOOL LLFolderBridge::isUpToDate() const { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; LLViewerInventoryCategory* category = (LLViewerInventoryCategory*)model->getCategory(mUUID); if( !category ) @@ -1169,6 +1408,21 @@ BOOL LLFolderBridge::isUpToDate() const return category->getVersion() != LLViewerInventoryCategory::VERSION_UNKNOWN; } +BOOL LLFolderBridge::isItemCopyable() const +{ + return TRUE; +} + +BOOL LLFolderBridge::copyToClipboard() const +{ + if(isItemCopyable()) + { + LLInventoryClipboard::instance().add(mUUID); + return TRUE; + } + return FALSE; +} + BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, BOOL drop) { @@ -1176,10 +1430,10 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, // the UI will get confused and pass in a NULL. if(!inv_cat) return FALSE; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if(!avatar) return FALSE; // cannot drag into library @@ -1206,7 +1460,14 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); BOOL move_is_into_trash = (mUUID == trash_id) || model->isObjectDescendentOf(mUUID, trash_id); - BOOL is_movable = (LLAssetType::AT_NONE == inv_cat->getPreferredType()); + BOOL is_movable = (!LLAssetType::lookupIsProtectedCategoryType(inv_cat->getPreferredType())); + LLUUID current_outfit_id = model->findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); + BOOL move_is_into_current_outfit = (mUUID == current_outfit_id); + if (move_is_into_current_outfit) + { + // BAP - restrictions? + is_movable = true; + } if( is_movable ) { gInventory.collectDescendents( cat_id, descendent_categories, descendent_items, FALSE ); @@ -1214,7 +1475,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, for( i = 0; i < descendent_categories.count(); i++ ) { LLInventoryCategory* category = descendent_categories[i]; - if( LLAssetType::AT_NONE != category->getPreferredType() ) + if(LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())) { // ...can't move "special folders" like Textures is_movable = FALSE; @@ -1232,7 +1493,7 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, if( (item->getType() == LLAssetType::AT_CLOTHING) || (item->getType() == LLAssetType::AT_BODYPART) ) { - if( gAgent.isWearingItem( item->getUUID() ) ) + if( gAgentWearables.isWearingItem( item->getUUID() ) ) { is_movable = FALSE; // It's generally movable, but not into the trash! break; @@ -1266,20 +1527,34 @@ BOOL LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat, { LLInventoryItem* item = descendent_items[i]; if (item->getType() == LLAssetType::AT_GESTURE - && gGestureManager.isGestureActive(item->getUUID())) + && LLGestureManager::instance().isGestureActive(item->getUUID())) { - gGestureManager.deactivateGesture(item->getUUID()); + LLGestureManager::instance().deactivateGesture(item->getUUID()); } } } - // Reparent the folder and restamp children if it's moving - // into trash. - LLInvFVBridge::changeCategoryParent( - model, - (LLViewerInventoryCategory*)inv_cat, - mUUID, - move_is_into_trash); + if (current_outfit_id == mUUID) // if target is current outfit folder we use link + { + link_inventory_item( + gAgent.getID(), + inv_cat->getUUID(), + mUUID, + inv_cat->getName(), + LLAssetType::AT_LINK_FOLDER, + LLPointer(NULL)); + } + else + { + + // Reparent the folder and restamp children if it's moving + // into trash. + LLInvFVBridge::changeCategoryParent( + model, + (LLViewerInventoryCategory*)inv_cat, + mUUID, + move_is_into_trash); + } } } else if(LLToolDragAndDrop::SOURCE_WORLD == source) @@ -1393,22 +1668,13 @@ BOOL move_inv_category_world_to_agent(const LLUUID& object_id, else { LLNotification::Params params("MoveInventoryFromObject"); - params.functor(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); LLNotifications::instance().forceResponse(params, 0); } } return accept; } -class LLFindWearables : public LLInventoryCollectFunctor -{ -public: - LLFindWearables() {} - virtual ~LLFindWearables() {} - virtual bool operator()(LLInventoryCategory* cat, - LLInventoryItem* item); -}; - bool LLFindWearables::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { @@ -1606,65 +1872,94 @@ void LLFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model if ("open" == action) { openItem(); + return; } else if ("paste" == action) { pasteFromClipboard(); + return; + } + else if ("paste_link" == action) + { + pasteLinkFromClipboard(); + return; } else if ("properties" == action) { showProperties(); + return; } else if ("replaceoutfit" == action) { modifyOutfit(FALSE); + return; } else if ("addtooutfit" == action) { modifyOutfit(TRUE); + return; + } + else if ("copy" == action) + { + copyToClipboard(); + return; } else if ("removefromoutfit" == action) { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; remove_inventory_category_from_avatar ( cat ); + return; } else if ("purge" == action) { - LLViewerInventoryCategory* cat; - cat = (LLViewerInventoryCategory*)getCategory(); - - if(cat) - { - model->purgeDescendentsOf(mUUID); - } - LLInventoryObject* obj = model->getObject(mUUID); - if(!obj) return; - obj->removeFromServer(); - model->deleteObject(mUUID); - model->notifyObservers(); + purgeItem(model, mUUID); + return; } else if ("restore" == action) { restoreItem(); + return; } } void LLFolderBridge::openItem() { lldebugs << "LLFolderBridge::openItem()" << llendl; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; - model->fetchDescendentsOf(mUUID); + bool fetching_inventory = model->fetchDescendentsOf(mUUID); + // Only change folder type if we have the folder contents. + if (!fetching_inventory) + { + // Disabling this for now, it's causing crash when new items are added to folders + // since folder type may change before new item item has finished processing. + // determineFolderType(); + } +} + +void LLFolderBridge::closeItem() +{ + determineFolderType(); +} + +void LLFolderBridge::determineFolderType() +{ + if (isUpToDate()) + { + LLInventoryModel* model = getInventoryModel(); + LLViewerInventoryCategory* category = model->getCategory(mUUID); + category->determineFolderType(); + } } BOOL LLFolderBridge::isItemRenameable() const { LLViewerInventoryCategory* cat = (LLViewerInventoryCategory*)getCategory(); - if(cat && (cat->getPreferredType() == LLAssetType::AT_NONE) + if(cat && !LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType()) && (cat->getOwnerID() == gAgent.getID())) { return TRUE; @@ -1678,83 +1973,123 @@ void LLFolderBridge::restoreItem() cat = (LLViewerInventoryCategory*)getCategory(); if(cat) { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); LLUUID new_parent = model->findCategoryUUIDForType(cat->getType()); // do not restamp children on restore LLInvFVBridge::changeCategoryParent(model, cat, new_parent, FALSE); } } -// Icons for folders are based on the preferred type -LLUIImagePtr LLFolderBridge::getIcon() const +LLAssetType::EType LLFolderBridge::getPreferredType() const { - const char* control = NULL; LLAssetType::EType preferred_type = LLAssetType::AT_NONE; LLViewerInventoryCategory* cat = getCategory(); if(cat) { preferred_type = cat->getPreferredType(); } + + return preferred_type; +} + +// Icons for folders are based on the preferred type +LLUIImagePtr LLFolderBridge::getIcon() const +{ + LLAssetType::EType preferred_type = LLAssetType::AT_NONE; + LLViewerInventoryCategory* cat = getCategory(); + if(cat) + { + preferred_type = cat->getPreferredType(); + } + return getIcon(preferred_type); +} + +LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type) +{ + if (preferred_type >= LLAssetType::AT_FOLDER_ENSEMBLE_START && + preferred_type <= LLAssetType::AT_FOLDER_ENSEMBLE_END) + { + LLUIImage* icon = LLUI::getUIImage(LLFolderType::lookupIconName(preferred_type)); + if (icon) + return icon; + } + + const char* control = NULL; switch(preferred_type) { - case LLAssetType::AT_TEXTURE: - control = "inv_folder_texture.tga"; - break; - case LLAssetType::AT_SOUND: - control = "inv_folder_sound.tga"; - break; - case LLAssetType::AT_CALLINGCARD: - control = "inv_folder_callingcard.tga"; - break; - case LLAssetType::AT_LANDMARK: - control = "inv_folder_landmark.tga"; - break; - case LLAssetType::AT_SCRIPT: - case LLAssetType::AT_LSL_TEXT: - control = "inv_folder_script.tga"; - break; - case LLAssetType::AT_OBJECT: - control = "inv_folder_object.tga"; - break; - case LLAssetType::AT_NOTECARD: - control = "inv_folder_notecard.tga"; - break; - case LLAssetType::AT_CATEGORY: - control = "inv_folder_plain_closed.tga"; - break; - case LLAssetType::AT_CLOTHING: - control = "inv_folder_clothing.tga"; - break; - case LLAssetType::AT_BODYPART: - control = "inv_folder_bodypart.tga"; - break; - case LLAssetType::AT_TRASH: - control = "inv_folder_trash.tga"; - break; - case LLAssetType::AT_SNAPSHOT_CATEGORY: - control = "inv_folder_snapshot.tga"; - break; - case LLAssetType::AT_LOST_AND_FOUND: - control = "inv_folder_lostandfound.tga"; - break; - case LLAssetType::AT_ANIMATION: - control = "inv_folder_animation.tga"; - break; - case LLAssetType::AT_GESTURE: - control = "inv_folder_gesture.tga"; - break; - default: - control = "inv_folder_plain_closed.tga"; - break; + case LLAssetType::AT_TEXTURE: + control = "inv_folder_texture.tga"; + break; + case LLAssetType::AT_SOUND: + control = "inv_folder_sound.tga"; + break; + case LLAssetType::AT_CALLINGCARD: + control = "inv_folder_callingcard.tga"; + break; + case LLAssetType::AT_LANDMARK: + control = "inv_folder_landmark.tga"; + break; + case LLAssetType::AT_SCRIPT: + case LLAssetType::AT_LSL_TEXT: + control = "inv_folder_script.tga"; + break; + case LLAssetType::AT_OBJECT: + control = "inv_folder_object.tga"; + break; + case LLAssetType::AT_NOTECARD: + control = "inv_folder_notecard.tga"; + break; + case LLAssetType::AT_CATEGORY: + control = "inv_folder_plain_closed.tga"; + break; + case LLAssetType::AT_CLOTHING: + control = "inv_folder_clothing.tga"; + break; + case LLAssetType::AT_BODYPART: + control = "inv_folder_bodypart.tga"; + break; + case LLAssetType::AT_TRASH: + control = "inv_folder_trash.tga"; + break; + case LLAssetType::AT_SNAPSHOT_CATEGORY: + control = "inv_folder_snapshot.tga"; + break; + case LLAssetType::AT_LOST_AND_FOUND: + control = "inv_folder_lostandfound.tga"; + break; + case LLAssetType::AT_ANIMATION: + control = "inv_folder_animation.tga"; + break; + case LLAssetType::AT_GESTURE: + control = "inv_folder_gesture.tga"; + break; + case LLAssetType::AT_FAVORITE: + //TODO - need icon + control = "inv_folder_plain_closed.tga"; + break; + case LLAssetType::AT_OUTFIT: + control = "inv_folder_outfit.tga"; + break; + case LLAssetType::AT_CURRENT_OUTFIT: + control = "inv_folder_current_outfit.tga"; + break; + case LLAssetType::AT_MY_OUTFITS: + control = "inv_folder_my_outfits.tga"; + break; + default: + control = "inv_folder_plain_closed.tga"; + break; } return LLUI::getUIImage(control); } BOOL LLFolderBridge::renameItem(const std::string& new_name) { - if(!isItemRenameable()) return FALSE; - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; + if(!isItemRenameable()) + return FALSE; + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; LLViewerInventoryCategory* cat = getCategory(); if(cat && (cat->getName() != new_name)) { @@ -1762,6 +2097,8 @@ BOOL LLFolderBridge::renameItem(const std::string& new_name) new_cat->rename(new_name); new_cat->updateServer(FALSE); model->updateCategory(new_cat); + model->updateLinkedObjects(cat->getUUID()); + model->notifyObservers(); } // return FALSE because we either notified observers (& therefore @@ -1777,7 +2114,7 @@ BOOL LLFolderBridge::removeItem() } // move it to the trash LLPreview::hide(mUUID); - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; LLUUID trash_id; @@ -1793,9 +2130,9 @@ BOOL LLFolderBridge::removeItem() { LLInventoryItem* item = descendent_items[i]; if (item->getType() == LLAssetType::AT_GESTURE - && gGestureManager.isGestureActive(item->getUUID())) + && LLGestureManager::instance().isGestureActive(item->getUUID())) { - gGestureManager.deactivateGesture(item->getUUID()); + LLGestureManager::instance().deactivateGesture(item->getUUID()); } } @@ -1810,18 +2147,9 @@ BOOL LLFolderBridge::removeItem() return TRUE; } -BOOL LLFolderBridge::isClipboardPasteable() const -{ - if(LLInventoryClipboard::instance().hasContents() && isAgentInventory()) - { - return TRUE; - } - return FALSE; -} - void LLFolderBridge::pasteFromClipboard() { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(model && isClipboardPasteable()) { LLInventoryItem* item = NULL; @@ -1846,6 +2174,42 @@ void LLFolderBridge::pasteFromClipboard() } } +void LLFolderBridge::pasteLinkFromClipboard() +{ + LLInventoryModel* model = getInventoryModel(); + if(model) + { + LLDynamicArray objects; + LLInventoryClipboard::instance().retrieve(objects); + S32 count = objects.count(); + LLUUID parent_id(mUUID); + for(S32 i = 0; i < count; i++) + { + const LLUUID &object_id = objects.get(i); + if (LLInventoryCategory *cat = model->getCategory(object_id)) + { + link_inventory_item( + gAgent.getID(), + cat->getUUID(), + parent_id, + cat->getName(), + LLAssetType::AT_LINK_FOLDER, + LLPointer(NULL)); + } + else if (LLInventoryItem *item = model->getItem(object_id)) + { + link_inventory_item( + gAgent.getID(), + item->getUUID(), + parent_id, + item->getName(), + LLAssetType::AT_LINK, + LLPointer(NULL)); + } + } + } +} + void LLFolderBridge::staticFolderOptionsMenu() { if (!sSelf) return; @@ -1856,14 +2220,12 @@ void LLFolderBridge::folderOptionsMenu() { std::vector disabled_items; - // *TODO: Translate - - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; const LLInventoryCategory* category = model->getCategory(mUUID); bool is_default_folder = category && - (LLAssetType::AT_NONE != category->getPreferredType()); + (LLAssetType::lookupIsProtectedCategoryType(category->getPreferredType())); // calling card related functionality for folders. @@ -1900,6 +2262,10 @@ void LLFolderBridge::folderOptionsMenu() } mItems.push_back(std::string("Take Off Items")); } + if (LLAssetType::AT_CURRENT_OUTFIT == category->getPreferredType()) + { + mItems.push_back(std::string("Replace Outfit")); + } hideContextEntries(*mMenu, mItems, disabled_items); } @@ -1918,10 +2284,12 @@ BOOL LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInv // Flags unused void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate + mItems.clear(); + mDisabledItems.clear(); + lldebugs << "LLFolderBridge::buildContextMenu()" << llendl; // std::vector disabled_items; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; LLUUID trash_id = model->findCategoryUUIDForType(LLAssetType::AT_TRASH); LLUUID lost_and_found_id = model->findCategoryUUIDForType(LLAssetType::AT_LOST_AND_FOUND); @@ -1951,38 +2319,23 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else if(isAgentInventory()) // do not allow creating in library { - // only mature accounts can create undershirts/underwear - /*if (!gAgent.isTeen()) - { - sub_menu->append(new LLMenuItemCallGL("New Undershirt", - &createNewUndershirt, - NULL, - (void*)this)); - sub_menu->append(new LLMenuItemCallGL("New Underpants", - &createNewUnderpants, - NULL, - (void*)this)); - }*/ + LLViewerInventoryCategory *cat = getCategory(); -/* BOOL contains_calling_cards = FALSE; - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - model->collectDescendentsIf(mUUID, - cat_array, - item_array, - LLInventoryModel::EXCLUDE_TRASH, - is_callingcard); - if(item_array.count() > 0) contains_calling_cards = TRUE; -*/ - mItems.push_back(std::string("New Folder")); + // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. + if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) + mItems.push_back(std::string("New Folder")); mItems.push_back(std::string("New Script")); mItems.push_back(std::string("New Note")); mItems.push_back(std::string("New Gesture")); mItems.push_back(std::string("New Clothes")); mItems.push_back(std::string("New Body Parts")); + mItems.push_back(std::string("Change Type")); + if (cat && LLAssetType::lookupIsProtectedCategoryType(cat->getPreferredType())) + { + mDisabledItems.push_back(std::string("Change Type")); + } + getClipboardEntries(false, mItems, mDisabledItems, flags); //Added by spatters to force inventory pull on right-click to display folder options correctly. 07-17-06 @@ -2036,7 +2389,7 @@ void LLFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) BOOL LLFolderBridge::hasChildren() const { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; LLInventoryModel::EHasChildren has_children; has_children = gInventory.categoryHasChildren(mUUID); @@ -2051,26 +2404,27 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, BOOL accept = FALSE; switch(cargo_type) { - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_CALLINGCARD: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_CLOTHING: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, - drop); - break; - case DAD_CATEGORY: - accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_CALLINGCARD: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_CLOTHING: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: + case DAD_LINK: + accept = dragItemIntoFolder((LLInventoryItem*)cargo_data, drop); - break; - default: - break; + break; + case DAD_CATEGORY: + accept = dragCategoryIntoFolder((LLInventoryCategory*)cargo_data, + drop); + break; + default: + break; } return accept; } @@ -2078,7 +2432,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop, LLViewerInventoryCategory* LLFolderBridge::getCategory() const { LLViewerInventoryCategory* cat = NULL; - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(model) { cat = (LLViewerInventoryCategory*)model->getCategory(mUUID); @@ -2098,7 +2452,8 @@ void LLFolderBridge::createNewCategory(void* user_data) { LLFolderBridge* bridge = (LLFolderBridge*)user_data; if(!bridge) return; - LLInventoryPanel* panel = bridge->mInventoryPanel; + LLInventoryPanel* panel = dynamic_cast(bridge->mInventoryPanel.get()); + if (!panel) return; LLInventoryModel* model = panel->getModel(); if(!model) return; LLUUID id; @@ -2190,7 +2545,7 @@ void LLFolderBridge::createWearable(LLFolderBridge* bridge, EWearableType type) // static void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type) { - LLWearable* wearable = gWearableList.createNewWearable(type); + LLWearable* wearable = LLWearableList::instance().createNewWearable(type); LLAssetType::EType asset_type = wearable->getAssetType(); LLInventoryType::EType inv_type = LLInventoryType::IT_WEARABLE; create_inventory_item(gAgent.getID(), gAgent.getSessionID(), @@ -2202,12 +2557,14 @@ void LLFolderBridge::createWearable(LLUUID parent_id, EWearableType type) void LLFolderBridge::modifyOutfit(BOOL append) { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return; LLViewerInventoryCategory* cat = getCategory(); if(!cat) return; - wear_inventory_category_on_avatar( cat, append ); + // BAP - was: + // wear_inventory_category_on_avatar( cat, append ); + wear_inventory_category( cat, FALSE, append ); } // helper stuff @@ -2253,7 +2610,7 @@ bool move_task_inventory_callback(const LLSD& notification, const LLSD& response BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, BOOL drop) { - LLInventoryModel* model = mInventoryPanel->getModel(); + LLInventoryModel* model = getInventoryModel(); if(!model) return FALSE; // cannot drag into library @@ -2262,7 +2619,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, return FALSE; } - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if(!avatar) return FALSE; LLToolDragAndDrop::ESource source = LLToolDragAndDrop::getInstance()->getSource(); @@ -2272,14 +2629,14 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { BOOL is_movable = TRUE; - switch( inv_item->getType() ) + switch( inv_item->getActualType() ) { case LLAssetType::AT_ROOT_CATEGORY: is_movable = FALSE; break; case LLAssetType::AT_CATEGORY: - is_movable = ( LLAssetType::AT_NONE == ((LLInventoryCategory*)inv_item)->getPreferredType() ); + is_movable = !LLAssetType::lookupIsProtectedCategoryType(((LLInventoryCategory*)inv_item)->getPreferredType()); break; default: break; @@ -2293,11 +2650,11 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, { case LLAssetType::AT_CLOTHING: case LLAssetType::AT_BODYPART: - is_movable = !gAgent.isWearingItem(inv_item->getUUID()); + is_movable = !gAgentWearables.isWearingItem(inv_item->getUUID(), TRUE); break; case LLAssetType::AT_OBJECT: - is_movable = !avatar->isWearingAttachment(inv_item->getUUID()); + is_movable = !avatar->isWearingAttachment(inv_item->getUUID(), TRUE); break; default: break; @@ -2308,29 +2665,44 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, if(accept && drop) { if (inv_item->getType() == LLAssetType::AT_GESTURE - && gGestureManager.isGestureActive(inv_item->getUUID()) && move_is_into_trash) + && LLGestureManager::instance().isGestureActive(inv_item->getUUID()) && move_is_into_trash) { - gGestureManager.deactivateGesture(inv_item->getUUID()); + LLGestureManager::instance().deactivateGesture(inv_item->getUUID()); } // If an item is being dragged between windows, unselect // everything in the active window so that we don't follow // the selection to its new location (which is very // annoying). - if (LLInventoryView::getActiveInventory()) + if (LLFloaterInventory::getActiveInventory()) { - LLInventoryPanel* active_panel = LLInventoryView::getActiveInventory()->getPanel(); - if (active_panel && (mInventoryPanel != active_panel)) + LLInventoryPanel* active_panel = LLFloaterInventory::getActiveInventory()->getPanel(); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + if (active_panel && (panel != active_panel)) { active_panel->unSelectAll(); } } - // restamp if the move is into the trash. - LLInvFVBridge::changeItemParent( - model, - (LLViewerInventoryItem*)inv_item, - mUUID, - move_is_into_trash); + LLUUID favorites_id = model->findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + if (favorites_id == mUUID) // if target is the favorites folder we use copy + { + copy_inventory_item( + gAgent.getID(), + inv_item->getPermissions().getOwner(), + inv_item->getUUID(), + mUUID, + std::string(), + LLPointer(NULL)); + } + else + { + // restamp if the move is into the trash. + LLInvFVBridge::changeItemParent( + model, + (LLViewerInventoryItem*)inv_item, + mUUID, + move_is_into_trash); + } } } else if(LLToolDragAndDrop::SOURCE_WORLD == source) @@ -2379,7 +2751,7 @@ BOOL LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item, else { LLNotification::Params params("MoveInventoryFromObject"); - params.functor(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); + params.functor.function(boost::bind(move_task_inventory_callback, _1, _2, move_inv)); LLNotifications::instance().forceResponse(params, 0); } } @@ -2432,49 +2804,18 @@ LLUIImagePtr LLScriptBridge::getIcon() const // | LLTextureBridge | // +=================================================+ -std::string LLTextureBridge::sPrefix("Texture: "); - - LLUIImagePtr LLTextureBridge::getIcon() const { return get_item_icon(LLAssetType::AT_TEXTURE, mInvType, 0, FALSE); } -void open_texture(const LLUUID& item_id, - const std::string& title, - BOOL show_keep_discard, - const LLUUID& source_id, - BOOL take_focus) -{ - // See if we can bring an exiting preview to the front - if( !LLPreview::show( item_id, take_focus ) ) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - - LLPreviewTexture* preview; - preview = new LLPreviewTexture("preview texture", - rect, - title, - item_id, - LLUUID::null, - show_keep_discard); - preview->setSourceID(source_id); - if(take_focus) preview->setFocus(TRUE); - - gFloaterView->adjustToFitScreen(preview, FALSE); - } -} - void LLTextureBridge::openItem() { LLViewerInventoryItem* item = getItem(); - if(item) + + if (item) { - open_texture(mUUID, getPrefix() + item->getName(), FALSE); + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } } @@ -2482,9 +2823,6 @@ void LLTextureBridge::openItem() // | LLSoundBridge | // +=================================================+ -std::string LLSoundBridge::sPrefix("Sound: "); - - LLUIImagePtr LLSoundBridge::getIcon() const { return get_item_icon(LLAssetType::AT_SOUND, LLInventoryType::IT_SOUND, 0, FALSE); @@ -2492,6 +2830,13 @@ LLUIImagePtr LLSoundBridge::getIcon() const void LLSoundBridge::openItem() { + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* // Changed this back to the way it USED to work: // only open the preview dialog through the contextual right-click menu // double-click just plays the sound @@ -2502,18 +2847,7 @@ void LLSoundBridge::openItem() openSoundPreview((void*)this); //send_uuid_sound_trigger(item->getAssetUUID(), 1.0); } - -// if(!LLPreview::show(mUUID)) -// { -// S32 left, top; -// gFloaterView->getNewFloaterPosition(&left, &top); -// LLRect rect = gSavedSettings.getRect("PreviewSoundRect"); -// rect.translate(left - rect.mLeft, top - rect.mTop); -// new LLPreviewSound("preview sound", -// rect, -// getPrefix() + getName(), -// mUUID)); -// } +*/ } void LLSoundBridge::previewItem() @@ -2528,20 +2862,7 @@ void LLSoundBridge::previewItem() void LLSoundBridge::openSoundPreview(void* which) { LLSoundBridge *me = (LLSoundBridge *)which; - if(!LLPreview::show(me->mUUID)) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewSoundRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLPreviewSound* preview = new LLPreviewSound("preview sound", - rect, - me->getPrefix() + me->getName(), - me->mUUID); - preview->setFocus(TRUE); - // Keep entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - } + LLFloaterReg::showInstance("preview_sound", LLSD(me->mUUID), TAKE_FOCUS_YES); } void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) @@ -2550,7 +2871,6 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - // *TODO: Translate if(isInTrash()) { items.push_back(std::string("Purge Item")); @@ -2579,7 +2899,15 @@ void LLSoundBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // | LLLandmarkBridge | // +=================================================+ -std::string LLLandmarkBridge::sPrefix("Landmark: "); +LLLandmarkBridge::LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags/* = 0x00*/) : +LLItemBridge(inventory, uuid) +{ + mVisited = FALSE; + if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) + { + mVisited = TRUE; + } +} LLUIImagePtr LLLandmarkBridge::getIcon() const { @@ -2591,7 +2919,6 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) std::vector items; std::vector disabled_items; - // *TODO: Translate lldebugs << "LLLandmarkBridge::buildContextMenu()" << llendl; if(isInTrash()) { @@ -2618,6 +2945,20 @@ void LLLandmarkBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } +// Convenience function for the two functions below. +void teleport_via_landmark(const LLUUID& asset_id) +{ + gAgent.teleportViaLandmark( asset_id ); + + // we now automatically track the landmark you're teleporting to + // because you'll probably arrive at a telehub instead + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if( floater_world_map ) + { + floater_world_map->trackLandmark( asset_id ); + } +} + // virtual void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { @@ -2626,52 +2967,24 @@ void LLLandmarkBridge::performAction(LLFolderView* folder, LLInventoryModel* mod LLViewerInventoryItem* item = getItem(); if(item) { - gAgent.teleportViaLandmark(item->getAssetUUID()); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - if( gFloaterWorldMap ) - { - gFloaterWorldMap->trackLandmark( item->getAssetUUID() ); - } + teleport_via_landmark(item->getAssetUUID()); } } - if ("about" == action) + else if ("about" == action) { LLViewerInventoryItem* item = getItem(); if(item) { - open_landmark(item, std::string(" ") + getPrefix() + item->getName(), FALSE); + LLSD key; + key["type"] = "landmark"; + key["id"] = item->getUUID(); + + LLSideTray::getInstance()->showPanel("panel_places", key); } } - else LLItemBridge::performAction(folder, model, action); -} - -void open_landmark(LLViewerInventoryItem* inv_item, - const std::string& title, - BOOL show_keep_discard, - const LLUUID& source_id, - BOOL take_focus) -{ - // See if we can bring an exiting preview to the front - if( !LLPreview::show( inv_item->getUUID(), take_focus ) ) + else { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewLandmarkRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - - LLPreviewLandmark* preview = new LLPreviewLandmark(title, - rect, - title, - inv_item->getUUID(), - show_keep_discard, - inv_item); - preview->setSourceID(source_id); - if(take_focus) preview->setFocus(TRUE); - // keep onscreen - gFloaterView->adjustToFitScreen(preview, FALSE); + LLItemBridge::performAction(folder, model, action); } } @@ -2682,15 +2995,7 @@ static bool open_landmark_callback(const LLSD& notification, const LLSD& respons LLUUID asset_id = notification["payload"]["asset_id"].asUUID(); if (option == 0) { - // HACK: This is to demonstrate teleport on double click for landmarks - gAgent.teleportViaLandmark( asset_id ); - - // we now automatically track the landmark you're teleporting to - // because you'll probably arrive at a telehub instead - if( gFloaterWorldMap ) - { - gFloaterWorldMap->trackLandmark( asset_id ); - } + teleport_via_landmark(asset_id); } return false; @@ -2701,15 +3006,23 @@ static LLNotificationFunctorRegistration open_landmark_callback_reg("TeleportFro void LLLandmarkBridge::openItem() { LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); if( item ) { // Opening (double-clicking) a landmark immediately teleports, // but warns you the first time. - // open_landmark(item, std::string(" ") + getPrefix() + item->getName(), FALSE); + // open_landmark(item); LLSD payload; payload["asset_id"] = item->getAssetUUID(); LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); } +*/ } @@ -2725,8 +3038,6 @@ void LLCallingCardObserver::changed(U32 mask) // | LLCallingCardBridge | // +=================================================+ -std::string LLCallingCardBridge::sPrefix("Calling Card: "); - LLCallingCardBridge::LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) : LLItemBridge(inventory, uuid) { @@ -2742,7 +3053,8 @@ LLCallingCardBridge::~LLCallingCardBridge() void LLCallingCardBridge::refreshFolderViewItem() { - LLFolderViewItem* itemp = mInventoryPanel->getRootFolder()->getItemByID(mUUID); + LLInventoryPanel* panel = dynamic_cast(mInventoryPanel.get()); + LLFolderViewItem* itemp = panel ? panel->getRootFolder()->getItemByID(mUUID) : NULL; if (itemp) { itemp->refresh(); @@ -2758,8 +3070,9 @@ void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* if (item && (item->getCreatorUUID() != gAgent.getID()) && (!item->getCreatorUUID().isNull())) { - gIMMgr->setFloaterOpen(TRUE); - gIMMgr->addSession(item->getName(), IM_NOTHING_SPECIAL, item->getCreatorUUID()); + std::string callingcard_name; + gCacheName->getFullName(item->getCreatorUUID(), callingcard_name); + gIMMgr->addSession(callingcard_name, IM_NOTHING_SPECIAL, item->getCreatorUUID()); } } else if ("lure" == action) @@ -2768,7 +3081,7 @@ void LLCallingCardBridge::performAction(LLFolderView* folder, LLInventoryModel* if (item && (item->getCreatorUUID() != gAgent.getID()) && (!item->getCreatorUUID().isNull())) { - handle_lure(item->getCreatorUUID()); + LLAvatarActions::offerTeleport(item->getCreatorUUID()); } } else LLItemBridge::performAction(folder, model, action); @@ -2801,17 +3114,22 @@ std::string LLCallingCardBridge::getLabelSuffix() const void LLCallingCardBridge::openItem() { LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } +/* + LLViewerInventoryItem* item = getItem(); if(item && !item->getCreatorUUID().isNull()) { - BOOL online; - online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); - LLFloaterAvatarInfo::showFromFriend(item->getCreatorUUID(), online); + LLAvatarActions::showProfile(item->getCreatorUUID()); } +*/ } void LLCallingCardBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate lldebugs << "LLCallingCardBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; @@ -2928,72 +3246,43 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop, return rv; } +BOOL LLCallingCardBridge::removeItem() +{ + if (LLFriendCardsManager::instance().isItemInAnyFriendsList(getItem())) + { + LLAvatarActions::removeFriendDialog(getItem()->getCreatorUUID()); + return FALSE; + } + else + { + return LLItemBridge::removeItem(); + } +} // +=================================================+ // | LLNotecardBridge | // +=================================================+ -std::string LLNotecardBridge::sPrefix("Note: "); - - LLUIImagePtr LLNotecardBridge::getIcon() const { return get_item_icon(LLAssetType::AT_NOTECARD, LLInventoryType::IT_NOTECARD, 0, FALSE); } -void open_notecard(LLViewerInventoryItem* inv_item, - const std::string& title, - const LLUUID& object_id, - BOOL show_keep_discard, - const LLUUID& source_id, - BOOL take_focus) -{ - // See if we can bring an existing preview to the front - if(!LLPreview::show(inv_item->getUUID(), take_focus)) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("NotecardEditorRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLPreviewNotecard* preview; - preview = new LLPreviewNotecard("preview notecard", rect, title, - inv_item->getUUID(), object_id, inv_item->getAssetUUID(), - show_keep_discard, inv_item); - preview->setSourceID(source_id); - if(take_focus) preview->setFocus(TRUE); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - - //if (source_id.notNull()) - //{ - // // look for existing tabbed view for content from same source - // LLPreview* existing_preview = LLPreview::getPreviewForSource(source_id); - // if (existing_preview) - // { - // // found existing preview from this source - // // is it already hosted in a multi-preview window? - // LLMultiPreview* preview_hostp = (LLMultiPreview*)existing_preview->getHost(); - // if (!preview_hostp) - // { - // // create new multipreview if it doesn't exist - // LLMultiPreview* preview_hostp = new LLMultiPreview(existing_preview->getRect()); - // preview_hostp->addFloater(existing_preview); - // } - // // add this preview to existing host - // preview_hostp->addFloater(preview); - // } - //} - } -} - - void LLNotecardBridge::openItem() { LLViewerInventoryItem* item = getItem(); + if (item) { - open_notecard(item, getPrefix() + item->getName(), LLUUID::null, FALSE); + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } + +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); + } +*/ } @@ -3001,8 +3290,6 @@ void LLNotecardBridge::openItem() // | LLGestureBridge | // +=================================================+ -std::string LLGestureBridge::sPrefix("Gesture: "); - LLUIImagePtr LLGestureBridge::getIcon() const { return get_item_icon(LLAssetType::AT_GESTURE, LLInventoryType::IT_GESTURE, 0, FALSE); @@ -3010,7 +3297,7 @@ LLUIImagePtr LLGestureBridge::getIcon() const LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const { - if( gGestureManager.isGestureActive(mUUID) ) + if( LLGestureManager::instance().isGestureActive(mUUID) ) { return LLFontGL::BOLD; } @@ -3022,7 +3309,7 @@ LLFontGL::StyleFlags LLGestureBridge::getLabelStyle() const std::string LLGestureBridge::getLabelSuffix() const { - if( gGestureManager.isGestureActive(mUUID) ) + if( LLGestureManager::instance().isGestureActive(mUUID) ) { return LLItemBridge::getLabelSuffix() + " (active)"; } @@ -3037,7 +3324,7 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode { if ("activate" == action) { - gGestureManager.activateGesture(mUUID); + LLGestureManager::instance().activateGesture(mUUID); LLViewerInventoryItem* item = gInventory.getItem(mUUID); if (!item) return; @@ -3049,7 +3336,7 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode } else if ("deactivate" == action) { - gGestureManager.deactivateGesture(mUUID); + LLGestureManager::instance().deactivateGesture(mUUID); LLViewerInventoryItem* item = gInventory.getItem(mUUID); if (!item) return; @@ -3065,34 +3352,30 @@ void LLGestureBridge::performAction(LLFolderView* folder, LLInventoryModel* mode void LLGestureBridge::openItem() { LLViewerInventoryItem* item = getItem(); - if (!item) return; - - // See if we can bring an existing preview to the front - if(!LLPreview::show(mUUID)) + + if (item) { - LLUUID item_id = mUUID; - std::string title = getPrefix() + item->getName(); - LLUUID object_id = LLUUID::null; - - // TODO: save the rectangle - LLPreviewGesture* preview = LLPreviewGesture::show(title, item_id, object_id); - preview->setFocus(TRUE); - - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); + preview->setFocus(TRUE); + } +*/ } BOOL LLGestureBridge::removeItem() { // Force close the preview window, if it exists - gGestureManager.deactivateGesture(mUUID); + LLGestureManager::instance().deactivateGesture(mUUID); return LLItemBridge::removeItem(); } void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate lldebugs << "LLGestureBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; @@ -3116,15 +3399,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Gesture Separator")); items.push_back(std::string("Activate")); items.push_back(std::string("Deactivate")); - - /*menu.append(new LLMenuItemCallGL("Activate", - handleActivateGesture, - enableActivateGesture, - (void*)this)); - menu.append(new LLMenuItemCallGL("Deactivate", - handleDeactivateGesture, - enableDeactivateGesture, - (void*)this));*/ } hideContextEntries(menu, items, disabled_items); } @@ -3133,9 +3407,6 @@ void LLGestureBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // | LLAnimationBridge | // +=================================================+ -std::string LLAnimationBridge::sPrefix("Animation: "); - - LLUIImagePtr LLAnimationBridge::getIcon() const { return get_item_icon(LLAssetType::AT_ANIMATION, LLInventoryType::IT_ANIMATION, 0, FALSE); @@ -3143,7 +3414,6 @@ LLUIImagePtr LLAnimationBridge::getIcon() const void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate std::vector items; std::vector disabled_items; @@ -3177,32 +3447,18 @@ void LLAnimationBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // virtual void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) { - S32 activate = 0; - if ((action == "playworld") || (action == "playlocal")) { - - if ("playworld" == action) activate = 1; - if ("playlocal" == action) activate = 2; - - // See if we can bring an existing preview to the front - if( !LLPreview::show( mUUID ) ) + if (getItem()) { - // There isn't one, so make a new preview - LLViewerInventoryItem* item = getItem(); - if( item ) + LLPreviewAnim::e_activation_type activate = LLPreviewAnim::NONE; + if ("playworld" == action) activate = LLPreviewAnim::PLAY; + if ("playlocal" == action) activate = LLPreviewAnim::AUDITION; + + LLPreviewAnim* preview = LLFloaterReg::showTypedInstance("preview_anim", LLSD(mUUID)); + if (preview) { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewAnimRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - LLPreviewAnim* preview = new LLPreviewAnim("preview anim", - rect, - getPrefix() + item->getName(), - mUUID, - activate); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); + preview->activate(activate); } } } @@ -3214,44 +3470,41 @@ void LLAnimationBridge::performAction(LLFolderView* folder, LLInventoryModel* mo void LLAnimationBridge::openItem() { - // See if we can bring an existing preview to the front - if( !LLPreview::show( mUUID ) ) + LLViewerInventoryItem* item = getItem(); + + if (item) { - // There isn't one, so make a new preview - LLViewerInventoryItem* item = getItem(); - if( item ) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewAnimRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - LLPreviewAnim* preview = new LLPreviewAnim("preview anim", - rect, - getPrefix() + item->getName(), - mUUID, - 0); - preview->setFocus(TRUE); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - } + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } +/* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); + } +*/ } // +=================================================+ // | LLObjectBridge | // +=================================================+ -// static -std::string LLObjectBridge::sPrefix("Object: "); - // static LLUUID LLObjectBridge::sContextMenuItemID; +LLObjectBridge::LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : +LLItemBridge(inventory, uuid), mInvType(type) +{ + mAttachPt = (flags & 0xff); // low bye of inventory flags + + mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; +} + BOOL LLObjectBridge::isItemRemovable() { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if(!avatar) return FALSE; - if(avatar->isWearingAttachment(mUUID)) return FALSE; + if(avatar->isWearingAttachment(mUUID, TRUE)) return FALSE; return LLInvFVBridge::isItemRemovable(); } @@ -3260,7 +3513,16 @@ LLUIImagePtr LLObjectBridge::getIcon() const return get_item_icon(LLAssetType::AT_OBJECT, mInvType, mAttachPt, mIsMultiObject ); } -void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); +LLInventoryObject* LLObjectBridge::getObject() const +{ + LLInventoryObject* object = NULL; + LLInventoryModel* model = getInventoryModel(); + if(model) + { + object = (LLInventoryObject*)model->getObject(mUUID); + } + return object; +} // virtual void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) @@ -3270,7 +3532,7 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model LLUUID object_id = mUUID; LLViewerInventoryItem* item; item = (LLViewerInventoryItem*)gInventory.getItem(object_id); - if(item && gInventory.isObjectDescendentOf(object_id, gAgent.getInventoryRootID())) + if(item && gInventory.isObjectDescendentOf(object_id, gInventory.getRootFolderID())) { rez_attachment(item, NULL); } @@ -3317,28 +3579,40 @@ void LLObjectBridge::performAction(LLFolderView* folder, LLInventoryModel* model void LLObjectBridge::openItem() { - /* Disabled -- this preview isn't useful. JC */ - // CP: actually, this code is required - made changes to match LLAnimationBridge::openItem() idiom - // The properties preview is useful, converting to show object properties. - DaveP - LLShowProps::showProperties(mUUID); + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + + /* + LLFloaterReg::showInstance("properties", mUUID); + */ } LLFontGL::StyleFlags LLObjectBridge::getLabelStyle() const { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + U8 font = LLFontGL::NORMAL; + + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( avatar && avatar->isWearingAttachment( mUUID ) ) { - return LLFontGL::BOLD; + font |= LLFontGL::BOLD; } - else + + LLInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) { - return LLFontGL::NORMAL; + font |= LLFontGL::ITALIC; } + + return (LLFontGL::StyleFlags)font; } std::string LLObjectBridge::getLabelSuffix() const { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( avatar && avatar->isWearingAttachment( mUUID ) ) { std::string attachment_point_name = avatar->getAttachedPointName(mUUID); @@ -3354,7 +3628,7 @@ std::string LLObjectBridge::getLabelSuffix() const void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment) { LLSD payload; - payload["item_id"] = item->getUUID(); + payload["item_id"] = item->getLinkedUUID(); // Wear the base object in case this is a link. S32 attach_pt = 0; if (gAgent.getAvatarObject() && attachment) @@ -3412,7 +3686,6 @@ static LLNotificationFunctorRegistration confirm_replace_attachment_rez_reg("Rep void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate std::vector items; std::vector disabled_items; if(isInTrash()) @@ -3427,16 +3700,21 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) } else { + LLInventoryItem* item = getItem(); + if (item && item->getIsLinkType()) + { + items.push_back(std::string("Goto Link")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); LLObjectBridge::sContextMenuItemID = mUUID; - LLInventoryItem* item = getItem(); if(item) { - LLVOAvatar *avatarp = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); if( !avatarp ) { return; @@ -3447,7 +3725,7 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Detach From Yourself")); } else - if( !isInTrash() ) + if( !isInTrash() && !isLinkedObjectInTrash() ) { items.push_back(std::string("Attach Separator")); items.push_back(std::string("Object Wear")); @@ -3456,38 +3734,39 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) // commented out for DEV-32347 //items.push_back(std::string("Restore to Last Position")); - LLMenuGL* attach_menu = menu.getChildMenuByName("Attach To", TRUE); - LLMenuGL* attach_hud_menu = menu.getChildMenuByName("Attach To HUD", TRUE); + LLMenuGL* attach_menu = menu.findChildMenuByName("Attach To", TRUE); + LLMenuGL* attach_hud_menu = menu.findChildMenuByName("Attach To HUD", TRUE); LLVOAvatar *avatarp = gAgent.getAvatarObject(); - if (attach_menu && (attach_menu->getChildCount() == 0) && - attach_hud_menu && (attach_hud_menu->getChildCount() == 0) && - avatarp) + if (attach_menu + && (attach_menu->getChildCount() == 0) + && attach_hud_menu + && (attach_hud_menu->getChildCount() == 0) + && avatarp) { for (LLVOAvatar::attachment_map_t::iterator iter = avatarp->mAttachmentPoints.begin(); iter != avatarp->mAttachmentPoints.end(); ) { LLVOAvatar::attachment_map_t::iterator curiter = iter++; LLViewerJointAttachment* attachment = curiter->second; - LLMenuItemCallGL *new_item; - if (attachment->getIsHUDAttachment()) + LLMenuItemCallGL::Params p; + std::string submenu_name = attachment->getName(); + if (LLTrans::getString(submenu_name) != "") { - attach_hud_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), - NULL, //&LLObjectBridge::attachToAvatar, - NULL, &attach_label, (void*)attachment)); + p.name = (" ")+LLTrans::getString(submenu_name)+" "; } else { - attach_menu->append(new_item = new LLMenuItemCallGL(attachment->getName(), - NULL, //&LLObjectBridge::attachToAvatar, - NULL, &attach_label, (void*)attachment)); - } - - LLSimpleListener* callback = mInventoryPanel->getListenerByName("Inventory.AttachObject"); - - if (callback) - { - new_item->addListener(callback, "on_click", LLSD(attachment->getName())); + p.name = submenu_name; } + LLSD cbparams; + cbparams["index"] = curiter->first; + cbparams["label"] = attachment->getName(); + p.on_click.function_name = "Inventory.AttachObject"; + p.on_click.parameter = LLSD(attachment->getName()); + p.on_enable.function_name = "Attachment.Label"; + p.on_enable.parameter = cbparams; + LLView* parent = attachment->getIsHUDAttachment() ? attach_hud_menu : attach_menu; + LLUICtrlFactory::create(p, parent); } } } @@ -3498,10 +3777,12 @@ void LLObjectBridge::buildContextMenu(LLMenuGL& menu, U32 flags) BOOL LLObjectBridge::renameItem(const std::string& new_name) { - if(!isItemRenameable()) return FALSE; - LLPreview::rename(mUUID, getPrefix() + new_name); - LLInventoryModel* model = mInventoryPanel->getModel(); - if(!model) return FALSE; + if(!isItemRenameable()) + return FALSE; + LLPreview::dirty(mUUID); + LLInventoryModel* model = getInventoryModel(); + if(!model) + return FALSE; LLViewerInventoryItem* item = getItem(); if(item && (item->getName() != new_name)) { @@ -3510,9 +3791,11 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) buildDisplayName(new_item, mDisplayName); new_item->updateServer(FALSE); model->updateItem(new_item); + model->updateLinkedObjects(item->getUUID()); + model->notifyObservers(); - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( avatar ) { LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() ); @@ -3534,8 +3817,6 @@ BOOL LLObjectBridge::renameItem(const std::string& new_name) // | LLLSLTextBridge | // +=================================================+ -std::string LLLSLTextBridge::sPrefix("Script: "); - LLUIImagePtr LLLSLTextBridge::getIcon() const { return get_item_icon(LLAssetType::AT_SCRIPT, LLInventoryType::IT_LSL, 0, FALSE); @@ -3543,27 +3824,19 @@ LLUIImagePtr LLLSLTextBridge::getIcon() const void LLLSLTextBridge::openItem() { - // See if we can bring an exiting preview to the front - if(!LLPreview::show(mUUID)) + LLViewerInventoryItem* item = getItem(); + + if (item) { - LLViewerInventoryItem* item = getItem(); - if (item) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewScriptRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - - LLPreviewLSL* preview = new LLPreviewLSL("preview lsl text", - rect, - getPrefix() + item->getName(), - mUUID); - preview->setFocus(TRUE); - // keep onscreen - gFloaterView->adjustToFitScreen(preview, FALSE); - } + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); } + /* + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); + } + */ } // +=================================================+ @@ -3578,7 +3851,7 @@ void wear_inventory_item_on_avatar( LLInventoryItem* item ) lldebugs << "wear_inventory_item_on_avatar( " << item->getName() << " )" << llendl; - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onWearOnAvatarArrived, @@ -3586,6 +3859,22 @@ void wear_inventory_item_on_avatar( LLInventoryItem* item ) } } +void wear_add_inventory_item_on_avatar( LLInventoryItem* item ) +{ + if(item) + { + lldebugs << "wear_add_inventory_item_on_avatar( " << item->getName() + << " )" << llendl; + + LLWearableList::instance().getAsset(item->getAssetUUID(), + item->getName(), + item->getType(), + LLWearableBridge::onWearAddOnAvatarArrived, + new LLUUID(item->getUUID())); + } +} + + struct LLFoundData { LLFoundData(const LLUUID& item_id, @@ -3715,7 +4004,7 @@ void LLOutfitObserver::done() } if(pid.isNull()) { - pid = gAgent.getInventoryRootID(); + pid = gInventory.getRootFolderID(); } LLUUID cat_id = gInventory.createNewCategory( @@ -3822,7 +4111,7 @@ void wear_outfit_by_name(const std::string& name) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; LLNameCategoryCollector has_name(name); - gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -3899,30 +4188,71 @@ void wear_inventory_category_on_avatar( LLInventoryCategory* category, BOOL appe lldebugs << "wear_inventory_category_on_avatar( " << category->getName() << " )" << llendl; - LLWearInfo* userdata = new LLWearInfo; - userdata->mAppend = append; - userdata->mCategoryID = category->getUUID(); - + BOOL follow_folder_links = (category->getPreferredType() == LLAssetType::AT_CURRENT_OUTFIT || category->getPreferredType() == LLAssetType::AT_OUTFIT ); if( gFloaterCustomize ) { - gFloaterCustomize->askToSaveIfDirty( - wear_inventory_category_on_avatar_step2, - userdata); + gFloaterCustomize->askToSaveIfDirty(boost::bind(wear_inventory_category_on_avatar_step2, _1, category->getUUID(), append, follow_folder_links)); } else { - wear_inventory_category_on_avatar_step2( - TRUE, - userdata ); + wear_inventory_category_on_avatar_step2(TRUE, category->getUUID(), append, follow_folder_links ); } } - -void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) +void removeDuplicateItems(LLInventoryModel::item_array_t& dst, const LLInventoryModel::item_array_t& src) { - LLWearInfo* wear_info = (LLWearInfo*)userdata; - if (!wear_info) return; + LLInventoryModel::item_array_t new_dst; + std::set mark_inventory; + std::set mark_asset; + S32 inventory_dups = 0; + S32 asset_dups = 0; + + for (LLInventoryModel::item_array_t::const_iterator src_pos = src.begin(); + src_pos != src.end(); + ++src_pos) + { + LLUUID src_item_id = (*src_pos)->getLinkedUUID(); + mark_inventory.insert(src_item_id); + LLUUID src_asset_id = (*src_pos)->getAssetUUID(); + mark_asset.insert(src_asset_id); + } + + for (LLInventoryModel::item_array_t::const_iterator dst_pos = dst.begin(); + dst_pos != dst.end(); + ++dst_pos) + { + LLUUID dst_item_id = (*dst_pos)->getLinkedUUID(); + + if (mark_inventory.find(dst_item_id) == mark_inventory.end()) + { + } + else + { + inventory_dups++; + } + + LLUUID dst_asset_id = (*dst_pos)->getAssetUUID(); + + if (mark_asset.find(dst_asset_id) == mark_asset.end()) + { + // Item is not already present in COF. + new_dst.put(*dst_pos); + mark_asset.insert(dst_item_id); + } + else + { + asset_dups++; + } + } + llinfos << "removeDups, original " << dst.count() << " final " << new_dst.count() + << " inventory dups " << inventory_dups << " asset_dups " << asset_dups << llendl; + + dst = new_dst; +} + +void wear_inventory_category_on_avatar_step2( BOOL proceed, LLUUID category, BOOL append, BOOL follow_folder_links ) +{ // Find all the wearables that are in the category's subtree. lldebugs << "wear_inventory_category_on_avatar_step2()" << llendl; if(proceed) @@ -3930,46 +4260,76 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; LLFindWearables is_wearable; - gInventory.collectDescendentsIf(wear_info->mCategoryID, + gInventory.collectDescendentsIf(category, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, - is_wearable); + is_wearable, + follow_folder_links); S32 i; S32 wearable_count = item_array.count(); LLInventoryModel::cat_array_t obj_cat_array; LLInventoryModel::item_array_t obj_item_array; LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(wear_info->mCategoryID, + gInventory.collectDescendentsIf(category, obj_cat_array, obj_item_array, LLInventoryModel::EXCLUDE_TRASH, - is_object); + is_object, + follow_folder_links); S32 obj_count = obj_item_array.count(); // Find all gestures in this folder LLInventoryModel::cat_array_t gest_cat_array; LLInventoryModel::item_array_t gest_item_array; LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(wear_info->mCategoryID, + gInventory.collectDescendentsIf(category, gest_cat_array, gest_item_array, LLInventoryModel::EXCLUDE_TRASH, - is_gesture); + is_gesture, + follow_folder_links); S32 gest_count = gest_item_array.count(); if( !wearable_count && !obj_count && !gest_count) { LLNotifications::instance().add("CouldNotPutOnOutfit"); - delete wear_info; return; } - + + const LLUUID ¤t_outfit_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_CURRENT_OUTFIT); // Processes that take time should show the busy cursor + inc_busy_count(); + + LLInventoryModel::cat_array_t co_cat_array; + LLInventoryModel::item_array_t co_item_array; + gInventory.collectDescendents(current_outfit_id, co_cat_array, co_item_array, + LLInventoryModel::EXCLUDE_TRASH); + if (append) + { + // Remove duplicates and update counts. + removeDuplicateItems(item_array,co_item_array); + wearable_count = item_array.count(); + + removeDuplicateItems(obj_item_array,co_item_array); + obj_count = obj_item_array.count(); + + removeDuplicateItems(gest_item_array,co_item_array); + gest_count = gest_item_array.count(); + } + + if (wearable_count > 0 || obj_count > 0) { - inc_busy_count(); + if (!append) + { + // Remove all current outfit folder links if we're now replacing the contents. + for (i = 0; i < co_item_array.count(); ++i) + { + gInventory.purgeObject(co_item_array.get(i)->getUUID()); + } + } } // Activate all gestures in this folder @@ -3977,11 +4337,11 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) { llinfos << "Activating " << gest_count << " gestures" << llendl; - gGestureManager.activateGestures(gest_item_array); + LLGestureManager::instance().activateGestures(gest_item_array); // Update the inventory item labels to reflect the fact // they are active. - LLViewerInventoryCategory* catp = gInventory.getCategory(wear_info->mCategoryID); + LLViewerInventoryCategory* catp = gInventory.getCategory(category); if (catp) { gInventory.updateCategory(catp); @@ -4009,23 +4369,29 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) } for(i = 0; i < wearable_count; ++i) { - gAddToOutfit = wear_info->mAppend; - + gAddToOutfit = append; found = found_container.get(i); - gWearableList.getAsset(found->mAssetID, - found->mName, - found->mAssetType, - wear_inventory_category_on_avatar_loop, - (void*)holder); + + // Populate the current outfit folder with links to the newly added wearables + std::string link_name = "WearableLink"; + link_inventory_item(gAgent.getID(), found->mItemID, current_outfit_id, link_name, + LLAssetType::AT_LINK, LLPointer(NULL)); + + // Fetch the wearables about to be worn. + LLWearableList::instance().getAsset(found->mAssetID, + found->mName, + found->mAssetType, + wear_inventory_category_on_avatar_loop, + (void*)holder); } } //If not appending and the folder doesn't contain only gestures, take off all attachments. - if (!wear_info->mAppend + if (!append && !(wearable_count == 0 && obj_count == 0 && gest_count > 0) ) { - LLAgent::userRemoveAllAttachments(NULL); + LLAgentWearables::userRemoveAllAttachments(NULL); } if( obj_count > 0 ) @@ -4063,12 +4429,12 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) msg->nextBlockFast(_PREHASH_HeaderData); msg->addUUIDFast(_PREHASH_CompoundMsgID, compound_msg_id ); msg->addU8Fast(_PREHASH_TotalObjects, obj_count ); - msg->addBOOLFast(_PREHASH_FirstDetachAll, !wear_info->mAppend ); + msg->addBOOLFast(_PREHASH_FirstDetachAll, !append ); } - LLInventoryItem* item = obj_item_array.get(i); + const LLInventoryItem* item = obj_item_array.get(i).get(); msg->nextBlockFast(_PREHASH_ObjectData ); - msg->addUUIDFast(_PREHASH_ItemID, item->getUUID() ); + msg->addUUIDFast(_PREHASH_ItemID, item->getLinkedUUID()); msg->addUUIDFast(_PREHASH_OwnerID, item->getPermissions().getOwner()); msg->addU8Fast(_PREHASH_AttachmentPt, 0 ); // Wear at the previous or default attachment point pack_permissions_slam(msg, item->getFlags(), item->getPermissions()); @@ -4080,12 +4446,28 @@ void wear_inventory_category_on_avatar_step2( BOOL proceed, void* userdata ) // End of message chunk msg->sendReliable( gAgent.getRegion()->getHost() ); } + + } + + for(i = 0; i < obj_count; ++i) + { + const std::string link_name = "AttachmentLink"; + const LLInventoryItem* item = obj_item_array.get(i).get(); + link_inventory_item(gAgent.getID(), item->getLinkedUUID(), current_outfit_id, link_name, + LLAssetType::AT_LINK, LLPointer(NULL)); } } } + + // In the particular case that we're switching to a different outfit, + // create a link to the folder that we wore. + LLViewerInventoryCategory* catp = gInventory.getCategory(category); + if (!append && catp && catp->getPreferredType() == LLAssetType::AT_OUTFIT) + { + link_inventory_item(gAgent.getID(), category, current_outfit_id, catp->getName(), + LLAssetType::AT_LINK_FOLDER, LLPointer(NULL)); + } } - delete wear_info; - wear_info = NULL; } void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data) @@ -4099,7 +4481,7 @@ void wear_inventory_category_on_avatar_loop(LLWearable* wearable, void* data) iter != holder->mFoundList.end(); ++iter) { LLFoundData* data = *iter; - if(wearable->getID() == data->mAssetID) + if(wearable->getAssetID() == data->mAssetID) { data->mWearable = wearable; break; @@ -4132,20 +4514,8 @@ void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, B { LLViewerInventoryItem* item; item = (LLViewerInventoryItem*)gInventory.getItem(data->mItemID); - if( item && (item->getAssetUUID() == wearable->getID()) ) + if( item && (item->getAssetUUID() == wearable->getAssetID()) ) { - //RN: after discussing with Brashears, I disabled this code - //Metadata should reside in the item, not the asset - //And this code does not handle failed asset uploads properly -// if(!wearable->isMatchedToInventoryItem(item )) -// { -// wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item ); -// // Now that we have an asset that matches the -// // item, update the item to point to the new -// // asset. -// item->setAssetUUID(wearable->getID()); -// item->updateAssetOnServer(); -// } items.put(item); wearables.put(wearable); } @@ -4156,7 +4526,7 @@ void wear_inventory_category_on_avatar_step3(LLWearableHoldingPattern* holder, B if(wearables.count() > 0) { - gAgent.setWearableOutfit(items, wearables, !append); + gAgentWearables.setWearableOutfit(items, wearables, !append); gInventory.notifyObservers(); } @@ -4172,36 +4542,29 @@ void remove_inventory_category_from_avatar( LLInventoryCategory* category ) << " )" << llendl; - LLUUID* uuid = new LLUUID(category->getUUID()); - if( gFloaterCustomize ) { gFloaterCustomize->askToSaveIfDirty( - remove_inventory_category_from_avatar_step2, - uuid); + boost::bind(remove_inventory_category_from_avatar_step2, _1, category->getUUID())); } else { - remove_inventory_category_from_avatar_step2( - TRUE, - uuid ); + remove_inventory_category_from_avatar_step2(TRUE, category->getUUID() ); } } -void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) +void remove_inventory_category_from_avatar_step2( BOOL proceed, LLUUID category_id) { // Find all the wearables that are in the category's subtree. - LLUUID* category_id = (LLUUID *)userdata; - lldebugs << "remove_inventory_category_from_avatar_step2()" << llendl; if(proceed) { LLInventoryModel::cat_array_t cat_array; LLInventoryModel::item_array_t item_array; LLFindWearables is_wearable; - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -4212,7 +4575,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLInventoryModel::cat_array_t obj_cat_array; LLInventoryModel::item_array_t obj_item_array; LLIsType is_object( LLAssetType::AT_OBJECT ); - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, obj_cat_array, obj_item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -4223,7 +4586,7 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) LLInventoryModel::cat_array_t gest_cat_array; LLInventoryModel::item_array_t gest_item_array; LLIsType is_gesture( LLAssetType::AT_GESTURE ); - gInventory.collectDescendentsIf(*category_id, + gInventory.collectDescendentsIf(category_id, gest_cat_array, gest_item_array, LLInventoryModel::EXCLUDE_TRASH, @@ -4234,9 +4597,9 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) { for(i = 0; i < wearable_count; ++i) { - if( gAgent.isWearingItem (item_array.get(i)->getUUID()) ) + if( gAgentWearables.isWearingItem (item_array.get(i)->getUUID()) ) { - gWearableList.getAsset(item_array.get(i)->getAssetUUID(), + LLWearableList::instance().getAsset(item_array.get(i)->getAssetUUID(), item_array.get(i)->getName(), item_array.get(i)->getType(), LLWearableBridge::onRemoveFromAvatarArrived, @@ -4275,9 +4638,9 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) { for(i = 0; i < gest_count; ++i) { - if ( gGestureManager.isGestureActive( gest_item_array.get(i)->getUUID()) ) + if ( LLGestureManager::instance().isGestureActive( gest_item_array.get(i)->getUUID()) ) { - gGestureManager.deactivateGesture( gest_item_array.get(i)->getUUID() ); + LLGestureManager::instance().deactivateGesture( gest_item_array.get(i)->getUUID() ); gInventory.updateItem( gest_item_array.get(i) ); gInventory.notifyObservers(); } @@ -4285,41 +4648,26 @@ void remove_inventory_category_from_avatar_step2( BOOL proceed, void* userdata) } } } - delete category_id; - category_id = NULL; } BOOL LLWearableBridge::renameItem(const std::string& new_name) { - if( gAgent.isWearingItem( mUUID ) ) + if( gAgentWearables.isWearingItem( mUUID ) ) { - gAgent.setWearableName( mUUID, new_name ); + gAgentWearables.setWearableName( mUUID, new_name ); } return LLItemBridge::renameItem(new_name); } BOOL LLWearableBridge::isItemRemovable() { - if(gAgent.isWearingItem(mUUID)) return FALSE; + if (gAgentWearables.isWearingItem(mUUID, TRUE)) return FALSE; return LLInvFVBridge::isItemRemovable(); } -LLFontGL::StyleFlags LLWearableBridge::getLabelStyle() const -{ - if( gAgent.isWearingItem( mUUID ) ) - { - // llinfos << "BOLD" << llendl; - return LLFontGL::BOLD; - } - else - { - return LLFontGL::NORMAL; - } -} - std::string LLWearableBridge::getLabelSuffix() const { - if( gAgent.isWearingItem( mUUID ) ) + if( gAgentWearables.isWearingItem( mUUID ) ) { return LLItemBridge::getLabelSuffix() + " (worn)"; } @@ -4341,6 +4689,10 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod { wearOnAvatar(); } + else if ("wear_add" == action) + { + wearAddOnAvatar(); + } else if ("edit" == action) { editOnAvatar(); @@ -4348,12 +4700,12 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod } else if ("take_off" == action) { - if(gAgent.isWearingItem(mUUID)) + if(gAgentWearables.isWearingItem(mUUID)) { LLViewerInventoryItem* item = getItem(); if (item) { - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), LLWearableBridge::onRemoveFromAvatarArrived, @@ -4366,13 +4718,20 @@ void LLWearableBridge::performAction(LLFolderView* folder, LLInventoryModel* mod void LLWearableBridge::openItem() { + LLViewerInventoryItem* item = getItem(); + + if (item) + { + LLInvFVBridgeAction::doAction(item->getType(),mUUID,getInventoryModel()); + } + /* if( isInTrash() ) { LLNotifications::instance().add("CannotWearTrash"); } else if(isAgentInventory()) { - if( !gAgent.isWearingItem( mUUID ) ) + if( !gAgentWearables.isWearingItem( mUUID ) ) { wearOnAvatar(); } @@ -4400,11 +4759,11 @@ void LLWearableBridge::openItem() LLNotifications::instance().add("CannotWearInfoNotComplete"); } } + */ } void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) { - // *TODO: Translate lldebugs << "LLWearableBridge::buildContextMenu()" << llendl; std::vector items; std::vector disabled_items; @@ -4434,6 +4793,11 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Open")); } + if (item && item->getIsLinkType()) + { + items.push_back(std::string("Goto Link")); + } + items.push_back(std::string("Properties")); getClipboardEntries(true, items, disabled_items, flags); @@ -4441,29 +4805,24 @@ void LLWearableBridge::buildContextMenu(LLMenuGL& menu, U32 flags) items.push_back(std::string("Wearable Separator")); items.push_back(std::string("Wearable Wear")); + items.push_back(std::string("Wearable Add")); items.push_back(std::string("Wearable Edit")); if ((flags & FIRST_SELECTED_ITEM) == 0) { disabled_items.push_back(std::string("Wearable Edit")); } - //menu.appendSeparator(); - //menu.append(new LLMenuItemCallGL("Wear", - // LLWearableBridge::onWearOnAvatar, - // LLWearableBridge::canWearOnAvatar, - // (void*)this)); - //menu.append(new LLMenuItemCallGL("Edit", - // LLWearableBridge::onEditOnAvatar, - // LLWearableBridge::canEditOnAvatar, - // (void*)this)); + // Don't allow items to be worn if their baseobj is in the trash. + if (isLinkedObjectInTrash()) + { + disabled_items.push_back(std::string("Wearable Wear")); + disabled_items.push_back(std::string("Wearable Add")); + disabled_items.push_back(std::string("Wearable Edit")); + } if( item && (item->getType() == LLAssetType::AT_CLOTHING) ) { items.push_back(std::string("Take Off")); - /*menu.append(new LLMenuItemCallGL("Take Off", - LLWearableBridge::onRemoveFromAvatar, - LLWearableBridge::canRemoveFromAvatar, - (void*)this));*/ } } hideContextEntries(menu, items, disabled_items); @@ -4480,7 +4839,7 @@ BOOL LLWearableBridge::canWearOnAvatar(void* user_data) LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); if(!item || !item->isComplete()) return FALSE; } - return (!gAgent.isWearingItem(self->mUUID)); + return (!gAgentWearables.isWearingItem(self->mUUID)); } // Called from menus @@ -4496,7 +4855,7 @@ void LLWearableBridge::wearOnAvatar() { // Don't wear anything until initial wearables are loaded, can // destroy clothing items. - if (!gAgent.areWearablesLoaded()) + if (!gAgentWearables.areWearablesLoaded()) { LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return; @@ -4523,6 +4882,37 @@ void LLWearableBridge::wearOnAvatar() } } +void LLWearableBridge::wearAddOnAvatar() +{ + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + + LLViewerInventoryItem* item = getItem(); + if(item) + { + if(!isAgentInventory()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else + { + wear_add_inventory_item_on_avatar(item); + } + } +} + // static void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userdata ) { @@ -4533,24 +4923,35 @@ void LLWearableBridge::onWearOnAvatarArrived( LLWearable* wearable, void* userda item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); if(item) { - if(item->getAssetUUID() == wearable->getID()) + if(item->getAssetUUID() == wearable->getAssetID()) { - //RN: after discussing with Brashears, I disabled this code - //Metadata should reside in the item, not the asset - //And this code does not handle failed asset uploads properly + gAgentWearables.setWearableItem(item, wearable); + gInventory.notifyObservers(); + //self->getFolderItem()->refreshFromRoot(); + } + else + { + llinfos << "By the time wearable asset arrived, its inv item already pointed to a different asset." << llendl; + } + } + } + delete item_id; +} -// if(!wearable->isMatchedToInventoryItem(item)) -// { -// LLWearable* new_wearable = gWearableList.createWearableMatchedToInventoryItem( wearable, item ); -// -// // Now that we have an asset that matches the -// // item, update the item to point to the new -// // asset. -// item->setAssetUUID(new_wearable->getID()); -// item->updateAssetOnServer(); -// wearable = new_wearable; -// } - gAgent.setWearable(item, wearable); +// static +void LLWearableBridge::onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ) +{ + LLUUID* item_id = (LLUUID*) userdata; + if(wearable) + { + LLViewerInventoryItem* item = NULL; + item = (LLViewerInventoryItem*)gInventory.getItem(*item_id); + if(item) + { + if(item->getAssetUUID() == wearable->getAssetID()) + { + bool do_append = true; + gAgentWearables.setWearableItem(item, wearable, do_append); gInventory.notifyObservers(); //self->getFolderItem()->refreshFromRoot(); } @@ -4569,7 +4970,7 @@ BOOL LLWearableBridge::canEditOnAvatar(void* user_data) LLWearableBridge* self = (LLWearableBridge*)user_data; if(!self) return FALSE; - return (gAgent.isWearingItem(self->mUUID)); + return (gAgentWearables.isWearingItem(self->mUUID)); } // static @@ -4584,11 +4985,12 @@ void LLWearableBridge::onEditOnAvatar(void* user_data) void LLWearableBridge::editOnAvatar() { - LLWearable* wearable = gAgent.getWearableFromWearableItem(mUUID); + const LLWearable* wearable = gAgentWearables.getWearableFromWearableItem(mUUID); if( wearable ) { // Set the tab to the right wearable. - LLFloaterCustomize::setCurrentWearableType( wearable->getType() ); + if (gFloaterCustomize) + gFloaterCustomize->setCurrentWearableType( wearable->getType() ); if( CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() ) { @@ -4604,7 +5006,7 @@ BOOL LLWearableBridge::canRemoveFromAvatar(void* user_data) LLWearableBridge* self = (LLWearableBridge*)user_data; if( self && (LLAssetType::AT_BODYPART != self->mAssetType) ) { - return gAgent.isWearingItem( self->mUUID ); + return gAgentWearables.isWearingItem( self->mUUID ); } return FALSE; } @@ -4614,12 +5016,12 @@ void LLWearableBridge::onRemoveFromAvatar(void* user_data) { LLWearableBridge* self = (LLWearableBridge*)user_data; if(!self) return; - if(gAgent.isWearingItem(self->mUUID)) + if(gAgentWearables.isWearingItem(self->mUUID)) { LLViewerInventoryItem* item = self->getItem(); if (item) { - gWearableList.getAsset(item->getAssetUUID(), + LLWearableList::instance().getAsset(item->getAssetUUID(), item->getName(), item->getType(), onRemoveFromAvatarArrived, @@ -4635,16 +5037,440 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable, LLUUID* item_id = (LLUUID*) userdata; if(wearable) { - if( gAgent.isWearingItem( *item_id ) ) + if( gAgentWearables.isWearingItem( *item_id ) ) { EWearableType type = wearable->getType(); if( !(type==WT_SHAPE || type==WT_SKIN || type==WT_HAIR || type==WT_EYES ) ) //&& //!((!gAgent.isTeen()) && ( type==WT_UNDERPANTS || type==WT_UNDERSHIRT )) ) { - gAgent.removeWearable( type ); + // MULTI_WEARABLE: FIXME HACK - always remove all + bool do_remove_all = false; + gAgentWearables.removeWearable( type, do_remove_all, 0 ); } } } delete item_id; } + +LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type, + const LLUUID& uuid,LLInventoryModel* model) +{ + LLInvFVBridgeAction* action = NULL; + switch(asset_type) + { + case LLAssetType::AT_TEXTURE: + action = new LLTextureBridgeAction(uuid,model); + break; + + case LLAssetType::AT_SOUND: + action = new LLSoundBridgeAction(uuid,model); + break; + + case LLAssetType::AT_LANDMARK: + action = new LLLandmarkBridgeAction(uuid,model); + break; + + case LLAssetType::AT_CALLINGCARD: + action = new LLCallingCardBridgeAction(uuid,model); + break; + + case LLAssetType::AT_OBJECT: + action = new LLObjectBridgeAction(uuid,model); + break; + + case LLAssetType::AT_NOTECARD: + action = new LLNotecardBridgeAction(uuid,model); + break; + + case LLAssetType::AT_ANIMATION: + action = new LLAnimationBridgeAction(uuid,model); + break; + + case LLAssetType::AT_GESTURE: + action = new LLGestureBridgeAction(uuid,model); + break; + + case LLAssetType::AT_LSL_TEXT: + action = new LLLSLTextBridgeAction(uuid,model); + break; + + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_BODYPART: + action = new LLWearableBridgeAction(uuid,model); + + break; + + default: + break; + } + return action; +} + +//static +void LLInvFVBridgeAction::doAction(LLAssetType::EType asset_type, + const LLUUID& uuid,LLInventoryModel* model) +{ + LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); + if(action) + { + action->doIt(); + delete action; + } +} + +//static +void LLInvFVBridgeAction::doAction(const LLUUID& uuid, LLInventoryModel* model) +{ + LLAssetType::EType asset_type = model->getItem(uuid)->getType(); + LLInvFVBridgeAction* action = createAction(asset_type,uuid,model); + if(action) + { + action->doIt(); + delete action; + } +} + +LLViewerInventoryItem* LLInvFVBridgeAction::getItem() const +{ + if(mModel) + return (LLViewerInventoryItem*)mModel->getItem(mUUID); + return NULL; +} + +//virtual +void LLTextureBridgeAction::doIt() +{ + if (getItem()) + { + LLFloaterReg::showInstance("preview_texture", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLSoundBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if(item) + { + LLFloaterReg::showInstance("preview_sound", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLLandmarkBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if( item ) + { + // Opening (double-clicking) a landmark immediately teleports, + // but warns you the first time. + LLSD payload; + payload["asset_id"] = item->getAssetUUID(); + LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLCallingCardBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if(item && item->getCreatorUUID().notNull()) + { + LLAvatarActions::showProfile(item->getCreatorUUID()); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void +LLNotecardBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLGestureBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLPreviewGesture* preview = LLPreviewGesture::show(mUUID, LLUUID::null); + preview->setFocus(TRUE); + } + + LLInvFVBridgeAction::doIt(); +} + +//virtual +void LLAnimationBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_anim", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLObjectBridgeAction::doIt() +{ + LLFloaterReg::showInstance("properties", mUUID); + + LLInvFVBridgeAction::doIt(); +} + + +//virtual +void LLLSLTextBridgeAction::doIt() +{ + LLViewerInventoryItem* item = getItem(); + if (item) + { + LLFloaterReg::showInstance("preview_script", LLSD(mUUID), TAKE_FOCUS_YES); + } + + LLInvFVBridgeAction::doIt(); +} + + +BOOL LLWearableBridgeAction::isInTrash() const +{ + if(!mModel) return FALSE; + LLUUID trash_id = mModel->findCategoryUUIDForType(LLAssetType::AT_TRASH); + return mModel->isObjectDescendentOf(mUUID, trash_id); +} + +BOOL LLWearableBridgeAction::isAgentInventory() const +{ + if(!mModel) return FALSE; + if(gInventory.getRootFolderID() == mUUID) return TRUE; + return mModel->isObjectDescendentOf(mUUID, gInventory.getRootFolderID()); +} + +void LLWearableBridgeAction::wearOnAvatar() +{ + // Don't wear anything until initial wearables are loaded, can + // destroy clothing items. + if (!gAgentWearables.areWearablesLoaded()) + { + LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); + return; + } + + LLViewerInventoryItem* item = getItem(); + if(item) + { + if(!isAgentInventory()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else + { + wear_inventory_item_on_avatar(item); + } + } +} + +//virtual +void LLWearableBridgeAction::doIt() +{ + if( isInTrash() ) + { + LLNotifications::instance().add("CannotWearTrash"); + } + else if(isAgentInventory()) + { + if( !gAgentWearables.isWearingItem( mUUID ) ) + { + wearOnAvatar(); + } + } + else + { + // must be in the inventory library. copy it to our inventory + // and put it on right away. + LLViewerInventoryItem* item = getItem(); + if(item && item->isComplete()) + { + LLPointer cb = new WearOnAvatarCallback(); + copy_inventory_item( + gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + LLUUID::null, + std::string(), + cb); + } + else if(item) + { + // *TODO: We should fetch the item details, and then do + // the operation above. + LLNotifications::instance().add("CannotWearInfoNotComplete"); + } + } + + LLInvFVBridgeAction::doIt(); +} + +// +=================================================+ +// | LLLinkItemBridge | +// +=================================================+ +// For broken links + +std::string LLLinkItemBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkItemBridge::getIcon() const +{ + if (LLViewerInventoryItem *item = getItem()) + { + return get_item_icon(item->getActualType(), LLInventoryType::IT_NONE, 0, FALSE); + } + return get_item_icon(LLAssetType::AT_LINK, LLInventoryType::IT_NONE, 0, FALSE); +} + +void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + } + hideContextEntries(menu, items, disabled_items); +} + + +// +=================================================+ +// | LLLinkBridge | +// +=================================================+ +// For broken links. + +std::string LLLinkFolderBridge::sPrefix("Link: "); + + +LLUIImagePtr LLLinkFolderBridge::getIcon() const +{ + LLAssetType::EType preferred_type = LLAssetType::AT_NONE; + if (LLViewerInventoryItem *item = getItem()) + { + if (const LLViewerInventoryCategory* cat = item->getLinkedCategory()) + { + preferred_type = cat->getPreferredType(); + } + } + return LLFolderBridge::getIcon(preferred_type); +} + +void LLLinkFolderBridge::buildContextMenu(LLMenuGL& menu, U32 flags) +{ + // *TODO: Translate + lldebugs << "LLLink::buildContextMenu()" << llendl; + std::vector items; + std::vector disabled_items; + + if(isInTrash()) + { + items.push_back(std::string("Purge Item")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Purge Item")); + } + + items.push_back(std::string("Restore Item")); + } + else + { + items.push_back(std::string("Goto Link")); + items.push_back(std::string("Delete")); + if (!isItemRemovable()) + { + disabled_items.push_back(std::string("Delete")); + } + } + hideContextEntries(menu, items, disabled_items); +} + +void LLLinkFolderBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action) +{ + if ("goto" == action) + { + gotoItem(folder); + return; + } + LLItemBridge::performAction(folder,model,action); +} + +void LLLinkFolderBridge::gotoItem(LLFolderView *folder) +{ + const LLUUID &cat_uuid = getFolderID(); + if (!cat_uuid.isNull()) + { + if (LLFolderViewItem *base_folder = folder->getItemByID(cat_uuid)) + { + if (LLInventoryModel* model = getInventoryModel()) + { + model->fetchDescendentsOf(cat_uuid); + } + base_folder->setOpen(TRUE); + folder->setSelectionFromRoot(base_folder,TRUE); + folder->scrollToShowSelection(); + } + } +} + +const LLUUID &LLLinkFolderBridge::getFolderID() const +{ + if (LLViewerInventoryItem *link_item = getItem()) + { + if (const LLViewerInventoryCategory *cat = link_item->getLinkedCategory()) + { + const LLUUID& cat_uuid = cat->getUUID(); + return cat_uuid; + } + } + return LLUUID::null; +} diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 526b30f214..25859b7f73 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -30,10 +30,17 @@ * $/LicenseInfo$ */ +#ifndef LL_LLINVENTORYBRIDGE_H +#define LL_LLINVENTORYBRIDGE_H + #include "llfloaterproperties.h" #include "llwearable.h" #include "llviewercontrol.h" #include "llcallingcard.h" +#include "llinventorymodel.h" +#include "llfoldervieweventlistener.h" + +class LLInventoryPanel; enum EInventoryIcon { @@ -64,10 +71,15 @@ enum EInventoryIcon CLOTHING_UNDERSHIRT_ICON_NAME, CLOTHING_UNDERPANTS_ICON_NAME, CLOTHING_SKIRT_ICON_NAME, + CLOTHING_ALPHA_ICON_NAME, + CLOTHING_TATTOO_ICON_NAME, ANIMATION_ICON_NAME, GESTURE_ICON_NAME, + LINKITEM_ICON_NAME, + LINKFOLDER_ICON_NAME, + ICON_NAME_COUNT }; @@ -93,31 +105,6 @@ struct LLAttachmentRezAction }; -//helper functions -class LLShowProps -{ -public: - - static void showProperties(const LLUUID& uuid) - { - if(!LLFloaterProperties::show(uuid, LLUUID::null)) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PropertiesRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - LLFloaterProperties* floater; - floater = new LLFloaterProperties("item properties", - rect, - "Inventory Item Properties", - uuid, - LLUUID::null); - // keep onscreen - gFloaterView->adjustToFitScreen(floater, FALSE); - } - } -}; - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryPanelObserver // @@ -128,7 +115,7 @@ class LLInventoryPanelObserver : public LLInventoryObserver public: LLInventoryPanelObserver(LLInventoryPanel* ip) : mIP(ip) {} virtual ~LLInventoryPanelObserver() {} - virtual void changed(U32 mask) { mIP->modelChanged(mask); } + virtual void changed(U32 mask); protected: LLInventoryPanel* mIP; }; @@ -150,6 +137,7 @@ public: // This method is a convenience function which creates the correct // type of bridge based on some basic information static LLInvFVBridge* createBridge(LLAssetType::EType asset_type, + LLAssetType::EType actual_asset_type, LLInventoryType::EType inv_type, LLInventoryPanel* inventory, const LLUUID& uuid, @@ -158,7 +146,6 @@ public: virtual const LLUUID& getUUID() const { return mUUID; } - virtual const std::string& getPrefix() { return LLStringUtil::null; } virtual void restoreItem() {} virtual void restoreToWorld() {} @@ -166,6 +153,7 @@ public: virtual const std::string& getName() const; virtual const std::string& getDisplayName() const; virtual PermissionMask getPermissionMask() const; + virtual LLAssetType::EType getPreferredType() const; virtual time_t getCreationDate() const; virtual LLFontGL::StyleFlags getLabelStyle() const { @@ -173,6 +161,8 @@ public: } virtual std::string getLabelSuffix() const { return LLStringUtil::null; } virtual void openItem() {} + virtual void closeItem() {} + virtual void gotoItem(LLFolderView *folder) {} // for links virtual void previewItem() {openItem();} virtual void showProperties(); virtual BOOL isItemRenameable() const { return TRUE; } @@ -186,7 +176,9 @@ public: virtual BOOL copyToClipboard() const { return FALSE; } virtual void cutToClipboard() {} virtual BOOL isClipboardPasteable() const; + virtual BOOL isClipboardPasteableAsLink() const; virtual void pasteFromClipboard() {} + virtual void pasteLinkFromClipboard() {} void getClipboardEntries(bool show_asset_id, std::vector &items, std::vector &disabled_items, U32 flags); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -200,11 +192,14 @@ public: virtual void clearDisplayName() {} protected: - LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : - mInventoryPanel(inventory), mUUID(uuid), mInvType(LLInventoryType::IT_NONE) {} + LLInvFVBridge(LLInventoryPanel* inventory, const LLUUID& uuid); LLInventoryObject* getInventoryObject() const; + LLInventoryModel* getInventoryModel() const; + BOOL isInTrash() const; + BOOL isLinkedObjectInTrash() const; // Is this obj or its baseobj in the trash? + // return true if the item is in agent inventory. if false, it // must be lost or in the inventory library. BOOL isAgentInventory() const; @@ -218,11 +213,13 @@ protected: const LLUUID& new_parent, BOOL restamp); void removeBatchNoCheck(LLDynamicArray& batch); + void renameLinkedItems(const LLUUID &item_id, const std::string& new_name); protected: - LLInventoryPanel* mInventoryPanel; - LLUUID mUUID; // item id + LLHandle mInventoryPanel; + const LLUUID mUUID; // item id LLInventoryType::EType mInvType; + void purgeItem(LLInventoryModel *model, const LLUUID &uuid); }; @@ -237,10 +234,12 @@ public: virtual void selectItem(); virtual void restoreItem(); virtual void restoreToWorld(); + virtual void gotoItem(LLFolderView *folder); virtual LLUIImagePtr getIcon() const; virtual const std::string& getDisplayName() const; virtual std::string getLabelSuffix() const; + virtual LLFontGL::StyleFlags getLabelStyle() const; virtual PermissionMask getPermissionMask() const; virtual time_t getCreationDate() const; virtual BOOL isItemRenameable() const; @@ -273,15 +272,19 @@ public: BOOL drop); virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual void openItem(); + virtual void closeItem(); virtual BOOL isItemRenameable() const; virtual void selectItem(); virtual void restoreItem(); + virtual LLAssetType::EType getPreferredType() const; virtual LLUIImagePtr getIcon() const; + static LLUIImagePtr getIcon(LLAssetType::EType asset_type); + virtual BOOL renameItem(const std::string& new_name); virtual BOOL removeItem(); - virtual BOOL isClipboardPasteable() const; virtual void pasteFromClipboard(); + virtual void pasteLinkFromClipboard(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual BOOL hasChildren() const; virtual BOOL dragOrDrop(MASK mask, BOOL drop, @@ -291,7 +294,9 @@ public: virtual BOOL isItemRemovable(); virtual BOOL isItemMovable(); virtual BOOL isUpToDate() const; - + virtual BOOL isItemCopyable() const; + virtual BOOL copyToClipboard() const; + static void createWearable(LLFolderBridge* bridge, EWearableType type); static void createWearable(LLUUID parent_folder_id, EWearableType type); @@ -322,6 +327,8 @@ protected: BOOL checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& typeToCheck); void modifyOutfit(BOOL append); + void determineFolderType(); + public: static LLFolderBridge* sSelf; static void staticFolderOptionsMenu(); @@ -351,15 +358,12 @@ class LLTextureBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; virtual void openItem(); protected: LLTextureBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type) : LLItemBridge(inventory, uuid), mInvType(type) {} - static std::string sPrefix; LLInventoryType::EType mInvType; }; @@ -367,8 +371,6 @@ class LLSoundBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; virtual void openItem(); virtual void previewItem(); @@ -378,33 +380,21 @@ public: protected: LLSoundBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : LLItemBridge(inventory, uuid) {} - static std::string sPrefix; }; class LLLandmarkBridge : public LLItemBridge { friend class LLInvFVBridge; public: - static const std::string& prefix() { return sPrefix; } - virtual const std::string& getPrefix() { return sPrefix; } virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); virtual LLUIImagePtr getIcon() const; virtual void openItem(); protected: - LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags = 0x00) : - LLItemBridge(inventory, uuid) - { - mVisited = FALSE; - if (flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) - { - mVisited = TRUE; - } - } + LLLandmarkBridge(LLInventoryPanel* inventory, const LLUUID& uuid, U32 flags = 0x00); protected: - static std::string sPrefix; BOOL mVisited; }; @@ -425,8 +415,6 @@ class LLCallingCardBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual std::string getLabelSuffix() const; //virtual const std::string& getDisplayName() const; virtual LLUIImagePtr getIcon() const; @@ -439,13 +427,13 @@ public: EDragAndDropType cargo_type, void* cargo_data); void refreshFolderViewItem(); + BOOL removeItem(); protected: LLCallingCardBridge( LLInventoryPanel* inventory, const LLUUID& uuid ); ~LLCallingCardBridge(); protected: - static std::string sPrefix; LLCallingCardObserver* mObserver; }; @@ -454,25 +442,18 @@ class LLNotecardBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; virtual void openItem(); protected: LLNotecardBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : LLItemBridge(inventory, uuid) {} - -protected: - static std::string sPrefix; }; class LLGestureBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; // Only suffix for gesture items, not task items, because only @@ -489,9 +470,6 @@ public: protected: LLGestureBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : LLItemBridge(inventory, uuid) {} - -protected: - static std::string sPrefix; }; @@ -499,7 +477,6 @@ class LLAnimationBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); @@ -509,9 +486,6 @@ public: protected: LLAnimationBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : LLItemBridge(inventory, uuid) {} - -protected: - static std::string sPrefix; }; @@ -519,8 +493,6 @@ class LLObjectBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual void openItem(); @@ -530,17 +502,12 @@ public: virtual BOOL isItemRemovable(); virtual BOOL renameItem(const std::string& new_name); -protected: - LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags) : - LLItemBridge(inventory, uuid), mInvType(type) - { - mAttachPt = (flags & 0xff); // low bye of inventory flags - - mIsMultiObject = ( flags & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS ) ? TRUE: FALSE; - } + LLInventoryObject* getObject() const; + +protected: + LLObjectBridge(LLInventoryPanel* inventory, const LLUUID& uuid, LLInventoryType::EType type, U32 flags); protected: - static std::string sPrefix; static LLUUID sContextMenuItemID; // Only valid while the context menu is open. LLInventoryType::EType mInvType; U32 mAttachPt; @@ -552,17 +519,12 @@ class LLLSLTextBridge : public LLItemBridge { friend class LLInvFVBridge; public: - virtual const std::string& getPrefix() { return sPrefix; } - virtual LLUIImagePtr getIcon() const; virtual void openItem(); protected: LLLSLTextBridge( LLInventoryPanel* inventory, const LLUUID& uuid ) : LLItemBridge(inventory, uuid) {} - -protected: - static std::string sPrefix; }; @@ -574,7 +536,6 @@ public: virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); virtual void openItem(); virtual void buildContextMenu(LLMenuGL& menu, U32 flags); - virtual LLFontGL::StyleFlags getLabelStyle() const; virtual std::string getLabelSuffix() const; virtual BOOL isItemRemovable(); virtual BOOL renameItem(const std::string& new_name); @@ -584,6 +545,9 @@ public: static void onWearOnAvatarArrived( LLWearable* wearable, void* userdata ); void wearOnAvatar(); + static void onWearAddOnAvatarArrived( LLWearable* wearable, void* userdata ); + void wearAddOnAvatar(); + static BOOL canEditOnAvatar( void* userdata ); // Access to editOnAvatar() from menu static void onEditOnAvatar( void* userdata ); void editOnAvatar(); @@ -605,3 +569,222 @@ protected: LLInventoryType::EType mInvType; EWearableType mWearableType; }; + +class LLLinkItemBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual const std::string& getPrefix() { return sPrefix; } + + virtual LLUIImagePtr getIcon() const; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + +protected: + LLLinkItemBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} + +protected: + static std::string sPrefix; +}; + + +class LLLinkFolderBridge : public LLItemBridge +{ + friend class LLInvFVBridge; +public: + virtual const std::string& getPrefix() { return sPrefix; } + + virtual LLUIImagePtr getIcon() const; + virtual void buildContextMenu(LLMenuGL& menu, U32 flags); + virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action); + virtual void gotoItem(LLFolderView *folder); + +protected: + LLLinkFolderBridge(LLInventoryPanel* inventory, const LLUUID& uuid) : + LLItemBridge(inventory, uuid) {} + const LLUUID &getFolderID() const; + +protected: + static std::string sPrefix; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLInvFVBridgeAction (& its derived classes) +// +// This is an implementation class to be able to +// perform action to view inventory items. +// +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLInvFVBridgeAction +{ +public: + // This method is a convenience function which creates the correct + // type of bridge action based on some basic information + static LLInvFVBridgeAction* createAction(LLAssetType::EType asset_type, + const LLUUID& uuid,LLInventoryModel* model); + + static void doAction(LLAssetType::EType asset_type, + const LLUUID& uuid, LLInventoryModel* model); + static void doAction(const LLUUID& uuid, LLInventoryModel* model); + + virtual void doIt() { }; + virtual ~LLInvFVBridgeAction(){}//need this because of warning on OSX +protected: + LLInvFVBridgeAction(const LLUUID& id,LLInventoryModel* model):mUUID(id),mModel(model){} + + LLViewerInventoryItem* getItem() const; +protected: + const LLUUID& mUUID; // item id + LLInventoryModel* mModel; + +}; + + + +class LLTextureBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLTextureBridgeAction(){} +protected: + LLTextureBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLSoundBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLSoundBridgeAction(){} +protected: + LLSoundBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLLandmarkBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLLandmarkBridgeAction(){} +protected: + LLLandmarkBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLCallingCardBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLCallingCardBridgeAction(){} +protected: + LLCallingCardBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLNotecardBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLNotecardBridgeAction(){} +protected: + LLNotecardBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLGestureBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLGestureBridgeAction(){} +protected: + LLGestureBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLAnimationBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLAnimationBridgeAction(){} +protected: + LLAnimationBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLObjectBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLObjectBridgeAction(){} +protected: + LLObjectBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLLSLTextBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt() ; + virtual ~LLLSLTextBridgeAction(){} +protected: + LLLSLTextBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + +}; + + +class LLWearableBridgeAction: public LLInvFVBridgeAction +{ + friend class LLInvFVBridgeAction; +public: + virtual void doIt(); + virtual ~LLWearableBridgeAction(){} +protected: + LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){} + + + BOOL isInTrash() const; + // return true if the item is in agent inventory. if false, it + // must be lost or in the inventory library. + BOOL isAgentInventory() const; + + void wearOnAvatar(); + +}; + +void wear_inventory_item_on_avatar(LLInventoryItem* item); +void wear_outfit_by_name(const std::string& name); +void wear_inventory_category(LLInventoryCategory* category, bool copy, bool append); + +class LLViewerJointAttachment; +void rez_attachment(LLViewerInventoryItem* item, LLViewerJointAttachment* attachment); + +// Move items from an in-world object's "Contents" folder to a specified +// folder in agent inventory. +BOOL move_inv_category_world_to_agent(const LLUUID& object_id, + const LLUUID& category_id, + BOOL drop, + void (*callback)(S32, void*) = NULL, + void* user_data = NULL); + + + +void teleport_via_landmark(const LLUUID& asset_id); + +#endif // LL_LLINVENTORYBRIDGE_H diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp new file mode 100644 index 0000000000..b4d3f4575b --- /dev/null +++ b/indra/newview/llinventoryfilter.cpp @@ -0,0 +1,664 @@ +/** +* @file llinventoryfilter.cpp +* @brief Support for filtering your inventory to only display a subset of the +* available items. +* +* $LicenseInfo:firstyear=2005&license=viewergpl$ +* +* Copyright (c) 2005-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#include "llviewerprecompiledheaders.h" + +#include "llinventoryfilter.h" + +// viewer includes +#include "llfoldervieweventlistener.h" +#include "llfolderviewitem.h" +#include "llinventorymodel.h" // gInventory.backgroundFetchActive() +#include "llviewercontrol.h" +#include "llviewerinventory.h" + +// linden library includes +#include "lltrans.h" + +///---------------------------------------------------------------------------- +/// Class LLInventoryFilter +///---------------------------------------------------------------------------- +LLInventoryFilter::LLInventoryFilter(const std::string& name) +: mName(name), + mModified(FALSE), + mNeedTextRebuild(TRUE) +{ + mFilterOps.mFilterTypes = 0xffffffffffffffffULL; + mFilterOps.mMinDate = time_min(); + mFilterOps.mMaxDate = time_max(); + mFilterOps.mHoursAgo = 0; + mFilterOps.mShowFolderState = SHOW_NON_EMPTY_FOLDERS; + mFilterOps.mPermissions = PERM_NONE; + mFilterOps.mFilterForCategories = FALSE; + + mOrder = SO_FOLDERS_BY_NAME; // This gets overridden by a pref immediately + + mSubStringMatchOffset = 0; + mFilterSubString.clear(); + mFilterGeneration = 0; + mMustPassGeneration = S32_MAX; + mMinRequiredGeneration = 0; + mFilterCount = 0; + mNextFilterGeneration = mFilterGeneration + 1; + + mLastLogoff = gSavedPerAccountSettings.getU32("LastLogoff"); + mFilterBehavior = FILTER_NONE; + + // copy mFilterOps into mDefaultFilterOps + markDefault(); +} + +LLInventoryFilter::~LLInventoryFilter() +{ +} + +BOOL LLInventoryFilter::check(LLFolderViewItem* item) +{ + time_t earliest; + + earliest = time_corrected() - mFilterOps.mHoursAgo * 3600; + if (mFilterOps.mMinDate > time_min() && mFilterOps.mMinDate < earliest) + { + earliest = mFilterOps.mMinDate; + } + else if (!mFilterOps.mHoursAgo) + { + earliest = 0; + } + LLFolderViewEventListener* listener = item->getListener(); + mSubStringMatchOffset = mFilterSubString.size() ? item->getSearchableLabel().find(mFilterSubString) : std::string::npos; + + bool passed_type = false; + if (mFilterOps.mFilterForCategories) + { + if (listener->getInventoryType() == LLInventoryType::IT_CATEGORY) + { + LLViewerInventoryCategory *cat = gInventory.getCategory(listener->getUUID()); + if (cat) + { + passed_type |= ((1LL << cat->getPreferredType() & mFilterOps.mFilterTypes) != U64(0)); + } + } + } + else + { + LLInventoryType::EType type = listener->getInventoryType(); + passed_type |= ((1LL << type & mFilterOps.mFilterTypes) != U64(0)); + if (type == LLInventoryType::IT_NONE) + { + const LLInventoryObject *obj = gInventory.getObject(listener->getUUID()); + if (obj && obj->getIsLinkType()) + { + passed_type = FALSE; + } + else + { + passed_type = TRUE; + } + } + } + + BOOL passed = passed_type + && (mFilterSubString.size() == 0 || mSubStringMatchOffset != std::string::npos) + && ((listener->getPermissionMask() & mFilterOps.mPermissions) == mFilterOps.mPermissions) + && (listener->getCreationDate() >= earliest && listener->getCreationDate() <= mFilterOps.mMaxDate); + return passed; +} + +const std::string LLInventoryFilter::getFilterSubString(BOOL trim) +{ + return mFilterSubString; +} + +std::string::size_type LLInventoryFilter::getStringMatchOffset() const +{ + return mSubStringMatchOffset; +} + +// has user modified default filter params? +BOOL LLInventoryFilter::isNotDefault() +{ + return mFilterOps.mFilterTypes != mDefaultFilterOps.mFilterTypes + || mFilterSubString.size() + || mFilterOps.mPermissions != mDefaultFilterOps.mPermissions + || mFilterOps.mMinDate != mDefaultFilterOps.mMinDate + || mFilterOps.mMaxDate != mDefaultFilterOps.mMaxDate + || mFilterOps.mHoursAgo != mDefaultFilterOps.mHoursAgo; +} + +BOOL LLInventoryFilter::isActive() +{ + return mFilterOps.mFilterTypes != 0xffffffffffffffffULL + || mFilterSubString.size() + || mFilterOps.mPermissions != PERM_NONE + || mFilterOps.mMinDate != time_min() + || mFilterOps.mMaxDate != time_max() + || mFilterOps.mHoursAgo != 0; +} + +BOOL LLInventoryFilter::isModified() +{ + return mModified; +} + +BOOL LLInventoryFilter::isModifiedAndClear() +{ + BOOL ret = mModified; + mModified = FALSE; + return ret; +} + +void LLInventoryFilter::setFilterTypes(U64 types, BOOL filter_for_categories) +{ + if (mFilterOps.mFilterTypes != types) + { + // keep current items only if no type bits getting turned off + BOOL fewer_bits_set = (mFilterOps.mFilterTypes & ~types); + BOOL more_bits_set = (~mFilterOps.mFilterTypes & types); + + mFilterOps.mFilterTypes = types; + if (more_bits_set && fewer_bits_set) + { + // neither less or more restrive, both simultaneously + // so we need to filter from scratch + setModified(FILTER_RESTART); + } + else if (more_bits_set) + { + // target is only one of all requested types so more type bits == less restrictive + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (fewer_bits_set) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + } + mFilterOps.mFilterForCategories = filter_for_categories; +} + +void LLInventoryFilter::setFilterSubString(const std::string& string) +{ + if (mFilterSubString != string) + { + // hitting BACKSPACE, for example + BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string); + // appending new characters + BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString); + mFilterSubString = string; + LLStringUtil::toUpper(mFilterSubString); + LLStringUtil::trimHead(mFilterSubString); + + if (less_restrictive) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (more_restrictive) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + setModified(FILTER_RESTART); + } + } +} + +void LLInventoryFilter::setFilterPermissions(PermissionMask perms) +{ + if (mFilterOps.mPermissions != perms) + { + // keep current items only if no perm bits getting turned off + BOOL fewer_bits_set = (mFilterOps.mPermissions & ~perms); + BOOL more_bits_set = (~mFilterOps.mPermissions & perms); + mFilterOps.mPermissions = perms; + + if (more_bits_set && fewer_bits_set) + { + setModified(FILTER_RESTART); + } + else if (more_bits_set) + { + // target must have all requested permission bits, so more bits == more restrictive + setModified(FILTER_MORE_RESTRICTIVE); + } + else if (fewer_bits_set) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + } +} + +void LLInventoryFilter::setDateRange(time_t min_date, time_t max_date) +{ + mFilterOps.mHoursAgo = 0; + if (mFilterOps.mMinDate != min_date) + { + mFilterOps.mMinDate = min_date; + setModified(); + } + if (mFilterOps.mMaxDate != llmax(mFilterOps.mMinDate, max_date)) + { + mFilterOps.mMaxDate = llmax(mFilterOps.mMinDate, max_date); + setModified(); + } +} + +void LLInventoryFilter::setDateRangeLastLogoff(BOOL sl) +{ + if (sl && !isSinceLogoff()) + { + setDateRange(mLastLogoff, time_max()); + setModified(); + } + if (!sl && isSinceLogoff()) + { + setDateRange(0, time_max()); + setModified(); + } +} + +BOOL LLInventoryFilter::isSinceLogoff() +{ + return (mFilterOps.mMinDate == (time_t)mLastLogoff) && + (mFilterOps.mMaxDate == time_max()); +} + +void LLInventoryFilter::setHoursAgo(U32 hours) +{ + if (mFilterOps.mHoursAgo != hours) + { + // *NOTE: need to cache last filter time, in case filter goes stale + BOOL less_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours > mFilterOps.mHoursAgo); + BOOL more_restrictive = (mFilterOps.mMinDate == time_min() && mFilterOps.mMaxDate == time_max() && hours <= mFilterOps.mHoursAgo); + mFilterOps.mHoursAgo = hours; + mFilterOps.mMinDate = time_min(); + mFilterOps.mMaxDate = time_max(); + if (less_restrictive) + { + setModified(FILTER_LESS_RESTRICTIVE); + } + else if (more_restrictive) + { + setModified(FILTER_MORE_RESTRICTIVE); + } + else + { + setModified(FILTER_RESTART); + } + } +} +void LLInventoryFilter::setShowFolderState(EFolderShow state) +{ + if (mFilterOps.mShowFolderState != state) + { + mFilterOps.mShowFolderState = state; + if (state == SHOW_NON_EMPTY_FOLDERS) + { + // showing fewer folders than before + setModified(FILTER_MORE_RESTRICTIVE); + } + else if (state == SHOW_ALL_FOLDERS) + { + // showing same folders as before and then some + setModified(FILTER_LESS_RESTRICTIVE); + } + else + { + setModified(); + } + } +} + +void LLInventoryFilter::setSortOrder(U32 order) +{ + if (mOrder != order) + { + mOrder = order; + setModified(); + } +} + +void LLInventoryFilter::markDefault() +{ + mDefaultFilterOps = mFilterOps; +} + +void LLInventoryFilter::resetDefault() +{ + mFilterOps = mDefaultFilterOps; + setModified(); +} + +void LLInventoryFilter::setModified(EFilterBehavior behavior) +{ + mModified = TRUE; + mNeedTextRebuild = TRUE; + mFilterGeneration = mNextFilterGeneration++; + + if (mFilterBehavior == FILTER_NONE) + { + mFilterBehavior = behavior; + } + else if (mFilterBehavior != behavior) + { + // trying to do both less restrictive and more restrictive filter + // basically means restart from scratch + mFilterBehavior = FILTER_RESTART; + } + + if (isNotDefault()) + { + // if not keeping current filter results, update last valid as well + switch(mFilterBehavior) + { + case FILTER_RESTART: + mMustPassGeneration = mFilterGeneration; + mMinRequiredGeneration = mFilterGeneration; + break; + case FILTER_LESS_RESTRICTIVE: + mMustPassGeneration = mFilterGeneration; + break; + case FILTER_MORE_RESTRICTIVE: + mMinRequiredGeneration = mFilterGeneration; + // must have passed either current filter generation (meaningless, as it hasn't been run yet) + // or some older generation, so keep the value + mMustPassGeneration = llmin(mMustPassGeneration, mFilterGeneration); + break; + default: + llerrs << "Bad filter behavior specified" << llendl; + } + } + else + { + // shortcut disabled filters to show everything immediately + mMinRequiredGeneration = 0; + mMustPassGeneration = S32_MAX; + } +} + +BOOL LLInventoryFilter::isFilterWith(LLInventoryType::EType t) +{ + return mFilterOps.mFilterTypes & (1LL << t); +} + +std::string LLInventoryFilter::getFilterText() +{ + if (!mNeedTextRebuild) + { + return mFilterText; + } + + mNeedTextRebuild = FALSE; + std::string filtered_types; + std::string not_filtered_types; + BOOL filtered_by_type = FALSE; + BOOL filtered_by_all_types = TRUE; + S32 num_filter_types = 0; + mFilterText.clear(); + + if (isFilterWith(LLInventoryType::IT_ANIMATION)) + { + //filtered_types += " Animations,"; + filtered_types += LLTrans::getString("Animations"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Animations,"; + not_filtered_types += LLTrans::getString("Animations"); + + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_CALLINGCARD)) + { + //filtered_types += " Calling Cards,"; + filtered_types += LLTrans::getString("Calling Cards"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Calling Cards,"; + not_filtered_types += LLTrans::getString("Calling Cards"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_WEARABLE)) + { + //filtered_types += " Clothing,"; + filtered_types += LLTrans::getString("Clothing"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Clothing,"; + not_filtered_types += LLTrans::getString("Clothing"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_GESTURE)) + { + //filtered_types += " Gestures,"; + filtered_types += LLTrans::getString("Gestures"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Gestures,"; + not_filtered_types += LLTrans::getString("Gestures"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_LANDMARK)) + { + //filtered_types += " Landmarks,"; + filtered_types += LLTrans::getString("Landmarks"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Landmarks,"; + not_filtered_types += LLTrans::getString("Landmarks"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_NOTECARD)) + { + //filtered_types += " Notecards,"; + filtered_types += LLTrans::getString("Notecards"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Notecards,"; + not_filtered_types += LLTrans::getString("Notecards"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_OBJECT) && isFilterWith(LLInventoryType::IT_ATTACHMENT)) + { + //filtered_types += " Objects,"; + filtered_types += LLTrans::getString("Objects"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Objects,"; + not_filtered_types += LLTrans::getString("Objects"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_LSL)) + { + //filtered_types += " Scripts,"; + filtered_types += LLTrans::getString("Scripts"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Scripts,"; + not_filtered_types += LLTrans::getString("Scripts"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_SOUND)) + { + //filtered_types += " Sounds,"; + filtered_types += LLTrans::getString("Sounds"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Sounds,"; + not_filtered_types += LLTrans::getString("Sounds"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_TEXTURE)) + { + //filtered_types += " Textures,"; + filtered_types += LLTrans::getString("Textures"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Textures,"; + not_filtered_types += LLTrans::getString("Textures"); + filtered_by_all_types = FALSE; + } + + if (isFilterWith(LLInventoryType::IT_SNAPSHOT)) + { + //filtered_types += " Snapshots,"; + filtered_types += LLTrans::getString("Snapshots"); + filtered_by_type = TRUE; + num_filter_types++; + } + else + { + //not_filtered_types += " Snapshots,"; + not_filtered_types += LLTrans::getString("Snapshots"); + filtered_by_all_types = FALSE; + } + + if (!gInventory.backgroundFetchActive() + && filtered_by_type + && !filtered_by_all_types) + { + mFilterText += " - "; + if (num_filter_types < 5) + { + mFilterText += filtered_types; + } + else + { + //mFilterText += "No "; + mFilterText += LLTrans::getString("No Filters"); + mFilterText += not_filtered_types; + } + // remove the ',' at the end + mFilterText.erase(mFilterText.size() - 1, 1); + } + + if (isSinceLogoff()) + { + //mFilterText += " - Since Logoff"; + mFilterText += LLTrans::getString("Since Logoff"); + } + return mFilterText; +} + +void LLInventoryFilter::toLLSD(LLSD& data) +{ + data["filter_types"] = (LLSD::Integer)getFilterTypes(); + data["min_date"] = (LLSD::Integer)getMinDate(); + data["max_date"] = (LLSD::Integer)getMaxDate(); + data["hours_ago"] = (LLSD::Integer)getHoursAgo(); + data["show_folder_state"] = (LLSD::Integer)getShowFolderState(); + data["permissions"] = (LLSD::Integer)getFilterPermissions(); + data["substring"] = (LLSD::String)getFilterSubString(); + data["sort_order"] = (LLSD::Integer)getSortOrder(); + data["since_logoff"] = (LLSD::Boolean)isSinceLogoff(); +} + +void LLInventoryFilter::fromLLSD(LLSD& data) +{ + if(data.has("filter_types")) + { + setFilterTypes((U32)data["filter_types"].asInteger()); + } + + if(data.has("min_date") && data.has("max_date")) + { + setDateRange(data["min_date"].asInteger(), data["max_date"].asInteger()); + } + + if(data.has("hours_ago")) + { + setHoursAgo((U32)data["hours_ago"].asInteger()); + } + + if(data.has("show_folder_state")) + { + setShowFolderState((EFolderShow)data["show_folder_state"].asInteger()); + } + + if(data.has("permissions")) + { + setFilterPermissions((PermissionMask)data["permissions"].asInteger()); + } + + if(data.has("substring")) + { + setFilterSubString(std::string(data["substring"].asString())); + } + + if(data.has("sort_order")) + { + setSortOrder((U32)data["sort_order"].asInteger()); + } + + if(data.has("since_logoff")) + { + setDateRangeLastLogoff((bool)data["since_logoff"].asBoolean()); + } +} diff --git a/indra/newview/llinventoryfilter.h b/indra/newview/llinventoryfilter.h new file mode 100644 index 0000000000..670b1f000b --- /dev/null +++ b/indra/newview/llinventoryfilter.h @@ -0,0 +1,151 @@ +/** +* @file llinventoryfilter.h +* @brief Support for filtering your inventory to only display a subset of the +* available items. +* +* $LicenseInfo:firstyear=2005&license=viewergpl$ +* +* Copyright (c) 2005-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ +#ifndef LLINVENTORYFILTER_H +#define LLINVENTORYFILTER_H + +// lots of includes here +#include "llinventorytype.h" +#include "llpermissionsflags.h" // PermissionsMask + +class LLFolderViewItem; + +class LLInventoryFilter +{ +public: + typedef enum e_folder_show + { + SHOW_ALL_FOLDERS, + SHOW_NON_EMPTY_FOLDERS, + SHOW_NO_FOLDERS + } EFolderShow; + + typedef enum e_filter_behavior + { + FILTER_NONE, // nothing to do, already filtered + FILTER_RESTART, // restart filtering from scratch + FILTER_LESS_RESTRICTIVE, // existing filtered items will certainly pass this filter + FILTER_MORE_RESTRICTIVE // if you didn't pass the previous filter, you definitely won't pass this one + } EFilterBehavior; + + static const U32 SO_DATE = 1; + static const U32 SO_FOLDERS_BY_NAME = 2; + static const U32 SO_SYSTEM_FOLDERS_TO_TOP = 4; + + LLInventoryFilter(const std::string& name); + virtual ~LLInventoryFilter(); + + void setFilterTypes(U64 types, BOOL filter_for_categories = FALSE); // if filter_for_categories is true, operate on folder preferred asset type + U32 getFilterTypes() const { return mFilterOps.mFilterTypes; } + + void setFilterSubString(const std::string& string); + const std::string getFilterSubString(BOOL trim = FALSE); + + void setFilterPermissions(PermissionMask perms); + PermissionMask getFilterPermissions() const { return mFilterOps.mPermissions; } + + void setDateRange(time_t min_date, time_t max_date); + void setDateRangeLastLogoff(BOOL sl); + time_t getMinDate() const { return mFilterOps.mMinDate; } + time_t getMaxDate() const { return mFilterOps.mMaxDate; } + + void setHoursAgo(U32 hours); + U32 getHoursAgo() const { return mFilterOps.mHoursAgo; } + + void setShowFolderState( EFolderShow state); + EFolderShow getShowFolderState() { return mFilterOps.mShowFolderState; } + + void setSortOrder(U32 order); + U32 getSortOrder() { return mOrder; } + + BOOL check(LLFolderViewItem* item); + std::string::size_type getStringMatchOffset() const; + BOOL isActive(); + BOOL isNotDefault(); + BOOL isModified(); + BOOL isModifiedAndClear(); + BOOL isSinceLogoff(); + void clearModified() { mModified = FALSE; mFilterBehavior = FILTER_NONE; } + const std::string getName() const { return mName; } + std::string getFilterText(); + + void setFilterCount(S32 count) { mFilterCount = count; } + S32 getFilterCount() { return mFilterCount; } + void decrementFilterCount() { mFilterCount--; } + + void markDefault(); + void resetDefault(); + + BOOL isFilterWith(LLInventoryType::EType t); + + S32 getCurrentGeneration() const { return mFilterGeneration; } + S32 getMinRequiredGeneration() const { return mMinRequiredGeneration; } + S32 getMustPassGeneration() const { return mMustPassGeneration; } + + //RN: this is public to allow system to externally force a global refilter + void setModified(EFilterBehavior behavior = FILTER_RESTART); + + void toLLSD(LLSD& data); + void fromLLSD(LLSD& data); + +protected: + struct filter_ops + { + U64 mFilterTypes; + BOOL mFilterForCategories; + time_t mMinDate; + time_t mMaxDate; + U32 mHoursAgo; + EFolderShow mShowFolderState; + PermissionMask mPermissions; + }; + filter_ops mFilterOps; + filter_ops mDefaultFilterOps; + std::string::size_type mSubStringMatchOffset; + std::string mFilterSubString; + U32 mOrder; + const std::string mName; + S32 mFilterGeneration; + S32 mMustPassGeneration; + S32 mMinRequiredGeneration; + S32 mFilterCount; + S32 mNextFilterGeneration; + EFilterBehavior mFilterBehavior; + +private: + U32 mLastLogoff; + BOOL mModified; + BOOL mNeedTextRebuild; + std::string mFilterText; +}; + +#endif diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index f98a3f9ee5..aadda3fbfd 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -42,9 +42,11 @@ #include "message.h" #include "llagent.h" +#include "llagentwearables.h" #include "llfloater.h" #include "llfocusmgr.h" -#include "llinventoryview.h" +#include "llinventorybridge.h" +#include "llfloaterinventory.h" #include "llviewerinventory.h" #include "llviewermessage.h" #include "llviewerwindow.h" @@ -53,11 +55,11 @@ #include "lldbstrings.h" #include "llviewerstats.h" #include "llmutelist.h" -#include "llnotify.h" +#include "llnotifications.h" #include "llcallbacklist.h" #include "llpreview.h" #include "llviewercontrol.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llsdutil.h" #include @@ -87,33 +89,6 @@ static std::deque sFetchQueue; const F32 MAX_TIME_FOR_SINGLE_FETCH = 10.f; const S32 MAX_FETCH_RETRIES = 10; const char CACHE_FORMAT_STRING[] = "%s.inv"; -const char* NEW_CATEGORY_NAME = "New Folder"; -const char* NEW_CATEGORY_NAMES[LLAssetType::AT_COUNT] = -{ - "Textures", // AT_TEXTURE - "Sounds", // AT_SOUND - "Calling Cards", // AT_CALLINGCARD - "Landmarks", // AT_LANDMARK - "Scripts", // AT_SCRIPT (deprecated?) - "Clothing", // AT_CLOTHING - "Objects", // AT_OBJECT - "Notecards", // AT_NOTECARD - "New Folder", // AT_CATEGORY - "Inventory", // AT_ROOT_CATEGORY - "Scripts", // AT_LSL_TEXT - "Scripts", // AT_LSL_BYTECODE - "Uncompressed Images", // AT_TEXTURE_TGA - "Body Parts", // AT_BODYPART - "Trash", // AT_TRASH - "Photo Album", // AT_SNAPSHOT_CATEGORY - "Lost And Found", // AT_LOST_AND_FOUND - "Uncompressed Sounds", // AT_SOUND_WAV - "Uncompressed Images", // AT_IMAGE_TGA - "Uncompressed Images", // AT_IMAGE_JPEG - "Animations", // AT_ANIMATION - "Gestures", // AT_GESTURE - "New Folder" // AT_SIMSTATE -}; struct InventoryIDPtrLess { @@ -180,9 +155,20 @@ bool LLCanCache::operator()(LLInventoryCategory* cat, LLInventoryItem* item) LLInventoryModel gInventory; // Default constructor -LLInventoryModel::LLInventoryModel() : - mModifyMask(LLInventoryObserver::ALL), +LLInventoryModel::LLInventoryModel() +: mModifyMask(LLInventoryObserver::ALL), + mChangedItemIDs(), + mCategoryMap(), + mItemMap(), + mCategoryLock(), + mItemLock(), mLastItem(NULL), + mParentChildCategoryTree(), + mParentChildItemTree(), + mObservers(), + mRootFolderID(), + mLibraryRootFolderID(), + mLibraryOwnerID(), mIsAgentInvUsable(false) { } @@ -324,7 +310,7 @@ LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool crea LLUUID rv = findCatUUID(t); if(rv.isNull() && isInventoryUsable() && create_folder) { - LLUUID root_id = gAgent.getInventoryRootID(); + LLUUID root_id = gInventory.getRootFolderID(); if(root_id.notNull()) { rv = createNewCategory(root_id, t, LLStringUtil::null); @@ -337,7 +323,7 @@ LLUUID LLInventoryModel::findCategoryUUIDForType(LLAssetType::EType t, bool crea // preferred type. Returns LLUUID::null if not found. LLUUID LLInventoryModel::findCatUUID(LLAssetType::EType preferred_type) { - LLUUID root_id = gAgent.getInventoryRootID(); + LLUUID root_id = gInventory.getRootFolderID(); if(LLAssetType::AT_CATEGORY == preferred_type) { return root_id; @@ -388,14 +374,9 @@ LLUUID LLInventoryModel::createNewCategory(const LLUUID& parent_id, { name.assign(pname); } - else if((preferred_type >= LLAssetType::AT_TEXTURE) && - (preferred_type < LLAssetType::AT_SIMSTATE)) - { - name.assign(NEW_CATEGORY_NAMES[preferred_type]); - } else { - name.assign(NEW_CATEGORY_NAME); + name.assign(LLAssetType::lookupCategoryName(preferred_type)); } // Add the category to the internal representation @@ -453,7 +434,8 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, cat_array_t& cats, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add) + LLInventoryCollectFunctor& add, + BOOL follow_folder_links) { // Start with categories if(!include_trash) @@ -477,9 +459,38 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } - // Move onto items LLViewerInventoryItem* item = NULL; item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + // Follow folder links recursively. Currently never goes more + // than one level deep (for current outfit support) + // Note: if making it fully recursive, need more checking against infinite loops. + if (follow_folder_links && item_array) + { + S32 count = item_array->count(); + for(S32 i = 0; i < count; ++i) + { + item = item_array->get(i); + if (item->getActualType() == LLAssetType::AT_LINK_FOLDER) + { + // BAP either getLinkedCategory() should return non-const, or the functor should take const. + LLViewerInventoryCategory *linked_cat = const_cast(item->getLinkedCategory()); + if (linked_cat) + { + if(add(linked_cat,NULL)) + { + // BAP should this be added here? May not + // matter if it's only being used in current + // outfit traversal. + cats.put(LLPointer(linked_cat)); + } + collectDescendentsIf(linked_cat->getUUID(), cats, items, include_trash, add, FALSE); + } + } + } + } + + // Move onto items if(item_array) { S32 count = item_array->count(); @@ -494,6 +505,47 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } +void LLInventoryModel::updateLinkedObjects(const LLUUID& object_id) +{ + LLInventoryModel::cat_array_t cat_array; + LLInventoryModel::item_array_t item_array; + LLLinkedItemIDMatches is_linked_item_match(object_id); + collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + item_array, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); + + for (LLInventoryModel::cat_array_t::iterator cat_iter = cat_array.begin(); + cat_iter != cat_array.end(); + cat_iter++) + { + LLViewerInventoryCategory *linked_cat = (*cat_iter); + addChangedMask(LLInventoryObserver::LABEL, linked_cat->getUUID()); + }; + + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID()); + }; + notifyObservers(); +} + +void LLInventoryModel::collectLinkedItems(const LLUUID& id, + item_array_t& items) +{ + LLInventoryModel::cat_array_t cat_array; + LLLinkedItemIDMatches is_linked_item_match(id); + collectDescendentsIf(gInventory.getRootFolderID(), + cat_array, + items, + LLInventoryModel::INCLUDE_TRASH, + is_linked_item_match); +} + // Generates a string containing the path to the item specified by // item_id. void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) @@ -518,7 +570,7 @@ void LLInventoryModel::appendPath(const LLUUID& id, std::string& path) bool LLInventoryModel::isInventoryUsable() { bool result = false; - if(gAgent.getInventoryRootID().notNull() && mIsAgentInvUsable) + if(gInventory.getRootFolderID().notNull() && mIsAgentInvUsable) { result = true; } @@ -543,9 +595,11 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) } LLViewerInventoryItem* old_item = getItem(item->getUUID()); + LLPointer new_item; if(old_item) { - // We already have an old item, modify it's values + // We already have an old item, modify its values + new_item = old_item; LLUUID old_parent_id = old_item->getParentUUID(); LLUUID new_parent_id = item->getParentUUID(); if(old_parent_id != new_parent_id) @@ -574,7 +628,7 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) else { // Simply add this item - LLPointer new_item = new LLViewerInventoryItem(item); + new_item = new LLViewerInventoryItem(item); addItem(new_item); if(item->getParentUUID().isNull()) @@ -634,11 +688,24 @@ U32 LLInventoryModel::updateItem(const LLViewerInventoryItem* item) } mask |= LLInventoryObserver::ADD; } - if(item->getType() == LLAssetType::AT_CALLINGCARD) + if(new_item->getType() == LLAssetType::AT_CALLINGCARD) { mask |= LLInventoryObserver::CALLING_CARD; + // Handle user created calling cards. + // Target ID is stored in the description field of the card. + LLUUID id; + std::string desc = new_item->getDescription(); + BOOL isId = desc.empty() ? FALSE : id.set(desc, FALSE); + if (isId) + { + // Valid UUID; set the item UUID and rename it + new_item->setCreator(id); + std::string avatar_name; + // Fetch the currect name + gCacheName->get(id, FALSE, boost::bind(&LLViewerInventoryItem::onCallingCardNameLookup, new_item.get(), _1, _2, _3)); + } } - addChangedMask(mask, item->getUUID()); + addChangedMask(mask, new_item->getUUID()); return mask; } @@ -777,6 +844,7 @@ void LLInventoryModel::moveObject(const LLUUID& object_id, const LLUUID& cat_id) // Delete a particular inventory object by ID. void LLInventoryModel::deleteObject(const LLUUID& id) { + purgeLinkedObjects(id); lldebugs << "LLInventoryModel::deleteObject()" << llendl; LLPointer obj = getObject(id); if(obj) @@ -816,6 +884,42 @@ void LLInventoryModel::deleteObject(const LLUUID& id) } } +// Delete a particular inventory item by ID, and remove it from the server. +void LLInventoryModel::purgeObject(const LLUUID &id) +{ + lldebugs << "LLInventoryModel::purgeObject()" << llendl; + LLPointer obj = getObject(id); + if(obj) + { + obj->removeFromServer(); + LLPreview::hide(id); + deleteObject(id); + } +} + +void LLInventoryModel::purgeLinkedObjects(const LLUUID &id) +{ + LLInventoryObject* objectp = getObject(id); + if (!objectp) return; + + if (objectp->getIsLinkType()) + { + return; + } + + LLInventoryModel::item_array_t item_array; + collectLinkedItems(id, item_array); + + for (LLInventoryModel::item_array_t::iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + LLViewerInventoryItem *linked_item = (*iter); + if (linked_item->getUUID() == id) continue; + purgeObject(linked_item->getUUID()); + } +} + // This is a method which collects the descendents of the id // provided. If the category is not found, no action is // taken. This method goes through the long winded process of @@ -1042,7 +1146,7 @@ void LLInventoryModel::mock(const LLUUID& root_id) root_id, LLUUID::null, LLAssetType::AT_CATEGORY, - NEW_CATEGORY_NAMES[LLAssetType::AT_ROOT_CATEGORY], + LLAssetType::lookupCategoryName(LLAssetType::AT_ROOT_CATEGORY), gAgent.getID()); addCategory(cat); gInventory.buildParentChildMap(); @@ -1122,14 +1226,14 @@ void LLInventoryModel::fetchInventoryResponder::error(U32 status, const std::str gInventory.notifyObservers("fetchinventory"); } -void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) +bool LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) { LLViewerInventoryCategory* cat = getCategory(folder_id); if(!cat) { llwarns << "Asked to fetch descendents of non-existent folder: " << folder_id << llendl; - return; + return false; } //S32 known_descendents = 0; ///cat_array_t* categories = get_ptr_in_map(mParentChildCategoryTree, folder_id); @@ -1142,10 +1246,7 @@ void LLInventoryModel::fetchDescendentsOf(const LLUUID& folder_id) //{ // known_descendents += items->count(); //} - if(!cat->fetchDescendents()) - { - //llinfos << "Not fetching descendents" << llendl; - } + return cat->fetchDescendents(); } //Initialize statics. @@ -1263,6 +1364,7 @@ void fetchDescendentsResponder::result(const LLSD& content) { cat->setVersion(version); cat->setDescendentCount(descendents); + cat->determineFolderType(); } } @@ -1459,8 +1561,8 @@ void LLInventoryModel::startBackgroundFetch(const LLUUID& cat_id) if (!sFullFetchStarted) { sFullFetchStarted = TRUE; - sFetchQueue.push_back(gInventoryLibraryRoot); - sFetchQueue.push_back(gAgent.getInventoryRootID()); + sFetchQueue.push_back(gInventory.getLibraryRootFolderID()); + sFetchQueue.push_back(gInventory.getRootFolderID()); gIdleCallbacks.addFunction(&LLInventoryModel::backgroundFetch, NULL); } } @@ -1684,6 +1786,12 @@ void LLInventoryModel::addItem(LLViewerInventoryItem* item) //llinfos << "LLInventoryModel::addItem()" << llendl; if(item) { + // This condition means that we tried to add a link without the baseobj being in memory. + // The item will show up as a broken link. + if (item->getIsBrokenLink()) + { + llwarns << "Add link item without baseobj present ( name: " << item->getName() << " itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) parent: " << item->getParentUUID() << llendl; + } mItemMap[item->getUUID()] = item; //mInventory[item->getUUID()] = item; } @@ -1933,6 +2041,7 @@ bool LLInventoryModel::loadSkeleton( { cat_array_t categories; item_array_t items; + cat_set_t invalid_categories; // Used to mark categories that weren't successfully loaded. std::string owner_id_str; owner_id.toString(owner_id_str); std::string path(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, owner_id_str)); @@ -1998,7 +2107,7 @@ bool LLInventoryModel::loadSkeleton( } // go ahead and add the cats returned during the download - std::set::iterator not_cached_id = cached_ids.end(); + std::set::const_iterator not_cached_id = cached_ids.end(); cached_category_count = cached_ids.size(); for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) { @@ -2018,16 +2127,26 @@ bool LLInventoryModel::loadSkeleton( // category with a correctly cached parent count = items.count(); cat_map_t::iterator unparented = mCategoryMap.end(); - for(int i = 0; i < count; ++i) + for(item_array_t::const_iterator item_iter = items.begin(); + item_iter != items.end(); + ++item_iter) { - cat_map_t::iterator cit = mCategoryMap.find(items[i]->getParentUUID()); + LLViewerInventoryItem *item = (*item_iter).get(); + const cat_map_t::iterator cit = mCategoryMap.find(item->getParentUUID()); if(cit != unparented) { - LLViewerInventoryCategory* cat = cit->second; + const LLViewerInventoryCategory* cat = cit->second.get(); if(cat->getVersion() != NO_VERSION) { - addItem(items[i]); + // This can happen if the linked object's baseobj is removed from the cache but the linked object is still in the cache. + if (item->getIsBrokenLink()) + { + llinfos << "Attempted to cached link item without baseobj present ( itemID: " << item->getUUID() << " assetID: " << item->getAssetUUID() << " ) " << llendl; + invalid_categories.insert(cit->second); + continue; + } + addItem(item); cached_item_count += 1; ++child_counts[cat->getUUID()]; } @@ -2049,14 +2168,13 @@ bool LLInventoryModel::loadSkeleton( // At this point, we need to set the known descendents for each // category which successfully cached so that we do not // needlessly fetch descendents for categories which we have. - update_map_t::iterator no_child_counts = child_counts.end(); - update_map_t::iterator the_count; + update_map_t::const_iterator no_child_counts = child_counts.end(); for(cat_set_t::iterator it = temp_cats.begin(); it != temp_cats.end(); ++it) { - LLViewerInventoryCategory* cat = (*it); + LLViewerInventoryCategory* cat = (*it).get(); if(cat->getVersion() != NO_VERSION) { - the_count = child_counts.find(cat->getUUID()); + update_map_t::const_iterator the_count = child_counts.find(cat->getUUID()); if(the_count != no_child_counts) { cat->setDescendentCount((*the_count).second.mValue); @@ -2068,6 +2186,17 @@ bool LLInventoryModel::loadSkeleton( } } + // Invalidate all categories that failed fetching descendents for whatever + // reason (e.g. one of the descendents was a broken link). + for (cat_set_t::iterator invalid_cat_it = invalid_categories.begin(); + invalid_cat_it != invalid_categories.end(); + invalid_cat_it++) + { + LLViewerInventoryCategory* cat = (*invalid_cat_it).get(); + cat->setVersion(NO_VERSION); + llinfos << "Invalidating category name: " << cat->getName() << " UUID: " << cat->getUUID() << " due to invalid descendents cache" << llendl; + } + if(remove_inventory_file) { // clean up the gunzipped file. @@ -2252,7 +2381,7 @@ void LLInventoryModel::buildParentChildMap() else { // it's a protected folder. - cat->setParent(gAgent.getInventoryRootID()); + cat->setParent(gInventory.getRootFolderID()); } cat->updateServer(TRUE); catsp = getUnlockedCatArray(cat->getParentUUID()); @@ -2352,7 +2481,7 @@ void LLInventoryModel::buildParentChildMap() } } - const LLUUID& agent_inv_root_id = gAgent.getInventoryRootID(); + LLUUID agent_inv_root_id = gInventory.getRootFolderID(); if (agent_inv_root_id.notNull()) { cat_array_t* catsp = get_ptr_in_map(mParentChildCategoryTree, agent_inv_root_id); @@ -2802,7 +2931,7 @@ void LLInventoryModel::processUpdateInventoryFolder(LLMessageSystem* msg, gInventory.notifyObservers(); // *HACK: Do the 'show' logic for a new item in the inventory. - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); if(view) { view->getPanel()->setSelection(lastfolder->getUUID(), TAKE_FOCUS_NO); @@ -3011,13 +3140,13 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // The incoming inventory could span more than one BulkInventoryUpdate packet, // so record the transaction ID for this purchase, then wear all clothing // that comes in as part of that transaction ID. JC - if (LLInventoryView::sWearNewClothing) + if (LLFloaterInventory::sWearNewClothing) { - LLInventoryView::sWearNewClothingTransactionID = tid; - LLInventoryView::sWearNewClothing = FALSE; + LLFloaterInventory::sWearNewClothingTransactionID = tid; + LLFloaterInventory::sWearNewClothing = FALSE; } - if (tid == LLInventoryView::sWearNewClothingTransactionID) + if (tid == LLFloaterInventory::sWearNewClothingTransactionID) { count = wearable_ids.size(); for (i = 0; i < count; ++i) @@ -3035,7 +3164,7 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) gInventoryCallbacks.fire(cbinfo.mCallback, cbinfo.mInvID); } // Don't show the inventory. We used to call showAgentInventory here. - //LLInventoryView* view = LLInventoryView::getActiveInventory(); + //LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); //if(view) //{ // const BOOL take_keyboard_focus = FALSE; @@ -3045,10 +3174,10 @@ void LLInventoryModel::processBulkUpdateInventory(LLMessageSystem* msg, void**) // // HACK to open inventory offers that are accepted. This information // // really needs to flow through the instant messages and inventory // // transfer/update messages. - // if (LLInventoryView::sOpenNextNewItem) + // if (LLFloaterInventory::sOpenNextNewItem) // { // view->openSelected(); - // LLInventoryView::sOpenNextNewItem = FALSE; + // LLFloaterInventory::sOpenNextNewItem = FALSE; // } // // // restore keyboard focus @@ -3158,6 +3287,93 @@ void LLInventoryModel::processMoveInventoryItem(LLMessageSystem* msg, void**) } } +//---------------------------------------------------------------------------- + +// Trash: LLAssetType::AT_TRASH, "ConfirmEmptyTrash" +// Lost&Found: LLAssetType::AT_LOST_AND_FOUND, "ConfirmEmptyLostAndFound" + +bool LLInventoryModel::callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLAssetType::EType folder_type) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if (option == 0) // YES + { + LLUUID folder_id = findCategoryUUIDForType(folder_type); + purgeDescendentsOf(folder_id); + notifyObservers(); + } + return false; +} + +void LLInventoryModel::emptyFolderType(const std::string notification, LLAssetType::EType folder_type) +{ + if (!notification.empty()) + { + LLNotifications::instance().add(notification, LLSD(), LLSD(), + boost::bind(&LLInventoryModel::callbackEmptyFolderType, this, _1, _2, folder_type)); + } + else + { + LLUUID folder_id = findCategoryUUIDForType(folder_type); + purgeDescendentsOf(folder_id); + notifyObservers(); + } +} + +//---------------------------------------------------------------------------- + +void LLInventoryModel::removeItem(const LLUUID& item_id) +{ + LLViewerInventoryItem* item = getItem(item_id); + const LLUUID& new_parent = findCategoryUUIDForType(LLAssetType::AT_TRASH); + if (item && item->getParentUUID() != new_parent) + { + LLInventoryModel::update_list_t update; + LLInventoryModel::LLCategoryUpdate old_folder(item->getParentUUID(),-1); + update.push_back(old_folder); + LLInventoryModel::LLCategoryUpdate new_folder(new_parent, 1); + update.push_back(new_folder); + accountForUpdate(update); + + LLPointer new_item = new LLViewerInventoryItem(item); + new_item->setParent(new_parent); + new_item->updateParentOnServer(TRUE); + updateItem(new_item); + notifyObservers(); + } +} + +LLUUID LLInventoryModel::getRootFolderID() const +{ + return mRootFolderID; +} + +void LLInventoryModel::setRootFolderID(const LLUUID& val) +{ + mRootFolderID = val; +} + +LLUUID LLInventoryModel::getLibraryRootFolderID() const +{ + return mLibraryRootFolderID; +} + +void LLInventoryModel::setLibraryRootFolderID(const LLUUID& val) +{ + mLibraryRootFolderID = val; +} + +LLUUID LLInventoryModel::getLibraryOwnerID() const +{ + return mLibraryOwnerID; +} + +void LLInventoryModel::setLibraryOwnerID(const LLUUID& val) +{ + mLibraryOwnerID = val; +} + +//---------------------------------------------------------------------------- + // *NOTE: DEBUG functionality void LLInventoryModel::dumpInventory() { @@ -3205,7 +3421,7 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* ite return false; bool allowed = false; - LLVOAvatar* my_avatar = NULL; + LLVOAvatarSelf* my_avatar = NULL; switch(item->getType()) { @@ -3223,7 +3439,7 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(LLInventoryItem* ite case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: - if(!gAgent.isWearingItem(item->getUUID())) + if(!gAgentWearables.isWearingItem(item->getUUID())) { allowed = true; } @@ -3887,11 +4103,20 @@ void LLInventoryTransactionObserver::changed(U32 mask) ///---------------------------------------------------------------------------- /// LLAssetIDMatches ///---------------------------------------------------------------------------- -bool LLAssetIDMatches ::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +bool LLAssetIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { return (item && item->getAssetUUID() == mAssetID); } +///---------------------------------------------------------------------------- +/// LLLinkedItemIDMatches +///---------------------------------------------------------------------------- +bool LLLinkedItemIDMatches::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + return (item && + (item->getIsLinkType()) && + (item->getLinkedUUID() == mBaseItemID)); // A linked item's assetID will be the compared-to item's itemID. +} ///---------------------------------------------------------------------------- /// Local function definitions diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index d73fef7207..2ddc35b9ef 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -35,6 +35,8 @@ #include "llassettype.h" #include "lldarray.h" +#include "llframetimer.h" +#include "llhttpclient.h" #include "lluuid.h" #include "llpermissionsflags.h" #include "llstring.h" @@ -111,11 +113,12 @@ public: LLInventoryModel(); ~LLInventoryModel(); - class fetchInventoryResponder: public LLHTTPClient::Responder + class fetchInventoryResponder : public LLHTTPClient::Responder { public: fetchInventoryResponder(const LLSD& request_sd) : mRequestSD(request_sd) {}; void result(const LLSD& content); + void error(U32 status, const std::string& reason); public: @@ -167,7 +170,7 @@ public: item_array_t*& items); void unlockDirectDescendentArrays(const LLUUID& cat_id); - // Starting with the object specified, add it's descendents to the + // Starting with the object specified, add its descendents to the // array provided, but do not add the inventory object specified // by id. There is no guaranteed order. Neither array will be // erased before adding objects to it. Do not store a copy of the @@ -178,14 +181,20 @@ public: cat_array_t& categories, item_array_t& items, BOOL include_trash); - void collectDescendentsIf(const LLUUID& id, cat_array_t& categories, item_array_t& items, BOOL include_trash, - LLInventoryCollectFunctor& add); + LLInventoryCollectFunctor& add, + BOOL follow_folder_links = FALSE); + + // Collect all items in inventory that are linked to item_id. + // Assumes item_id is itself not a linked item. + void collectLinkedItems(const LLUUID& item_id, + item_array_t& items); + // Updates all linked objects pointing to this id. + void updateLinkedObjects(const LLUUID& object_id); - // This method will return false if this inventory model is in an usabel state. // The inventory model usage is sensitive to the initial construction of the // model. bool isInventoryUsable(); @@ -197,7 +206,7 @@ public: // Calling this method with an inventory item will either change // an existing item with a matching item_id, or will add the item // to the current inventory. Returns the change mask generated by - // the update. No notifcation will be sent to observers. This + // the update. No notification will be sent to observers. This // method will only generate network traffic if the item had to be // reparented. // *NOTE: In usage, you will want to perform cache accounting @@ -224,16 +233,21 @@ public: // delete a particular inventory object by ID. This will purge one // object from the internal data structures maintaining a - // cosistent internal state. No cache accounting, observer - // notification, or server update is performed. + // consistent internal state. No cache accounting, observer + // notification, or server update is performed. Purges linked items. void deleteObject(const LLUUID& id); + + // delete a particular inventory object by ID, and delete it from + // the server. Also purges linked items via purgeLinkedObjects. + void purgeObject(const LLUUID& id); + void purgeLinkedObjects(const LLUUID& id); - // This is a method which collects the descendents of the id + // This is a method which collects the descendants of the id // provided. If the category is not found, no action is // taken. This method goes through the long winded process of // removing server representation of folders and items while doing // cache accounting in a fairly efficient manner. This method does - // not notify observers (though maybe it shouldd...) + // not notify observers (though maybe it should...) void purgeDescendentsOf(const LLUUID& id); // This method optimally removes the referenced categories and @@ -283,8 +297,9 @@ public: // minimal functionality before the actual arrival of inventory. //void mock(const LLUUID& root_id); - // make sure we have the descendents in the structure. - void fetchDescendentsOf(const LLUUID& folder_id); + // Make sure we have the descendents in the structure. Returns true + // if a fetch was performed. + bool fetchDescendentsOf(const LLUUID& folder_id); // Add categories to a list to be fetched in bulk. static void bulkFetch(std::string url); @@ -365,7 +380,15 @@ public: // returns true iff category version is known and theoretical // descendents == actual descendents. bool isCategoryComplete(const LLUUID& cat_id) const; + + // callbacks + // Trigger a notification and empty the folder type (AT_TRASH or AT_LOST_AND_FOUND) if confirmed + void emptyFolderType(const std::string notification, LLAssetType::EType folder_type); + bool callbackEmptyFolderType(const LLSD& notification, const LLSD& response, LLAssetType::EType folder_type); + // Utility Functions + void removeItem(const LLUUID& item_id); + // start and stop background breadth-first fetching of inventory contents // this gets triggered when performing a filter-search static void startBackgroundFetch(const LLUUID& cat_id = LLUUID::null); // start fetch process @@ -374,6 +397,22 @@ public: static bool isEverythingFetched(); static void backgroundFetch(void*); // background fetch idle function static void incrBulkFetch(S16 fetching) { sBulkFetchCount+=fetching; if (sBulkFetchCount<0) sBulkFetchCount=0; } + + + // Data about the agent's root folder and root library folder + // are stored here, rather than in LLAgent where it used to be, because + // gInventory is a singleton and represents the agent's inventory. + // The "library" is actually the inventory of a special agent, + // usually Alexandria Linden. + LLUUID getRootFolderID() const; + LLUUID getLibraryOwnerID() const; + LLUUID getLibraryRootFolderID() const; + + // These are set during login with data from the server + void setRootFolderID(const LLUUID& id); + void setLibraryOwnerID(const LLUUID& id); + void setLibraryRootFolderID(const LLUUID& id); + protected: // Internal methods which add inventory and make sure that all of @@ -426,7 +465,7 @@ protected: item_array_t* getUnlockedItemArray(const LLUUID& id); protected: - // Varaibles used to track what has changed since the last notify. + // Variables used to track what has changed since the last notify. U32 mModifyMask; typedef std::set changed_items_t; changed_items_t mChangedItemIDs; @@ -457,6 +496,11 @@ protected: typedef std::set observer_list_t; observer_list_t mObservers; + // Agent inventory folder information. + LLUUID mRootFolderID; + LLUUID mLibraryRootFolderID; + LLUUID mLibraryOwnerID; + // completing the fetch once per session should be sufficient static BOOL sBackgroundFetchActive; static BOOL sTimelyFetchPending; @@ -520,6 +564,22 @@ protected: LLUUID mAssetID; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLLinkedItemIDMatches +// +// This functor finds inventory items linked to the specific inventory id. +// Assumes the inventory id is itself not a linked item. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLLinkedItemIDMatches : public LLInventoryCollectFunctor +{ +public: + LLLinkedItemIDMatches(const LLUUID& item_id) : mBaseItemID(item_id) {} + virtual ~LLLinkedItemIDMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); + +protected: + LLUUID mBaseItemID; +}; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIsType @@ -666,6 +726,20 @@ protected: std::string mName; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLFindWearables +// +// Collects wearables based on item type. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLFindWearables : public LLInventoryCollectFunctor +{ +public: + LLFindWearables() {} + virtual ~LLFindWearables() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLInventoryCompletionObserver diff --git a/indra/newview/lljoystickbutton.cpp b/indra/newview/lljoystickbutton.cpp index 326c511fcf..efc03b3d88 100644 --- a/indra/newview/lljoystickbutton.cpp +++ b/indra/newview/lljoystickbutton.cpp @@ -42,15 +42,19 @@ // Project includes #include "llui.h" #include "llagent.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llmoveview.h" #include "llglheaders.h" -static LLRegisterWidget r1("joystick_slide"); -static LLRegisterWidget r2("joystick_turn"); +static LLDefaultChildRegistry::Register r1("joystick_slide"); +static LLDefaultChildRegistry::Register r2("joystick_turn"); +static LLDefaultChildRegistry::Register r3("joystick_rotate"); +static LLDefaultChildRegistry::Register r4("joystick_zoom"); +static LLDefaultChildRegistry::Register r5("joystick_track"); + const F32 NUDGE_TIME = 0.25f; // in seconds @@ -59,15 +63,18 @@ const F32 ORBIT_NUDGE_RATE = 0.05f; // fraction of normal speed // // Public Methods // -LLJoystick::LLJoystick( - const std::string& name, - LLRect rect, - const std::string &default_image, - const std::string &selected_image, - EJoystickQuadrant initial_quadrant ) - : - LLButton(name, rect, default_image, selected_image, LLStringUtil::null, NULL, NULL), - mInitialQuadrant(initial_quadrant), +void QuadrantNames::declareValues() +{ + declare("origin", JQ_ORIGIN); + declare("up", JQ_UP); + declare("down", JQ_DOWN); + declare("left", JQ_LEFT); + declare("right", JQ_RIGHT); +} + + +LLJoystick::LLJoystick(const LLJoystick::Params& p) +: LLButton(p), mInitialOffset(0, 0), mLastMouse(0, 0), mFirstMouse(0, 0), @@ -76,10 +83,10 @@ LLJoystick::LLJoystick( mHorizSlopNear(0), mHorizSlopFar(0), mHeldDown(FALSE), - mHeldDownTimer() + mHeldDownTimer(), + mInitialQuadrant(p.quadrant) { - setHeldDownCallback(&LLJoystick::onHeldDown); - setCallbackUserData(this); + setHeldDownCallback(&LLJoystick::onBtnHeldDown, this); } @@ -178,16 +185,14 @@ F32 LLJoystick::getElapsedHeldDownTime() } // static -void LLJoystick::onHeldDown(void *userdata) +void LLJoystick::onBtnHeldDown(void *userdata) { LLJoystick *self = (LLJoystick *)userdata; - - // somebody removed this function without checking the - // build. Removed 2007-03-26. - //llassert( gViewerWindow->hasMouseCapture( self ) ); - - self->mHeldDown = TRUE; - self->onHeldDown(); + if (self) + { + self->mHeldDown = TRUE; + self->onHeldDown(); + } } EJoystickQuadrant LLJoystick::selectQuadrant(LLXMLNodePtr node) @@ -246,23 +251,6 @@ EJoystickQuadrant LLJoystick::quadrantFromName(const std::string& sQuadrant) } -LLXMLNodePtr LLJoystick::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("halign", TRUE)->setStringValue(LLFontGL::nameFromHAlign(getHAlign())); - node->createChild("quadrant", TRUE)->setStringValue(nameFromQuadrant(mInitialQuadrant)); - - addImageAttributeToXML(node,getImageUnselectedName(),getImageUnselectedID(),std::string("image_unselected")); - addImageAttributeToXML(node,getImageSelectedName(),getImageSelectedID(),std::string("image_selected")); - - node->createChild("scale_image", TRUE)->setBoolValue(getScaleImage()); - - return node; -} - - - //------------------------------------------------------------------------------- // LLJoystickAgentTurn //------------------------------------------------------------------------------- @@ -327,46 +315,6 @@ void LLJoystickAgentTurn::onHeldDown() } } -LLView* LLJoystickAgentTurn::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("button"); - node->getAttributeString("name", name); - - std::string image_unselected; - if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected); - - std::string image_selected; - if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected); - - EJoystickQuadrant quad = JQ_ORIGIN; - if (node->hasAttribute("quadrant")) quad = selectQuadrant(node); - - LLJoystickAgentTurn *button = new LLJoystickAgentTurn(name, - LLRect(), - image_unselected, - image_selected, - quad); - - if (node->hasAttribute("halign")) - { - LLFontGL::HAlign halign = selectFontHAlign(node); - button->setHAlign(halign); - } - - if (node->hasAttribute("scale_image")) - { - BOOL needsScale = FALSE; - node->getAttributeBOOL("scale_image",needsScale); - button->setScaleImage( needsScale ); - } - - button->initFromXML(node, parent); - - return button; -} - - - //------------------------------------------------------------------------------- // LLJoystickAgentSlide //------------------------------------------------------------------------------- @@ -435,54 +383,12 @@ void LLJoystickAgentSlide::onHeldDown() } -// static -LLView* LLJoystickAgentSlide::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("button"); - node->getAttributeString("name", name); - - std::string image_unselected; - if (node->hasAttribute("image_unselected")) node->getAttributeString("image_unselected",image_unselected); - - std::string image_selected; - if (node->hasAttribute("image_selected")) node->getAttributeString("image_selected",image_selected); - - - EJoystickQuadrant quad = JQ_ORIGIN; - if (node->hasAttribute("quadrant")) quad = selectQuadrant(node); - - LLJoystickAgentSlide *button = new LLJoystickAgentSlide(name, - LLRect(), - image_unselected, - image_selected, - quad); - - if (node->hasAttribute("halign")) - { - LLFontGL::HAlign halign = selectFontHAlign(node); - button->setHAlign(halign); - } - - if (node->hasAttribute("scale_image")) - { - BOOL needsScale = FALSE; - node->getAttributeBOOL("scale_image",needsScale); - button->setScaleImage( needsScale ); - } - - button->initFromXML(node, parent); - - return button; -} - - //------------------------------------------------------------------------------- // LLJoystickCameraRotate //------------------------------------------------------------------------------- -LLJoystickCameraRotate::LLJoystickCameraRotate(const std::string& name, LLRect rect, const std::string &out_img, const std::string &in_img) - : - LLJoystick(name, rect, out_img, in_img, JQ_ORIGIN), +LLJoystickCameraRotate::LLJoystickCameraRotate(const LLJoystickCameraRotate::Params& p) +: LLJoystick(p), mInLeft( FALSE ), mInTop( FALSE ), mInRight( FALSE ), @@ -636,10 +542,17 @@ void LLJoystickCameraRotate::draw() { drawDebugRect(); } + + //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) + //std::set::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); + //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) + //{ + // drawDebugRect(); + //} } // Draws image rotated by multiples of 90 degrees -void LLJoystickCameraRotate::drawRotatedImage( LLImageGL* image, S32 rotations ) +void LLJoystickCameraRotate::drawRotatedImage( LLTexture* image, S32 rotations ) { S32 width = image->getWidth(); S32 height = image->getHeight(); @@ -679,6 +592,15 @@ void LLJoystickCameraRotate::drawRotatedImage( LLImageGL* image, S32 rotations ) // LLJoystickCameraTrack //------------------------------------------------------------------------------- +LLJoystickCameraTrack::Params::Params() +{ + held_down_delay.seconds(0.0); +} + +LLJoystickCameraTrack::LLJoystickCameraTrack(const LLJoystickCameraTrack::Params& p) +: LLJoystickCameraRotate(p) +{} + void LLJoystickCameraTrack::onHeldDown() { @@ -717,17 +639,15 @@ void LLJoystickCameraTrack::onHeldDown() // LLJoystickCameraZoom //------------------------------------------------------------------------------- -LLJoystickCameraZoom::LLJoystickCameraZoom(const std::string& name, LLRect rect, const std::string &out_img, const std::string &plus_in_img, const std::string &minus_in_img) - : - LLJoystick(name, rect, out_img, LLStringUtil::null, JQ_ORIGIN), +LLJoystickCameraZoom::LLJoystickCameraZoom(const LLJoystickCameraZoom::Params& p) +: LLJoystick(p), mInTop( FALSE ), - mInBottom( FALSE ) + mInBottom( FALSE ), + mPlusInImage(p.plus_image), + mMinusInImage(p.minus_image) { - mPlusInImage = LLUIImageList::getInstance()->getUIImage(plus_in_img); - mMinusInImage = LLUIImageList::getInstance()->getUIImage(minus_in_img); } - BOOL LLJoystickCameraZoom::handleMouseDown(S32 x, S32 y, MASK mask) { BOOL handled = LLJoystick::handleMouseDown(x, y, mask); @@ -808,6 +728,13 @@ void LLJoystickCameraZoom::draw() { drawDebugRect(); } + + //// *HACK: also draw debug rectangles around currently-being-edited LLView, and any elements that are being highlighted by GUI preview code (see LLFloaterUIPreview) + //std::set::iterator iter = std::find(sPreviewHighlightedElements.begin(), sPreviewHighlightedElements.end(), this); + //if ((sEditingUI && this == sEditingUIView) || (iter != sPreviewHighlightedElements.end() && sDrawPreviewHighlights)) + //{ + // drawDebugRect(); + //} } void LLJoystickCameraZoom::updateSlop() diff --git a/indra/newview/lljoystickbutton.h b/indra/newview/lljoystickbutton.h index 076a506f14..8caef30fa4 100644 --- a/indra/newview/lljoystickbutton.h +++ b/indra/newview/lljoystickbutton.h @@ -35,7 +35,7 @@ #include "llbutton.h" #include "llcoord.h" -#include "llviewerimage.h" +#include "llviewertexture.h" typedef enum e_joystick_quadrant { @@ -46,11 +46,27 @@ typedef enum e_joystick_quadrant JQ_RIGHT } EJoystickQuadrant; +struct QuadrantNames : public LLInitParam::TypeValuesHelper +{ + static void declareValues(); +}; + class LLJoystick : public LLButton { public: - LLJoystick(const std::string& name, LLRect rect, const std::string &default_image, const std::string &selected_image, EJoystickQuadrant initial); + struct Params + : public LLInitParam::Block + { + Optional quadrant; + + Params() + : quadrant("quadrant", JQ_ORIGIN) + { + label = ""; + } + }; + LLJoystick(const Params&); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); @@ -60,10 +76,9 @@ public: virtual void onHeldDown() = 0; F32 getElapsedHeldDownTime(); - static void onHeldDown(void *userdata); // called by llbutton callback handler + static void onBtnHeldDown(void *userdata); // called by llbutton callback handler void setInitialQuadrant(EJoystickQuadrant initial) { mInitialQuadrant = initial; }; - virtual LLXMLNodePtr getXML(bool save_children = true) const; static std::string nameFromQuadrant(const EJoystickQuadrant quadrant); static EJoystickQuadrant quadrantFromName(const std::string& name); static EJoystickQuadrant selectQuadrant(LLXMLNodePtr node); @@ -91,14 +106,9 @@ class LLJoystickAgentTurn : public LLJoystick { public: - LLJoystickAgentTurn(const std::string& name, LLRect rect, const std::string &default_image, const std::string &selected_image, EJoystickQuadrant initial) - : LLJoystick(name, rect, default_image, selected_image, initial) - { } - + struct Params : public LLJoystick::Params {}; + LLJoystickAgentTurn(const Params& p) : LLJoystick(p) {} virtual void onHeldDown(); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - }; @@ -107,14 +117,11 @@ class LLJoystickAgentSlide : public LLJoystick { public: - LLJoystickAgentSlide(const std::string& name, LLRect rect, const std::string &default_image, const std::string &selected_image, EJoystickQuadrant initial) - : LLJoystick(name, rect, default_image, selected_image, initial) - { } - + struct Params : public LLJoystick::Params {}; + LLJoystickAgentSlide(const Params& p) : LLJoystick(p) {} + virtual void onHeldDown(); virtual void onMouseUp(); - - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); }; @@ -123,7 +130,16 @@ class LLJoystickCameraRotate : public LLJoystick { public: - LLJoystickCameraRotate(const std::string& name, LLRect rect, const std::string &out_img, const std::string &in_img); + struct Params + : public LLInitParam::Block + { + Params() + { + held_down_delay.seconds(0.0); + } + }; + + LLJoystickCameraRotate(const LLJoystickCameraRotate::Params&); virtual void setToggleState( BOOL left, BOOL top, BOOL right, BOOL bottom ); @@ -134,7 +150,7 @@ public: protected: F32 getOrbitRate(); virtual void updateSlop(); - void drawRotatedImage( LLImageGL* image, S32 rotations ); + void drawRotatedImage( LLTexture* image, S32 rotations ); protected: BOOL mInLeft; @@ -149,10 +165,13 @@ class LLJoystickCameraTrack : public LLJoystickCameraRotate { public: - LLJoystickCameraTrack(const std::string& name, LLRect rect, const std::string &out_img, const std::string &in_img) - : LLJoystickCameraRotate(name, rect, out_img, in_img) - { } + struct Params + : public LLInitParam::Block + { + Params(); + }; + LLJoystickCameraTrack(const LLJoystickCameraTrack::Params&); virtual void onHeldDown(); }; @@ -162,7 +181,20 @@ class LLJoystickCameraZoom : public LLJoystick { public: - LLJoystickCameraZoom(const std::string& name, LLRect rect, const std::string &out_img, const std::string &plus_in_img, const std::string &minus_in_img); + struct Params + : public LLInitParam::Block + { + Optional plus_image; + Optional minus_image; + + Params() + : plus_image ("plus_image", NULL), + minus_image ("minus_image", NULL) + { + held_down_delay.seconds(0.0); + } + }; + LLJoystickCameraZoom(const Params&); virtual void setToggleState( BOOL top, BOOL bottom ); diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp new file mode 100644 index 0000000000..df9aa32d1b --- /dev/null +++ b/indra/newview/lllandmarkactions.cpp @@ -0,0 +1,299 @@ +/** +* @file lllandmarkactions.cpp +* @brief LLLandmarkActions class implementation +* +* $LicenseInfo:firstyear=2001&license=viewergpl$ +* +* Copyright (c) 2001-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "lllandmarkactions.h" + +#include "roles_constants.h" + +#include "llinventory.h" +#include "lllandmark.h" +#include "llparcel.h" + +#include "llnotifications.h" + +#include "llagent.h" +#include "llinventorymodel.h" +#include "lllandmarklist.h" +#include "llslurl.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llworldmap.h" +#include "lllandmark.h" +#include "llinventorymodel.h" +#include "llagentui.h" + +// Returns true if the given inventory item is a landmark pointing to the current parcel. +// Used to filter inventory items. +class LLIsAgentParcelLandmark : public LLInventoryCollectFunctor +{ +public: + /*virtual*/ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + return false; + + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return false; + + return LLViewerParcelMgr::getInstance()->inAgentParcel(landmark_global_pos); + } +}; + +class LLFetchLandmarksByName : public LLInventoryCollectFunctor +{ +private: + std::string name; + BOOL use_substring; + //this member will be contain copy of founded items to keep the result unique + std::set check_duplicate; + +public: +LLFetchLandmarksByName(std::string &landmark_name, BOOL if_use_substring) +:name(landmark_name), +use_substring(if_use_substring) + { + LLStringUtil::toLower(name); + } + +public: + /*virtual*/ bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) + { + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + return false; + + LLLandmark* landmark = gLandmarkList.getAsset(item->getAssetUUID()); + if (!landmark) // the landmark not been loaded yet + return false; + + bool acceptable = false; + std::string landmark_name = item->getName(); + LLStringUtil::toLower(landmark_name); + if(use_substring) + { + acceptable = landmark_name.find( name ) != std::string::npos; + } + else + { + acceptable = landmark_name == name; + } + if(acceptable){ + if(check_duplicate.find(landmark_name) != check_duplicate.end()){ + // we have duplicated items in landmarks + acceptable = false; + }else{ + check_duplicate.insert(landmark_name); + } + } + + return acceptable; + } +}; + +LLInventoryModel::item_array_t LLLandmarkActions::fetchLandmarksByName(std::string& name, BOOL use_substring) +{ + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLFetchLandmarksByName fetchLandmarks(name, use_substring); + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + fetchLandmarks); + return items; +} + +bool LLLandmarkActions::landmarkAlreadyExists() +{ + // Determine whether there are landmarks pointing to the current parcel. + LLInventoryModel::item_array_t items; + collectParcelLandmark(items); + return !items.empty(); +} + + +LLViewerInventoryItem* LLLandmarkActions::findLandmarkForAgentParcel() +{ + // Determine whether there are landmarks pointing to the current parcel. + LLInventoryModel::cat_array_t cats; + LLInventoryModel::item_array_t items; + LLIsAgentParcelLandmark is_current_parcel_landmark; + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_current_parcel_landmark); + + if(items.empty()) + { + return NULL; + } + + return items[0]; +} + +bool LLLandmarkActions::canCreateLandmarkHere() +{ + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if(!agent_parcel) + { + llwarns << "No agent region" << llendl; + return false; + } + if (agent_parcel->getAllowLandmark() + || LLViewerParcelMgr::isParcelOwnedByAgent(agent_parcel, GP_LAND_ALLOW_LANDMARK)) + { + return true; + } + + return false; +} + +void LLLandmarkActions::createLandmarkHere( + const std::string& name, + const std::string& desc, + const LLUUID& folder_id) +{ + if(!gAgent.getRegion()) + { + llwarns << "No agent region" << llendl; + return; + } + LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!agent_parcel) + { + llwarns << "No agent parcel" << llendl; + return; + } + if (!canCreateLandmarkHere()) + { + LLNotifications::instance().add("CannotCreateLandmarkNotOwner"); + return; + } + + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + folder_id, LLTransactionID::tnull, + name, desc, + LLAssetType::AT_LANDMARK, + LLInventoryType::IT_LANDMARK, + NOT_WEARABLE, PERM_ALL, + NULL); +} + +void LLLandmarkActions::createLandmarkHere() +{ + std::string landmark_name, landmark_desc; + + LLAgentUI::buildLocationString(landmark_name, LLAgentUI::LOCATION_FORMAT_LANDMARK); + LLAgentUI::buildLocationString(landmark_desc, LLAgentUI::LOCATION_FORMAT_FULL); + LLUUID folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); + + createLandmarkHere(landmark_name, landmark_desc, folder_id); +} + +void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slurl_callback_t cb, bool escaped /* = true */) +{ + std::string sim_name; + bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name); + if (gotSimName) + { + std::string slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped); + cb(slurl); + + return; + } + else + { + U64 new_region_handle = to_region_handle(global_pos); + + LLWorldMap::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponse, + cb, + global_pos, + escaped, + _1, _2, _3, _4); + + LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false); + } +} + +void LLLandmarkActions::onRegionResponse(slurl_callback_t cb, + const LLVector3d& global_pos, + bool escaped, + U64 region_handle, + const std::string& url, + const LLUUID& snapshot_id, + bool teleport) +{ + std::string sim_name; + std::string slurl; + bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal(global_pos, sim_name); + if (gotSimName) + { + slurl = LLSLURL::buildSLURLfromPosGlobal(sim_name, global_pos, escaped); + } + else + { + slurl = ""; + } + + cb(slurl); +} + +bool LLLandmarkActions::getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal) +{ + LLViewerInventoryItem* item = gInventory.getItem(landmarkInventoryItemID); + if (NULL == item) + return false; + + const LLUUID& asset_id = item->getAssetUUID(); + LLLandmark* landmark = gLandmarkList.getAsset(asset_id, NULL); + + if (NULL == landmark) + return false; + + return landmark->getGlobalPos(posGlobal); +} + +void LLLandmarkActions::collectParcelLandmark(LLInventoryModel::item_array_t& items){ + LLInventoryModel::cat_array_t cats; + LLIsAgentParcelLandmark is_current_parcel_landmark; + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_current_parcel_landmark); +} diff --git a/indra/newview/lllandmarkactions.h b/indra/newview/lllandmarkactions.h new file mode 100644 index 0000000000..c74072c0f4 --- /dev/null +++ b/indra/newview/lllandmarkactions.h @@ -0,0 +1,116 @@ +/** + * @file lllandmarkactions.h + * @brief LLLandmark class declaration + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLLANDMARKACTIONS_H +#define LL_LLLANDMARKACTIONS_H + +#include "llinventorymodel.h" + +/** + * @brief Provides helper functions to manage landmarks + */ +class LLLandmarkActions +{ +public: + typedef boost::function slurl_callback_t; + + /** + * @brief Fetches landmark LLViewerInventoryItems for the given landmark name. + */ + static LLInventoryModel::item_array_t fetchLandmarksByName(std::string& name, BOOL if_use_substring); + /** + * @brief Checks whether landmark exists for current parcel. + */ + static bool landmarkAlreadyExists(); + + /** + * @brief Searches landmark for parcel agent is currently in. + * @return Returns landmark for agent parcel or NULL. + * + * *TODO: dzaporozhan: There can be many landmarks for single parcel. + */ + static LLViewerInventoryItem* findLandmarkForAgentParcel(); + + /** + * @brief Checks whether agent has rights to create landmark for current parcel. + */ + static bool canCreateLandmarkHere(); + + /** + * @brief Creates landmark for current parcel. + */ + static void createLandmarkHere(); + + /** + * @brief Creates landmark for current parcel. + */ + static void createLandmarkHere( + const std::string& name, + const std::string& desc, + const LLUUID& folder_id); + + /** + * @brief Trying to find in inventory a landmark of the current parcel. + * Normally items should contain only one item, + * because we can create the only landmark per parcel according to Navigation spec. + */ + static void collectParcelLandmark(LLInventoryModel::item_array_t& items); + + /** + * @brief Creates SLURL for given global position. + */ + static void getSLURLfromPosGlobal(const LLVector3d& global_pos, slurl_callback_t cb, bool escaped = true); + + /** + * @brief Gets landmark global position specified by inventory LLUUID. + * Found position is placed into "posGlobal" variable. + *. + * @return - true if specified item exists in Inventory and an appropriate landmark found. + * and its position is known, false otherwise. + */ + // *TODO: mantipov: profide callback for cases, when Landmark is not loaded yet. + static bool getLandmarkGlobalPos(const LLUUID& landmarkInventoryItemID, LLVector3d& posGlobal); + +private: + LLLandmarkActions(); + LLLandmarkActions(const LLLandmarkActions&); + + static void onRegionResponse(slurl_callback_t cb, + const LLVector3d& global_pos, + bool escaped, + U64 region_handle, + const std::string& url, + const LLUUID& snapshot_id, + bool teleport); +}; + +#endif //LL_LLLANDMARKACTIONS_H diff --git a/indra/newview/lllandmarklist.cpp b/indra/newview/lllandmarklist.cpp index 2f43b41042..318344f9ef 100644 --- a/indra/newview/lllandmarklist.cpp +++ b/indra/newview/lllandmarklist.cpp @@ -54,7 +54,7 @@ LLLandmarkList::~LLLandmarkList() std::for_each(mList.begin(), mList.end(), DeletePairedPointer()); } -LLLandmark* LLLandmarkList::getAsset( const LLUUID& asset_uuid ) +LLLandmark* LLLandmarkList::getAsset(const LLUUID& asset_uuid, loaded_callback_t cb) { LLLandmark* landmark = get_ptr_in_map(mList, asset_uuid); if(landmark) @@ -65,6 +65,12 @@ LLLandmark* LLLandmarkList::getAsset( const LLUUID& asset_uuid ) { if ( gLandmarkList.mBadList.find(asset_uuid) == gLandmarkList.mBadList.end() ) { + if (cb) + { + loaded_callback_map_t::value_type vt(asset_uuid, cb); + mLoadedCallbackMap.insert(vt); + } + gAssetStorage->getAssetData( asset_uuid, LLAssetType::AT_LANDMARK, @@ -96,6 +102,8 @@ void LLLandmarkList::processGetAssetReply( LLLandmark* landmark = LLLandmark::constructFromString(&buffer[0]); if (landmark) { + gLandmarkList.mList[ uuid ] = landmark; + LLVector3d pos; if(!landmark->getGlobalPos(pos)) { @@ -106,10 +114,15 @@ void LLLandmarkList::processGetAssetReply( gMessageSystem, gAgent.getRegionHost(), region_id, - NULL); + boost::bind(&LLLandmarkList::onRegionHandle, &gLandmarkList, uuid)); } + + // the callback will be called when we get the region handle. + } + else + { + gLandmarkList.makeCallbacks(uuid); } - gLandmarkList.mList[ uuid ] = landmark; } } else @@ -134,3 +147,45 @@ BOOL LLLandmarkList::assetExists(const LLUUID& asset_uuid) { return mList.count(asset_uuid) != 0 || mBadList.count(asset_uuid) != 0; } + +void LLLandmarkList::onRegionHandle(const LLUUID& landmark_id) +{ + LLLandmark* landmark = getAsset(landmark_id); + + if (!landmark) + { + llwarns << "Got region handle but the landmark not found." << llendl; + return; + } + + // Calculate landmark global position. + // This should succeed since the region handle is available. + LLVector3d pos; + if (!landmark->getGlobalPos(pos)) + { + llwarns << "Got region handle but the landmark global position is still unknown." << llendl; + return; + } + + makeCallbacks(landmark_id); +} + +void LLLandmarkList::makeCallbacks(const LLUUID& landmark_id) +{ + LLLandmark* landmark = getAsset(landmark_id); + + if (!landmark) + { + llwarns << "Landmark to make callbacks for not found." << llendl; + } + + // make all the callbacks here. + loaded_callback_map_t::iterator it; + while((it = mLoadedCallbackMap.find(landmark_id)) != mLoadedCallbackMap.end()) + { + if (landmark) + (*it).second(landmark); + + mLoadedCallbackMap.erase(it); + } +} diff --git a/indra/newview/lllandmarklist.h b/indra/newview/lllandmarklist.h index c41ba7a0f0..ebf1b65e97 100644 --- a/indra/newview/lllandmarklist.h +++ b/indra/newview/lllandmarklist.h @@ -33,6 +33,7 @@ #ifndef LL_LLLANDMARKLIST_H #define LL_LLLANDMARKLIST_H +#include #include #include "lllandmark.h" #include "lluuid.h" @@ -45,6 +46,8 @@ class LLInventoryItem; class LLLandmarkList { public: + typedef boost::function loaded_callback_t; + LLLandmarkList() {} ~LLLandmarkList(); @@ -53,7 +56,7 @@ public: //const LLLandmark* getNext() { return mList.getNextData(); } BOOL assetExists(const LLUUID& asset_uuid); - LLLandmark* getAsset(const LLUUID& asset_uuid); + LLLandmark* getAsset(const LLUUID& asset_uuid, loaded_callback_t cb = NULL); static void processGetAssetReply( LLVFS *vfs, const LLUUID& uuid, @@ -63,11 +66,19 @@ public: LLExtStat ext_status ); protected: + void onRegionHandle(const LLUUID& landmark_id); + void makeCallbacks(const LLUUID& landmark_id); + typedef std::map landmark_list_t; landmark_list_t mList; typedef std::set landmark_bad_list_t; landmark_bad_list_t mBadList; + + // *TODO: make the callback multimap a template class and make use of it + // here and in LLLandmark. + typedef std::multimap loaded_callback_map_t; + loaded_callback_map_t mLoadedCallbackMap; }; diff --git a/indra/newview/lllistbrowser.cpp b/indra/newview/lllistbrowser.cpp new file mode 100644 index 0000000000..edd8e9818f --- /dev/null +++ b/indra/newview/lllistbrowser.cpp @@ -0,0 +1,37 @@ +/** + * @file lllistbrowser.cpp + * @brief UI widget showing a search filter, list view, icon action buttons, + * and verb action buttons, as usually embedded in the side tray. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "llviewerprecompiledheaders.h" + +#include "lllistbrowser.h" + +// TODO diff --git a/indra/newview/lllistbrowser.h b/indra/newview/lllistbrowser.h new file mode 100644 index 0000000000..bc9498c514 --- /dev/null +++ b/indra/newview/lllistbrowser.h @@ -0,0 +1,36 @@ +/** + * @file lllistbrowser.h + * @brief UI widget showing a search filter, list view, icon action buttons, + * and verb action buttons, as usually embedded in the side tray. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLLISTBROWSER_H +#define LLLISTBROWSER_H + +#endif // LLLISTBROWSER_H diff --git a/indra/newview/lllistview.cpp b/indra/newview/lllistview.cpp new file mode 100644 index 0000000000..3019d5d3d5 --- /dev/null +++ b/indra/newview/lllistview.cpp @@ -0,0 +1,73 @@ +/** + * @file lllistview.cpp + * @brief UI widget containing a scrollable, possibly hierarchical list of + * folders (LLListViewFolder) and items (LLListViewItem). + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "llviewerprecompiledheaders.h" + +#include "lllistview.h" + +#include "lltextbox.h" +#include "lluictrlfactory.h" // LLDefaultChildRegistry + +// linker optimizes this out on Windows until there is a real reference +// to this file +static LLDefaultChildRegistry::Register r("list_view"); + +LLListView::Params::Params() +: bg_color("bg_color"), + fg_selected_color("fg_selected_color"), + bg_selected_color("bg_selected_color") +{} + +LLListView::LLListView(const Params& p) +: LLUICtrl(p), + mLabel(NULL), + mBgColor(p.bg_color()), + mFgSelectedColor(p.fg_selected_color()), + mBgSelectedColor(p.bg_selected_color()) +{ + LLRect label_rect(0, 20, 300, 0); + LLTextBox::Params text_box_params; + text_box_params.rect(label_rect); + text_box_params.text("This is a list-view"); + mLabel = LLUICtrlFactory::create(text_box_params); + addChild(mLabel); +} + +LLListView::~LLListView() +{} + + +// placeholder for setting a property +void LLListView::setString(const std::string& s) +{ + mLabel->setValue( LLSD(s) ); +} diff --git a/indra/newview/lllistview.h b/indra/newview/lllistview.h new file mode 100644 index 0000000000..501c0c9e1f --- /dev/null +++ b/indra/newview/lllistview.h @@ -0,0 +1,66 @@ +/** + * @file lllistview.h + * @brief UI widget containing a scrollable, possibly hierarchical list of + * folders (LLListViewFolder) and items (LLListViewItem). + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLLISTVIEW_H +#define LLLISTVIEW_H + +#include "llui.h" // for LLUIColor, *TODO: use more specific header +#include "lluictrl.h" + +class LLTextBox; + +class LLListView +: public LLUICtrl +{ +public: + struct Params : public LLInitParam::Block + { + Optional bg_color, + fg_selected_color, + bg_selected_color; + Params(); + }; + LLListView(const Params& p); + virtual ~LLListView(); + + // placeholder for setting a property + void setString(const std::string& s); + +private: + // TODO: scroll container? + LLTextBox* mLabel; // just for testing + LLUIColor mBgColor; + LLUIColor mFgSelectedColor; + LLUIColor mBgSelectedColor; +}; + +#endif // LLLISTVIEW_H diff --git a/indra/newview/lllocaltextureobject.cpp b/indra/newview/lllocaltextureobject.cpp new file mode 100644 index 0000000000..e4a20aea68 --- /dev/null +++ b/indra/newview/lllocaltextureobject.cpp @@ -0,0 +1,149 @@ +/** + * @file lllocaltextureobject.cpp + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lllocaltextureobject.h" + +#include "lltexlayer.h" +#include "llviewertexture.h" +#include "lltextureentry.h" +#include "lluuid.h" + + +LLLocalTextureObject::LLLocalTextureObject() : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1) +{ + mImage = NULL; +} + +LLLocalTextureObject::LLLocalTextureObject(LLViewerFetchedTexture *image, LLTextureEntry *entry, LLTexLayer *layer, LLUUID id) +{ + if (entry) + { + LLTextureEntry * te = new LLTextureEntry(*entry); + mTexEntry = boost::shared_ptr(te); + } + + if (layer) + { + LLTexLayer *texLayer = new LLTexLayer(*layer); + mTexLayer = boost::shared_ptr(texLayer); + } + mImage = image; + mID = id; +} + +LLLocalTextureObject::LLLocalTextureObject(const LLLocalTextureObject <o) : +mImage(lto.mImage), +mTexEntry(lto.mTexEntry), +mTexLayer(lto.mTexLayer), +mID(lto.mID), +mIsBakedReady(lto.mIsBakedReady), +mDiscard(lto.mDiscard) +{ +} + +LLLocalTextureObject::~LLLocalTextureObject() +{ +} + +LLViewerFetchedTexture* LLLocalTextureObject::getImage() const +{ + return mImage; +} + +LLTextureEntry* LLLocalTextureObject::getTexEntry() const +{ + return mTexEntry.get(); +} + +LLTexLayer* LLLocalTextureObject::getTexLayer() const +{ + return mTexLayer.get(); +} + +LLUUID LLLocalTextureObject::getID() const +{ + return mID; +} + +S32 LLLocalTextureObject::getDiscard() const +{ + return mDiscard; +} + +BOOL LLLocalTextureObject::getBakedReady() const +{ + return mIsBakedReady; +} + +void LLLocalTextureObject::setImage(LLViewerFetchedTexture* new_image) +{ + mImage = new_image; +} + +void LLLocalTextureObject::setTexEntry(LLTextureEntry *new_te) +{ + LLTextureEntry *ptr = NULL; + if (new_te) + { + ptr = new LLTextureEntry(*new_te); + } + mTexEntry = boost::shared_ptr(ptr); +} + +void LLLocalTextureObject::setTexLayer(LLTexLayer *new_tex_layer) +{ + LLTexLayer *ptr = NULL; + if (new_tex_layer) + { + ptr = new LLTexLayer(*new_tex_layer); + } + mTexLayer = boost::shared_ptr(ptr); +} + +void LLLocalTextureObject::setID(LLUUID new_id) +{ + mID = new_id; +} + +void LLLocalTextureObject::setDiscard(S32 new_discard) +{ + mDiscard = new_discard; +} + +void LLLocalTextureObject::setBakedReady(BOOL ready) +{ + mIsBakedReady = ready; +} + diff --git a/indra/newview/lllocaltextureobject.h b/indra/newview/lllocaltextureobject.h new file mode 100644 index 0000000000..79e1562dce --- /dev/null +++ b/indra/newview/lllocaltextureobject.h @@ -0,0 +1,85 @@ +/** + * @file lllocaltextureobject.h + * @brief LLLocalTextureObject class header file + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LOCALTEXTUREOBJECT_H +#define LL_LOCALTEXTUREOBJECT_H + +#include + +class LLViewerFetchedTexture; +class LLUUID; +class LLTexLayer; +class LLTextureEntry; + +// Stores all relevant information for a single texture +// assumed to have ownership of all objects referred to - +// will delete objects when being replaced or if object is destroyed. +class LLLocalTextureObject +{ +public: + LLLocalTextureObject(); + LLLocalTextureObject(LLViewerFetchedTexture *image, LLTextureEntry *entry, LLTexLayer *layer, LLUUID id); + LLLocalTextureObject(const LLLocalTextureObject <o); + ~LLLocalTextureObject(); + + LLViewerFetchedTexture* getImage() const; + LLTextureEntry* getTexEntry() const; + LLTexLayer* getTexLayer() const; + LLUUID getID() const; + S32 getDiscard() const; + BOOL getBakedReady() const; + + void setImage(LLViewerFetchedTexture* new_image); + void setTexEntry(LLTextureEntry *new_te); + void setTexLayer(LLTexLayer *new_tex_layer); + void setID(LLUUID new_id); + void setDiscard(S32 new_discard); + void setBakedReady(BOOL ready); + +protected: + +private: + + LLPointer mImage; + // NOTE: LLLocalTextureObject should be the exclusive owner of mTexEntry and mTexLayer + // using shared pointers here only for smart assignment & cleanup + // do NOT create new shared pointers to these objects, or keep pointers to them around + boost::shared_ptr mTexEntry; + boost::shared_ptr mTexLayer; + LLUUID mID; + + BOOL mIsBakedReady; + S32 mDiscard; +}; + + #endif // LL_LOCALTEXTUREOBJECT_H + diff --git a/indra/newview/lllocationhistory.cpp b/indra/newview/lllocationhistory.cpp new file mode 100644 index 0000000000..c83cde9d83 --- /dev/null +++ b/indra/newview/lllocationhistory.cpp @@ -0,0 +1,204 @@ +/** + * @file lllocationhistory.cpp + * @brief Typed locations history + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lllocationhistory.h" + +#include // for std::setw() + +#include "llui.h" + +const char LLLocationHistory::delimiter = '\t'; + +LLLocationHistory::LLLocationHistory() : + mFilename("typed_locations.txt") +{ +} + +void LLLocationHistory::addItem(const std::string & item, const std::string & tooltip) { + static LLUICachedControl max_items("LocationHistoryMaxSize", 100); + + // check if this item doesn't duplicate any existing one + std::vector::iterator item_iter = std::find_if(mItems.begin(), mItems.end(), + boost::bind(&LLLocationHistory::equalByRegionParcel,this,_1,item)); + if(item_iter != mItems.end()){ + /*replace duplicate. + * If an item's region and item's parcel are equal. + */ + mToolTips.erase(*item_iter); + mItems.erase(item_iter); + + } + + mItems.push_back(item); + mToolTips[item] = tooltip; + + // If the vector size exceeds the maximum, purge the oldest items. + if ((S32)mItems.size() > max_items) { + for(std::vector::iterator i = mItems.begin(); i != mItems.end()-max_items; ++i) { + mToolTips.erase(*i); + mItems.erase(i); + } + } +} + +/** + * check if the history item is equal. + * @return true - if region name and parcel is equal. + */ +bool LLLocationHistory::equalByRegionParcel(const std::string& item, const std::string& newItem){ + + + S32 itemIndex = item.find('('); + S32 newItemIndex = newItem.find('('); + + std::string region_parcel = item.substr(0,itemIndex); + std::string new_region_parcel = newItem.substr(0,newItemIndex); + + return region_parcel == new_region_parcel; +} +bool LLLocationHistory::touchItem(const std::string & item) { + bool result = false; + std::vector::iterator item_iter = std::find(mItems.begin(), mItems.end(), item); + + // the last used item should be the first in the history + if (item_iter != mItems.end()) { + mItems.erase(item_iter); + mItems.push_back(item); + result = true; + } + + return result; +} + +void LLLocationHistory::removeItems() +{ + mItems.clear(); + mToolTips.clear(); +} + +std::string LLLocationHistory::getToolTip(const std::string & item) const { + std::map::const_iterator i = mToolTips.find(item); + + return i != mToolTips.end() ? i->second : ""; +} + +bool LLLocationHistory::getMatchingItems(std::string substring, location_list_t& result) const +{ + // *TODO: an STL algorithm would look nicer + result.clear(); + + std::string needle = substring; + LLStringUtil::toLower(needle); + + for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) + { + std::string haystack = *it; + LLStringUtil::toLower(haystack); + + if (haystack.find(needle) != std::string::npos) + result.push_back(*it); + } + + return result.size(); +} + +void LLLocationHistory::dump() const +{ + llinfos << "Location history dump:" << llendl; + int i = 0; + for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it, ++i) + { + llinfos << "#" << std::setw(2) << std::setfill('0') << i << ": " << *it << llendl; + } +} + +void LLLocationHistory::save() const +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, mFilename); + + // open a file for writing + llofstream file (resolved_filename); + if (!file.is_open()) + { + llwarns << "can't open location history file \"" << mFilename << "\" for writing" << llendl; + return; + } + + for (location_list_t::const_iterator it = mItems.begin(); it != mItems.end(); ++it) + { + std::string tooltip = getToolTip(*it); + if(!tooltip.empty()) + { + file << (*it) << delimiter << tooltip << std::endl; + } + } + + file.close(); +} + +void LLLocationHistory::load() +{ + llinfos << "Loading location history." << llendl; + + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, mFilename); + llifstream file(resolved_filename); + + if (!file.is_open()) + { + llwarns << "can't load location history from file \"" << mFilename << "\"" << llendl; + return; + } + + removeItems(); + + // add each line in the file to the list + std::string line; + + while (std::getline(file, line)) { + size_t dp = line.find(delimiter); + + if (dp != std::string::npos) { + const std::string reg_name = line.substr(0, dp); + const std::string tooltip = line.substr(dp + 1, std::string::npos); + + addItem(reg_name, tooltip); + } + } + + file.close(); + + mLoadedSignal(); +} diff --git a/indra/newview/lllocationhistory.h b/indra/newview/lllocationhistory.h new file mode 100644 index 0000000000..060a6b2fe8 --- /dev/null +++ b/indra/newview/lllocationhistory.h @@ -0,0 +1,76 @@ +/** + * @file llocationhistory.h + * @brief Typed locations history + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLLOCATIONHISTORY_H +#define LL_LLLOCATIONHISTORY_H + +#include "llsingleton.h" // for LLSingleton + +#include +#include +#include +#include + +class LLLocationHistory: public LLSingleton +{ + LOG_CLASS(LLLocationHistory); + +public: + typedef std::vector location_list_t; + typedef boost::function loaded_callback_t; + typedef boost::signals2::signal loaded_signal_t; + + LLLocationHistory(); + + void addItem(const std::string & item, const std::string & tooltip); + bool touchItem(const std::string & item); + void removeItems(); + std::string getToolTip(const std::string & item) const; + size_t getItemCount() const { return mItems.size(); } + const location_list_t& getItems() const { return mItems; } + bool getMatchingItems(std::string substring, location_list_t& result) const; + boost::signals2::connection setLoadedCallback(loaded_callback_t cb) { return mLoadedSignal.connect(cb); } + + void save() const; + void load(); + void dump() const; + +private: + bool equalByRegionParcel(const std::string& item, const std::string& item_to_add); + const static char delimiter; + std::vector mItems; + std::map mToolTips; + std::string mFilename; /// File to store the history to. + loaded_signal_t mLoadedSignal; +}; + +#endif diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp new file mode 100644 index 0000000000..a8ec826e88 --- /dev/null +++ b/indra/newview/lllocationinputctrl.cpp @@ -0,0 +1,688 @@ +/** + * @file lllocationinputctrl.cpp + * @brief Combobox-like location input control + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// file includes +#include "lllocationinputctrl.h" + +// common includes +#include "llbutton.h" +#include "llfocusmgr.h" +#include "llmenugl.h" +#include "llstring.h" +#include "lltrans.h" +#include "lluictrlfactory.h" + +// newview includes +#include "llinventorymodel.h" +#include "lllandmarkactions.h" +#include "lllandmarklist.h" +#include "lllocationhistory.h" +#include "llsidetray.h" +#include "llslurl.h" +#include "lltrans.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llviewercontrol.h" +#include "llviewermenu.h" +#include "llurllineeditorctrl.h" +#include "llagentui.h" + +//============================================================================ +/* + * "ADD LANDMARK" BUTTON UPDATING LOGIC + * + * If the current parcel has been landmarked, we should draw + * a special image on the button. + * + * To avoid determining the appropriate image on every draw() we do that + * only in the following cases: + * 1) Navbar is shown for the first time after login. + * 2) Agent moves to another parcel. + * 3) A landmark is created or removed. + * + * The first case is handled by the handleLoginComplete() method. + * + * The second case is handled by setting the "agent parcel changed" callback + * on LLViewerParcelMgr. + * + * The third case is the most complex one. We have two inventory observers for that: + * one is designated to handle adding landmarks, the other handles removal. + * Let's see how the former works. + * + * When we get notified about landmark addition, the landmark position is unknown yet. What we can + * do at that point is initiate loading the landmark data by LLLandmarkList and set the + * "loading finished" callback on it. Finally, when the callback is triggered, + * we can determine whether the landmark refers to a point within the current parcel + * and choose the appropriate image for the "Add landmark" button. + */ + +/** + * Initiates loading the landmarks that have been just added. + * + * Once the loading is complete we'll be notified + * with the callback we set for LLLandmarkList. + */ +class LLAddLandmarkObserver : public LLInventoryAddedObserver +{ +public: + LLAddLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} + +private: + /*virtual*/ void done() + { + std::vector::const_iterator it = mAdded.begin(), end = mAdded.end(); + for(; it != end; ++it) + { + LLInventoryItem* item = gInventory.getItem(*it); + if (!item || item->getType() != LLAssetType::AT_LANDMARK) + continue; + + // Start loading the landmark. + LLLandmark* lm = gLandmarkList.getAsset( + item->getAssetUUID(), + boost::bind(&LLLocationInputCtrl::onLandmarkLoaded, mInput, _1)); + if (lm) + { + // Already loaded? Great, handle it immediately (the callback won't be called). + mInput->onLandmarkLoaded(lm); + } + } + + mAdded.clear(); + } + + LLLocationInputCtrl* mInput; +}; + +/** + * Updates the "Add landmark" button once a landmark gets removed. + */ +class LLRemoveLandmarkObserver : public LLInventoryObserver +{ +public: + LLRemoveLandmarkObserver(LLLocationInputCtrl* input) : mInput(input) {} + +private: + /*virtual*/ void changed(U32 mask) + { + if (mask & (~(LLInventoryObserver::LABEL|LLInventoryObserver::INTERNAL|LLInventoryObserver::ADD))) + { + mInput->updateAddLandmarkButton(); + } + } + + LLLocationInputCtrl* mInput; +}; + +//============================================================================ + + +static LLDefaultChildRegistry::Register r("location_input"); + +LLLocationInputCtrl::Params::Params() +: add_landmark_image_enabled("add_landmark_image_enabled"), + add_landmark_image_disabled("add_landmark_image_disabled"), + add_landmark_image_hover("add_landmark_image_hover"), + add_landmark_image_selected("add_landmark_image_selected"), + add_landmark_button("add_landmark_button"), + add_landmark_hpad("add_landmark_hpad", 0), + info_button("info_button") +{ +} + +LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p) +: LLComboBox(p), + mAddLandmarkHPad(p.add_landmark_hpad), + mInfoBtn(NULL), + mLocationContextMenu(NULL), + mAddLandmarkBtn(NULL), + mLandmarkImageOn(NULL), + mLandmarkImageOff(NULL) +{ + // Lets replace default LLLineEditor with LLLocationLineEditor + // to make needed escaping while copying and cutting url + this->removeChild(mTextEntry); + delete mTextEntry; + + // Can't access old mTextEntry fields as they are protected, so lets build new params + // That is C&P from LLComboBox::createLineEditor function + static LLUICachedControl drop_shadow_button ("DropShadowButton", 0); + S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0; + LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button; + + LLLineEditor::Params params = p.combo_editor; + params.rect(text_entry_rect); + params.default_text(LLStringUtil::null); + params.max_length_bytes(p.max_chars); + params.commit_callback.function(boost::bind(&LLComboBox::onTextCommit, this, _2)); + params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1)); + params.focus_lost_callback(NULL); + params.handle_edit_keys_directly(true); + params.commit_on_focus_lost(false); + params.follows.flags(FOLLOWS_ALL); + mTextEntry = LLUICtrlFactory::create(params); + this->addChild(mTextEntry); + // LLLineEditor is replaced with LLLocationLineEditor + + // "Place information" button. + LLButton::Params info_params = p.info_button; + mInfoBtn = LLUICtrlFactory::create(info_params); + mInfoBtn->setClickedCallback(boost::bind(&LLLocationInputCtrl::onInfoButtonClicked, this)); + addChild(mInfoBtn); + + // "Add landmark" button. + LLButton::Params al_params = p.add_landmark_button; + + // Image for unselected state will be set in updateAddLandmarkButton(), + // it will be either mLandmarkOn or mLandmarkOff + if (p.add_landmark_image_enabled()) + { + mLandmarkImageOn = p.add_landmark_image_enabled; + } + if (p.add_landmark_image_disabled()) + { + mLandmarkImageOff = p.add_landmark_image_disabled; + } + + if(p.add_landmark_image_selected) + { + al_params.image_selected = p.add_landmark_image_selected; + } + if (p.add_landmark_image_hover()) + { + al_params.image_hover_unselected = p.add_landmark_image_hover; + } + + al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this)); + mAddLandmarkBtn = LLUICtrlFactory::create(al_params); + enableAddLandmarkButton(true); + addChild(mAddLandmarkBtn); + + // Register callbacks and load the location field context menu (NB: the order matters). + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2)); + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2)); + + setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2)); + getTextEntry()->setMouseUpCallback(boost::bind(&LLLocationInputCtrl::changeLocationPresentation, this)); + + // Load the location field context menu + mLocationContextMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!mLocationContextMenu) + { + llwarns << "Error loading navigation bar context menu" << llendl; + + } + getTextEntry()->setRightMouseUpCallback(boost::bind(&LLLocationInputCtrl::onTextEditorRightClicked,this,_2,_3,_4)); + updateWidgetlayout(); + + // - Make the "Add landmark" button updated when either current parcel gets changed + // or a landmark gets created or removed from the inventory. + // - Update the location string on parcel change. + mParcelMgrConnection = LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback( + boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this)); + + mLocationHistoryConnection = LLLocationHistory::getInstance()->setLoadedCallback( + boost::bind(&LLLocationInputCtrl::onLocationHistoryLoaded, this)); + + mRemoveLandmarkObserver = new LLRemoveLandmarkObserver(this); + mAddLandmarkObserver = new LLAddLandmarkObserver(this); + gInventory.addObserver(mRemoveLandmarkObserver); + gInventory.addObserver(mAddLandmarkObserver); + + mAddLandmarkTooltip = LLTrans::getString("location_ctrl_add_landmark"); + mEditLandmarkTooltip = LLTrans::getString("location_ctrl_edit_landmark"); +} + +LLLocationInputCtrl::~LLLocationInputCtrl() +{ + gInventory.removeObserver(mRemoveLandmarkObserver); + gInventory.removeObserver(mAddLandmarkObserver); + delete mRemoveLandmarkObserver; + delete mAddLandmarkObserver; + + mParcelMgrConnection.disconnect(); + mLocationHistoryConnection.disconnect(); +} + +void LLLocationInputCtrl::setEnabled(BOOL enabled) +{ + LLComboBox::setEnabled(enabled); + mAddLandmarkBtn->setEnabled(enabled); +} + +void LLLocationInputCtrl::hideList() +{ + LLComboBox::hideList(); + if (mTextEntry && hasFocus()) + focusTextEntry(); +} + +BOOL LLLocationInputCtrl::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) +{ + // Let the buttons show their tooltips. + if (LLUICtrl::handleToolTip(x, y, msg, sticky_rect_screen) && !msg.empty()) + { + if (mList->getRect().pointInRect(x, y)) { + LLLocationHistory* lh = LLLocationHistory::getInstance(); + const std::string tooltip = lh->getToolTip(msg); + + if (!tooltip.empty()) { + msg = tooltip; + } + } + + return TRUE; + } + + msg = LLUI::sShowXUINames ? getShowNamesToolTip() : ""; + return mTextEntry->getRect().pointInRect(x, y); +} + +BOOL LLLocationInputCtrl::handleKeyHere(KEY key, MASK mask) +{ + BOOL result = LLComboBox::handleKeyHere(key, mask); + + if (key == KEY_DOWN && hasFocus() && mList->getItemCount() != 0) + { + showList(); + } + + return result; +} + +void LLLocationInputCtrl::onTextEntry(LLLineEditor* line_editor) +{ + KEY key = gKeyboard->currentKey(); + + if (line_editor->getText().empty()) + { + prearrangeList(); // resets filter + hideList(); + } + // Typing? (moving cursor should not affect showing the list) + else if (key != KEY_LEFT && key != KEY_RIGHT && key != KEY_HOME && key != KEY_END) + { + prearrangeList(line_editor->getText()); + if (mList->getItemCount() != 0) + { + showList(); + focusTextEntry(); + } + else + { + // Hide the list if it's empty. + hideList(); + } + } + + LLComboBox::onTextEntry(line_editor); +} + +/** + * Useful if we want to just set the text entry value, no matter what the list contains. + * + * This is faster than setTextEntry(). + */ +void LLLocationInputCtrl::setText(const LLStringExplicit& text) +{ + if (mTextEntry) + { + mTextEntry->setText(text); + mHasAutocompletedText = FALSE; + } +} + +void LLLocationInputCtrl::setFocus(BOOL b) +{ + LLComboBox::setFocus(b); + + if (mTextEntry && b && !mList->getVisible()) + mTextEntry->setFocus(TRUE); +} + +void LLLocationInputCtrl::handleLoginComplete() +{ + // An agent parcel update hasn't occurred yet, so we have to + // manually set location and the appropriate "Add landmark" icon. + refresh(); +} + +//== private methods ========================================================= + +void LLLocationInputCtrl::onFocusReceived() +{ + prearrangeList(); +} + +void LLLocationInputCtrl::onFocusLost() +{ + LLUICtrl::onFocusLost(); + refreshLocation(); + if(mTextEntry->hasSelection()){ + mTextEntry->deselect(); + } +} +void LLLocationInputCtrl::draw(){ + + if(!hasFocus() && gSavedSettings.getBOOL("ShowCoordinatesOption")){ + refreshLocation(); + } + LLComboBox::draw(); +} + +void LLLocationInputCtrl::onInfoButtonClicked() +{ + LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "agent")); +} + +void LLLocationInputCtrl::onAddLandmarkButtonClicked() +{ + LLViewerInventoryItem* landmark = LLLandmarkActions::findLandmarkForAgentParcel(); + + // Landmark exists, open it for preview and edit + if(landmark && landmark->getUUID().notNull()) + { + LLSD key; + key["type"] = "landmark"; + key["id"] = landmark->getUUID(); + + LLSideTray::getInstance()->showPanel("panel_places", key); + } + else + { + LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); + } +} + +void LLLocationInputCtrl::onAgentParcelChange() +{ + refresh(); +} + +void LLLocationInputCtrl::onLandmarkLoaded(LLLandmark* lm) +{ + (void) lm; + updateAddLandmarkButton(); +} + +void LLLocationInputCtrl::onLocationHistoryLoaded() +{ + rebuildLocationHistory(); +} + +void LLLocationInputCtrl::onLocationPrearrange(const LLSD& data) +{ + std::string filter = data.asString(); + rebuildLocationHistory(filter); + + //Let's add landmarks to the top of the list if any + if( filter.size() !=0 ) + { + LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(filter, TRUE); + + for(U32 i=0; i < landmark_items.size(); i++) + { + mList->addSimpleElement(landmark_items[i]->getName(), ADD_TOP); + } + } + mList->mouseOverHighlightNthItem(-1); // Clear highlight on the last selected item. +} + +void LLLocationInputCtrl::onTextEditorRightClicked(S32 x, S32 y, MASK mask) +{ + if (mLocationContextMenu) + { + updateContextMenu(); + mLocationContextMenu->buildDrawLabels(); + mLocationContextMenu->updateParent(LLMenuGL::sMenuContainer); + hideList(); + setFocus(true); + changeLocationPresentation(); + LLMenuGL::showPopup(this, mLocationContextMenu, x, y); + } +} + +void LLLocationInputCtrl::refresh() +{ + refreshLocation(); // update location string + updateAddLandmarkButton(); // indicate whether current parcel has been landmarked +} + +void LLLocationInputCtrl::refreshLocation() +{ + // Is one of our children focused? + if (LLUICtrl::hasFocus() || mButton->hasFocus() || mList->hasFocus() || + (mTextEntry && mTextEntry->hasFocus()) || (mAddLandmarkBtn->hasFocus())) + + { + llwarns << "Location input should not be refreshed when having focus" << llendl; + return; + } + + // Update location field. + std::string location_name; + LLAgentUI::ELocationFormat format = (gSavedSettings.getBOOL("ShowCoordinatesOption") ? + LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM: LLAgentUI::LOCATION_FORMAT_NORMAL); + + if (!LLAgentUI::buildLocationString(location_name, format)) location_name = "Unknown"; + setText(location_name); +} + +void LLLocationInputCtrl::rebuildLocationHistory(std::string filter) +{ + LLLocationHistory::location_list_t filtered_items; + const LLLocationHistory::location_list_t* itemsp = NULL; + LLLocationHistory* lh = LLLocationHistory::getInstance(); + + if (filter.empty()) + { + itemsp = &lh->getItems(); + } + else + { + lh->getMatchingItems(filter, filtered_items); + itemsp = &filtered_items; + } + + removeall(); + for (LLLocationHistory::location_list_t::const_reverse_iterator it = itemsp->rbegin(); it != itemsp->rend(); it++) + { + add(*it); + } +} + +void LLLocationInputCtrl::focusTextEntry() +{ + // We can't use "mTextEntry->setFocus(TRUE)" instead because + // if the "select_on_focus" parameter is true it places the cursor + // at the beginning (after selecting text), thus screwing up updateSelection(). + if (mTextEntry) + gFocusMgr.setKeyboardFocus(mTextEntry); +} + +void LLLocationInputCtrl::enableAddLandmarkButton(bool val) +{ + // We don't want to disable the button because it should be click able at any time, + // instead switch images. + LLUIImage* img = val ? mLandmarkImageOn : mLandmarkImageOff; + if(img) + { + mAddLandmarkBtn->setImageUnselected(img); + } +} + +// Change the "Add landmark" button image +// depending on whether current parcel has been landmarked. +void LLLocationInputCtrl::updateAddLandmarkButton() +{ + bool landmark_exists = LLLandmarkActions::landmarkAlreadyExists(); + enableAddLandmarkButton(!landmark_exists); + + std::string tooltip; + if(landmark_exists) + { + tooltip = mEditLandmarkTooltip; + } + else + { + tooltip = mAddLandmarkTooltip; + } + mAddLandmarkBtn->setToolTip(tooltip); +} + +void LLLocationInputCtrl::updateContextMenu(){ + + if (mLocationContextMenu) + { + LLMenuItemGL* landmarkItem = mLocationContextMenu->getChild("Landmark"); + if (!LLLandmarkActions::landmarkAlreadyExists()) + { + landmarkItem->setLabel(LLTrans::getString("AddLandmarkNavBarMenu")); + } + else + { + landmarkItem->setLabel(LLTrans::getString("EditLandmarkNavBarMenu")); + } + } +} +void LLLocationInputCtrl::updateWidgetlayout() +{ + const LLRect& rect = getLocalRect(); + const LLRect& hist_btn_rect = mButton->getRect(); + LLRect info_btn_rect = mInfoBtn->getRect(); + + // info button + info_btn_rect.setOriginAndSize( + 2, (rect.getHeight() - info_btn_rect.getHeight()) / 2, + info_btn_rect.getWidth(), info_btn_rect.getHeight()); + mInfoBtn->setRect(info_btn_rect); + + // "Add Landmark" button + { + LLRect al_btn_rect = mAddLandmarkBtn->getRect(); + al_btn_rect.translate( + hist_btn_rect.mLeft - mAddLandmarkHPad - al_btn_rect.getWidth(), + (rect.getHeight() - al_btn_rect.getHeight()) / 2); + mAddLandmarkBtn->setRect(al_btn_rect); + } +} + +void LLLocationInputCtrl::changeLocationPresentation() +{ + //change location presentation only if user does not select anything and + //human-readable region name is being displayed + if(mTextEntry && !mTextEntry->hasSelection() && + !LLSLURL::isSLURL(mTextEntry->getText())) + { + //needs unescaped one + mTextEntry->setText(LLAgentUI::buildSLURL(false)); + mTextEntry->selectAll(); + } +} + +void LLLocationInputCtrl::onLocationContextMenuItemClicked(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == std::string("show_coordinates")) + { + gSavedSettings.setBOOL("ShowCoordinatesOption",!gSavedSettings.getBOOL("ShowCoordinatesOption")); + } + else if (item == std::string("landmark")) + { + LLInventoryModel::item_array_t items; + LLLandmarkActions::collectParcelLandmark(items); + + if(items.empty()) + { + LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); + }else{ + LLSideTray::getInstance()->showPanel("panel_places", + LLSD().insert("type", "landmark").insert("id",items.get(0)->getUUID())); + } + } + else if (item == std::string("cut")) + { + mTextEntry->cut(); + } + else if (item == std::string("copy")) + { + mTextEntry->copy(); + } + else if (item == std::string("paste")) + { + mTextEntry->paste(); + } + else if (item == std::string("delete")) + { + mTextEntry->deleteSelection(); + } + else if (item == std::string("select_all")) + { + mTextEntry->selectAll(); + } +} + +bool LLLocationInputCtrl::onLocationContextMenuItemEnabled(const LLSD& userdata) +{ + std::string item = userdata.asString(); + + if (item == std::string("can_cut")) + { + return mTextEntry->canCut(); + } + else if (item == std::string("can_copy")) + { + return mTextEntry->canCopy(); + } + else if (item == std::string("can_paste")) + { + return mTextEntry->canPaste(); + } + else if (item == std::string("can_delete")) + { + return mTextEntry->canDeselect(); + } + else if (item == std::string("can_select_all")) + { + return mTextEntry->canSelectAll(); + } + else if(item == std::string("show_coordinates")){ + + return gSavedSettings.getBOOL("ShowCoordinatesOption"); + } + + return false; +} diff --git a/indra/newview/lllocationinputctrl.h b/indra/newview/lllocationinputctrl.h new file mode 100644 index 0000000000..d967df8257 --- /dev/null +++ b/indra/newview/lllocationinputctrl.h @@ -0,0 +1,140 @@ +/** + * @file lllocationinputctrl.h + * @brief Combobox-like location input control + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLLOCATIONINPUTCTRL_H +#define LL_LLLOCATIONINPUTCTRL_H + +#include + +class LLLandmark; + +// internals +class LLAddLandmarkObserver; +class LLRemoveLandmarkObserver; +class LLMenuGL; + +/** + * Location input control. + * + * @see LLNavigationBar + */ +class LLLocationInputCtrl +: public LLComboBox +{ + LOG_CLASS(LLLocationInputCtrl); + friend class LLAddLandmarkObserver; + friend class LLRemoveLandmarkObserver; + +public: + struct Params + : public LLInitParam::Block + { + Optional add_landmark_image_enabled, + add_landmark_image_disabled, + add_landmark_image_hover, + add_landmark_image_selected; + Optional add_landmark_hpad; + Optional add_landmark_button, + info_button; + Params(); + }; + + // LLView interface + /*virtual*/ void setEnabled(BOOL enabled); + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect); + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusLost(); + /*virtual*/ void draw(); + //======================================================================== + + // LLUICtrl interface + /*virtual*/ void setFocus(BOOL b); + //======================================================================== + + // LLComboBox interface + void hideList(); + void onTextEntry(LLLineEditor* line_editor); + //======================================================================== + + LLLineEditor* getTextEntry() const { return mTextEntry; } + void handleLoginComplete(); + +private: + friend class LLUICtrlFactory; + LLLocationInputCtrl(const Params&); + virtual ~LLLocationInputCtrl(); + + void focusTextEntry(); + /** + * Changes the "Add landmark" button image + * depending on whether current parcel has been landmarked. + */ + void enableAddLandmarkButton(bool val); + void refresh(); + void refreshLocation(); + void rebuildLocationHistory(std::string filter = ""); + void setText(const LLStringExplicit& text); + void updateAddLandmarkButton(); + void updateContextMenu(); + void updateWidgetlayout(); + void changeLocationPresentation(); + + void onInfoButtonClicked(); + void onLocationHistoryLoaded(); + void onLocationPrearrange(const LLSD& data); + void onTextEditorRightClicked(S32 x, S32 y, MASK mask); + void onLandmarkLoaded(LLLandmark* lm); + void onAddLandmarkButtonClicked(); + void onAgentParcelChange(); + // callbacks + bool onLocationContextMenuItemEnabled(const LLSD& userdata); + void onLocationContextMenuItemClicked(const LLSD& userdata); + + LLMenuGL* mLocationContextMenu; + LLButton* mAddLandmarkBtn; + LLButton* mInfoBtn; + S32 mAddLandmarkHPad; + + LLAddLandmarkObserver* mAddLandmarkObserver; + LLRemoveLandmarkObserver* mRemoveLandmarkObserver; + + boost::signals2::connection mParcelMgrConnection; + boost::signals2::connection mLocationHistoryConnection; + LLUIImage* mLandmarkImageOn; + LLUIImage* mLandmarkImageOff; + + std::string mAddLandmarkTooltip; + std::string mEditLandmarkTooltip; +}; + +#endif diff --git a/indra/newview/lllogchat.cpp b/indra/newview/lllogchat.cpp index 1709d6465d..69214b5cab 100644 --- a/indra/newview/lllogchat.cpp +++ b/indra/newview/lllogchat.cpp @@ -35,6 +35,7 @@ #include "lllogchat.h" #include "llappviewer.h" #include "llfloaterchat.h" +#include "lltrans.h" const S32 LOG_RECALL_SIZE = 2048; @@ -64,20 +65,26 @@ std::string LLLogChat::timestamp(bool withdate) time_t utc_time; utc_time = time_corrected(); - // There's only one internal tm buffer. - struct tm* timep; + std::string timeStr; + LLSD substitution; + substitution["datetime"] = (S32) utc_time; - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - timep = utc_to_pacific_time(utc_time, gPacificDaylightTime); - - std::string text; if (withdate) - text = llformat("[%d/%02d/%02d %d:%02d] ", (timep->tm_year-100)+2000, timep->tm_mon+1, timep->tm_mday, timep->tm_hour, timep->tm_min); + { + timeStr = "["+LLTrans::getString ("TimeYear")+"]/[" + +LLTrans::getString ("TimeMonth")+"]/[" + +LLTrans::getString ("TimeDay")+"] [" + +LLTrans::getString ("TimeHour")+"]:[" + +LLTrans::getString ("TimeMin")+"] "; + } else - text = llformat("[%d:%02d] ", timep->tm_hour, timep->tm_min); + { + timeStr = "[" + LLTrans::getString("TimeHour") + "]:[" + + LLTrans::getString ("TimeMin")+"] "; + } - return text; + LLStringUtil::format (timeStr, substitution); + return timeStr; } @@ -114,7 +121,7 @@ void LLLogChat::loadHistory(std::string filename , void (*callback)(ELogLineType LLFILE* fptr = LLFile::fopen(makeLogFileName(filename), "r"); /*Flawfinder: ignore*/ if (!fptr) { - //LLUIString message = LLFloaterChat::getInstance()->getString("IM_logging_string"); + //LLUIString message = LLTrans::getString("IM_logging_string"); //callback(LOG_EMPTY,"IM_logging_string",userdata); callback(LOG_EMPTY,LLStringUtil::null,userdata); return; //No previous conversation with this name. diff --git a/indra/newview/llloginhandler.cpp b/indra/newview/llloginhandler.cpp index 053f798882..6f0b8a3c1e 100644 --- a/indra/newview/llloginhandler.cpp +++ b/indra/newview/llloginhandler.cpp @@ -156,21 +156,15 @@ void LLLoginHandler::parse(const LLSD& queryMap) { LLURLSimString::setString(queryMap["region"].asString()); } - else if (startLocation == "home") + else if (!startLocation.empty()) // "last" or "home" or ??? (let LLURLSimString figure it out) { - gSavedSettings.setBOOL("LoginLastLocation", FALSE); - LLURLSimString::setString(LLStringUtil::null); - } - else if (startLocation == "last") - { - gSavedSettings.setBOOL("LoginLastLocation", TRUE); - LLURLSimString::setString(LLStringUtil::null); + LLURLSimString::setString(startLocation); } } bool LLLoginHandler::handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { parse(query_map); diff --git a/indra/newview/llloginhandler.h b/indra/newview/llloginhandler.h index c76d7e8274..0844b80c7c 100644 --- a/indra/newview/llloginhandler.h +++ b/indra/newview/llloginhandler.h @@ -40,7 +40,7 @@ class LLLoginHandler : public LLCommandHandler public: // allow from external browsers LLLoginHandler() : LLCommandHandler("login", false) { } - /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web); + /*virtual*/ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web); // Fill in our internal fields from a SLURL like // secondlife:///app/login?first=Bob&last=Dobbs diff --git a/indra/newview/lllookshistorypanel.h b/indra/newview/lllookshistorypanel.h new file mode 100644 index 0000000000..986c9a1c4d --- /dev/null +++ b/indra/newview/lllookshistorypanel.h @@ -0,0 +1,72 @@ +/** + * @file llpanelteleporthistory.h + * @brief Teleport history represented by a scrolling list + * class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELLOOKSHISTORY_H +#define LL_LLPANELLOOKSHISTORY_H + +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" + +#include "llpanelappearancetab.h" +#include "lllookshistory.h" + +class LLLooksHistoryPanel : public LLPanelAppearanceTab +{ +public: + LLLooksHistoryPanel(); + virtual ~LLLooksHistoryPanel(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onSearchEdit(const std::string& string); + /*virtual*/ void onShowOnMap(); + /*virtual*/ void onLooks(); + ///*virtual*/ void onCopySLURL(); + + void showLooksHistory(); + void handleItemSelect(const LLSD& data); + + static void onDoubleClickItem(void* user_data); + +private: + enum LOOKS_HISTORY_COLUMN_ORDER + { + LIST_ICON, + LIST_ITEM_TITLE, + LIST_INDEX + }; + + LLLooksHistory* mLooksHistory; + LLScrollListCtrl* mHistoryItems; + std::string mFilterSubString; +}; + +#endif //LL_LLPANELLOOKSHISTORY_H diff --git a/indra/newview/llmanip.cpp b/indra/newview/llmanip.cpp index 53c74aaec1..3d1d6cad74 100644 --- a/indra/newview/llmanip.cpp +++ b/indra/newview/llmanip.cpp @@ -40,7 +40,7 @@ #include "llrender.h" #include "llprimitive.h" #include "llview.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llagent.h" #include "llviewercontrol.h" @@ -452,35 +452,36 @@ void LLManip::renderXYZ(const LLVector3 &vec) gViewerWindow->setup3DRender(); { + LLFontGL* font = LLFontGL::getFontSansSerif(); LLLocale locale(LLLocale::USER_LOCALE); LLGLDepthTest gls_depth(GL_FALSE); // render drop shadowed text feedback_string = llformat("X: %.3f", vec.mV[VX]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, -102.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); feedback_string = llformat("Y: %.3f", vec.mV[VY]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, -27.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); feedback_string = llformat("Z: %.3f", vec.mV[VZ]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, 48.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f + 1.f, (F32)vertical_offset - 1.f, LLColor4::black, FALSE); // render text on top feedback_string = llformat("X: %.3f", vec.mV[VX]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, -102.f, (F32)vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f), FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -102.f, (F32)vertical_offset, LLColor4(1.f, 0.5f, 0.5f, 1.f), FALSE); glColor3f(0.5f, 1.f, 0.5f); feedback_string = llformat("Y: %.3f", vec.mV[VY]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, -27.f, (F32)vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f), FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -27.f, (F32)vertical_offset, LLColor4(0.5f, 1.f, 0.5f, 1.f), FALSE); glColor3f(0.5f, 0.5f, 1.f); feedback_string = llformat("Z: %.3f", vec.mV[VZ]); - hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ), LLFontGL::NORMAL, 48.f, (F32)vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f), FALSE); + hud_render_text(utf8str_to_wstring(feedback_string), camera_pos, *font, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 48.f, (F32)vertical_offset, LLColor4(0.5f, 0.5f, 1.f, 1.f), FALSE); } } void LLManip::renderTickText(const LLVector3& pos, const std::string& text, const LLColor4 &color) { - const LLFontGL* big_fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* big_fontp = LLFontGL::getFontSansSerif(); BOOL hud_selection = mObjectSelection->getSelectType() == SELECT_TYPE_HUD; glMatrixMode(GL_MODELVIEW); @@ -498,10 +499,10 @@ void LLManip::renderTickText(const LLVector3& pos, const std::string& text, cons // render shadow first LLColor4 shadow_color = LLColor4::black; shadow_color.mV[VALPHA] = color.mV[VALPHA] * 0.5f; - gViewerWindow->setupViewport(1, -1); - hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(text), 3.f, shadow_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); - gViewerWindow->setupViewport(); - hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(text), 3.f, color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + gViewerWindow->setup3DViewport(1, -1); + hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, shadow_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + gViewerWindow->setup3DViewport(); + hud_render_utf8text(text, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(text), 3.f, color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); glPopMatrix(); } @@ -510,8 +511,8 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string { LLLocale locale(LLLocale::USER_LOCALE); - const LLFontGL* big_fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - const LLFontGL* small_fontp = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF_SMALL ); + const LLFontGL* big_fontp = LLFontGL::getFontSansSerif(); + const LLFontGL* small_fontp = LLFontGL::getFontSansSerifSmall(); std::string val_string; std::string fraction_string; @@ -560,29 +561,29 @@ void LLManip::renderTickValue(const LLVector3& pos, F32 value, const std::string { fraction_string = llformat("%c%02d%s", LLResMgr::getInstance()->getDecimalPoint(), fractional_portion, suffix.c_str()); - gViewerWindow->setupViewport(1, -1); - hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, -1.f * big_fontp->getWidthF32(val_string), 3.f, shadow_color, hud_selection); - hud_render_utf8text(fraction_string, render_pos, *small_fontp, LLFontGL::NORMAL, 1.f, 3.f, shadow_color, hud_selection); + gViewerWindow->setup3DViewport(1, -1); + hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -1.f * big_fontp->getWidthF32(val_string), 3.f, shadow_color, hud_selection); + hud_render_utf8text(fraction_string, render_pos, *small_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 1.f, 3.f, shadow_color, hud_selection); - gViewerWindow->setupViewport(); - hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, -1.f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection); - hud_render_utf8text(fraction_string, render_pos, *small_fontp, LLFontGL::NORMAL, 1.f, 3.f, color, hud_selection); + gViewerWindow->setup3DViewport(); + hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -1.f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection); + hud_render_utf8text(fraction_string, render_pos, *small_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, 1.f, 3.f, color, hud_selection); } else { - gViewerWindow->setupViewport(1, -1); - hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(val_string), 3.f, shadow_color, hud_selection); - gViewerWindow->setupViewport(); - hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection); + gViewerWindow->setup3DViewport(1, -1); + hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(val_string), 3.f, shadow_color, hud_selection); + gViewerWindow->setup3DViewport(); + hud_render_utf8text(val_string, render_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(val_string), 3.f, color, hud_selection); } glPopMatrix(); } LLColor4 LLManip::setupSnapGuideRenderPass(S32 pass) { - static LLColor4 grid_color_fg = gColors.getColor("GridlineColor"); - static LLColor4 grid_color_bg = gColors.getColor("GridlineBGColor"); - static LLColor4 grid_color_shadow = gColors.getColor("GridlineShadowColor"); + static LLColor4 grid_color_fg = LLUIColorTable::instance().getColor("GridlineColor"); + static LLColor4 grid_color_bg = LLUIColorTable::instance().getColor("GridlineBGColor"); + static LLColor4 grid_color_shadow = LLUIColorTable::instance().getColor("GridlineShadowColor"); LLColor4 line_color; F32 line_alpha = gSavedSettings.getF32("GridOpacity"); @@ -591,14 +592,14 @@ LLColor4 LLManip::setupSnapGuideRenderPass(S32 pass) { case 0: // shadow - gViewerWindow->setupViewport(1, -1); + gViewerWindow->setup3DViewport(1, -1); line_color = grid_color_shadow; line_color.mV[VALPHA] *= line_alpha; LLUI::setLineWidth(2.f); break; case 1: // hidden lines - gViewerWindow->setupViewport(); + gViewerWindow->setup3DViewport(); line_color = grid_color_bg; line_color.mV[VALPHA] *= line_alpha; LLUI::setLineWidth(1.f); diff --git a/indra/newview/llmaniprotate.cpp b/indra/newview/llmaniprotate.cpp index 8b0484bba6..d1d112c4bf 100644 --- a/indra/newview/llmaniprotate.cpp +++ b/indra/newview/llmaniprotate.cpp @@ -63,6 +63,7 @@ #include "pipeline.h" #include "lldrawable.h" #include "llglheaders.h" +#include "lltrans.h" const F32 RADIUS_PIXELS = 100.f; // size in screen space const F32 SQ_RADIUS = RADIUS_PIXELS * RADIUS_PIXELS; @@ -897,7 +898,6 @@ void LLManipRotate::renderSnapGuides() } gGL.end(); - // *TODO: Translate //RN: text rendering does own shadow pass, so only render once if (pass == 1 && render_text && i % 16 == 0) { @@ -905,32 +905,32 @@ void LLManipRotate::renderSnapGuides() { if (i == 0) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Forward") : std::string("East"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white); } else if (i == 16) { if (constraint_axis.mV[VZ] > 0.f) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Left") : std::string("North"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white); } else { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Right") : std::string("South"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white); } } else if (i == 32) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Back") : std::string("West"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white); } else { if (constraint_axis.mV[VZ] > 0.f) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Right") : std::string("South"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white); } else { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Left") : std::string("North"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white); } } } @@ -938,32 +938,32 @@ void LLManipRotate::renderSnapGuides() { if (i == 0) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Left") : std::string("North"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Left") : LLTrans::getString("North"), LLColor4::white); } else if (i == 16) { if (constraint_axis.mV[VX] > 0.f) { - renderTickText(text_point, std::string("Up"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white); } else { - renderTickText(text_point, std::string("Down"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white); } } else if (i == 32) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Right") : std::string("South"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Right") : LLTrans::getString("South"), LLColor4::white); } else { if (constraint_axis.mV[VX] > 0.f) { - renderTickText(text_point, std::string("Down"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white); } else { - renderTickText(text_point, std::string("Up"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white); } } } @@ -971,32 +971,32 @@ void LLManipRotate::renderSnapGuides() { if (i == 0) { - renderTickText(text_point, std::string("Up"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Up"), LLColor4::white); } else if (i == 16) { if (constraint_axis.mV[VY] > 0.f) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Forward") : std::string("East"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white); } else { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Back") : std::string("West"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white); } } else if (i == 32) { - renderTickText(text_point, std::string("Down"), LLColor4::white); + renderTickText(text_point, LLTrans::getString("Down"), LLColor4::white); } else { if (constraint_axis.mV[VY] > 0.f) { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Back") : std::string("West"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Back") : LLTrans::getString("West"), LLColor4::white); } else { - renderTickText(text_point, mObjectSelection->isAttachment() ? std::string("Forward") : std::string("East"), LLColor4::white); + renderTickText(text_point, mObjectSelection->isAttachment() ? LLTrans::getString("Forward") : LLTrans::getString("East"), LLColor4::white); } } } @@ -1107,8 +1107,8 @@ BOOL LLManipRotate::updateVisiblity() mCenterToProfilePlaneMag = mRadiusMeters * mRadiusMeters / mCenterToCamMag; mCenterToProfilePlane = -mCenterToProfilePlaneMag * mCenterToCamNorm; - mCenterScreen.set((S32)((0.5f - mRotationCenter.mdV[VY]) / gAgent.mHUDCurZoom * gViewerWindow->getWindowWidth()), - (S32)((mRotationCenter.mdV[VZ] + 0.5f) / gAgent.mHUDCurZoom * gViewerWindow->getWindowHeight())); + mCenterScreen.set((S32)((0.5f - mRotationCenter.mdV[VY]) / gAgent.mHUDCurZoom * gViewerWindow->getWorldViewWidth()), + (S32)((mRotationCenter.mdV[VZ] + 0.5f) / gAgent.mHUDCurZoom * gViewerWindow->getWorldViewHeight())); visible = TRUE; } else @@ -1624,8 +1624,8 @@ void LLManipRotate::mouseToRay( S32 x, S32 y, LLVector3* ray_pt, LLVector3* ray_ { if (LLSelectMgr::getInstance()->getSelection()->getSelectType() == SELECT_TYPE_HUD) { - F32 mouse_x = (((F32)x / gViewerWindow->getWindowWidth()) - 0.5f) / gAgent.mHUDCurZoom; - F32 mouse_y = ((((F32)y) / gViewerWindow->getWindowHeight()) - 0.5f) / gAgent.mHUDCurZoom; + F32 mouse_x = (((F32)x / gViewerWindow->getWorldViewWidth()) - 0.5f) / gAgent.mHUDCurZoom; + F32 mouse_y = ((((F32)y) / gViewerWindow->getWorldViewHeight()) - 0.5f) / gAgent.mHUDCurZoom; *ray_pt = LLVector3(-1.f, -mouse_x, mouse_y); *ray_dir = LLVector3(1.f, 0.f, 0.f); @@ -1699,7 +1699,7 @@ void LLManipRotate::highlightManipulators( S32 x, S32 y ) F32 dist_y = mouse_dir_y.normVec(); F32 dist_z = mouse_dir_z.normVec(); - F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWindowHeight(); + F32 distance_threshold = (MAX_MANIP_SELECT_DISTANCE * mRadiusMeters) / gViewerWindow->getWorldViewHeight(); if (llabs(dist_x - mRadiusMeters) * llmax(0.05f, proj_rot_x_axis) < distance_threshold) { diff --git a/indra/newview/llmanipscale.cpp b/indra/newview/llmanipscale.cpp index b1cdfe3886..72596e850a 100644 --- a/indra/newview/llmanipscale.cpp +++ b/indra/newview/llmanipscale.cpp @@ -415,7 +415,7 @@ BOOL LLManipScale::handleHover(S32 x, S32 y, MASK mask) // Patch up textures, if possible. LLSelectMgr::getInstance()->adjustTexturesByScale(FALSE, getStretchTextures()); - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLSCALE); + gViewerWindow->setCursor(UI_CURSOR_TOOLSCALE); return TRUE; } @@ -493,8 +493,8 @@ void LLManipScale::highlightManipulators(S32 x, S32 y) mProjectedManipulators.insert(projManipulator); } - F32 half_width = (F32)gViewerWindow->getWindowWidth() / 2.f; - F32 half_height = (F32)gViewerWindow->getWindowHeight() / 2.f; + F32 half_width = (F32)gViewerWindow->getWorldViewWidth() / 2.f; + F32 half_height = (F32)gViewerWindow->getWorldViewHeight() / 2.f; LLVector2 manip2d; LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); LLVector2 delta; @@ -1368,7 +1368,7 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) else { F32 object_distance = dist_vec(mScaleCenter, LLViewerCamera::getInstance()->getOrigin()); - mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWindowWidth() * object_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio(); + mSnapRegimeOffset = (SNAP_GUIDE_SCREEN_OFFSET * gViewerWindow->getWorldViewWidth() * object_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio(); } LLVector3 cam_at_axis; F32 snap_guide_length; @@ -1381,7 +1381,7 @@ void LLManipScale::updateSnapGuides(const LLBBox& bbox) { cam_at_axis = LLViewerCamera::getInstance()->getAtAxis(); F32 manipulator_distance = dist_vec(box_corner_agent, LLViewerCamera::getInstance()->getOrigin()); - snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH * gViewerWindow->getWindowWidth() * manipulator_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio(); + snap_guide_length = (SNAP_GUIDE_SCREEN_LENGTH * gViewerWindow->getWorldViewWidth() * manipulator_distance) / LLViewerCamera::getInstance()->getPixelMeterRatio(); } mSnapGuideLength = snap_guide_length / llmax(0.1f, (llmin(mSnapGuideDir1 * cam_at_axis, mSnapGuideDir2 * cam_at_axis))); @@ -1827,10 +1827,10 @@ void LLManipScale::renderSnapGuides(const LLBBox& bbox) std::string help_text = "Move mouse cursor over ruler"; LLColor4 help_text_color = LLColor4::white; help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, grid_alpha, 0.f); - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); help_text = "to snap to grid"; help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapRegimeOffset * 0.4f; - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); } } } diff --git a/indra/newview/llmaniptranslate.cpp b/indra/newview/llmaniptranslate.cpp index f2585c8543..cc2531d139 100644 --- a/indra/newview/llmaniptranslate.cpp +++ b/indra/newview/llmaniptranslate.cpp @@ -61,7 +61,7 @@ #include "llviewerjoint.h" #include "llviewerobject.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llworld.h" #include "llui.h" #include "pipeline.h" @@ -78,7 +78,7 @@ const F32 PLANE_TICK_SIZE = 0.4f; const F32 MANIPULATOR_SCALE_HALF_LIFE = 0.07f; const F32 SNAP_ARROW_SCALE = 0.7f; -static LLPointer sGridTex = NULL ; +static LLPointer sGridTex = NULL ; const LLManip::EManipPart MANIPULATOR_IDS[9] = { @@ -154,7 +154,7 @@ void LLManipTranslate::restoreGL() U32 mip = 0; destroyGL() ; - sGridTex = new LLImageGL() ; + sGridTex = LLViewerTextureManager::getLocalTexture() ; if(!sGridTex->createGLTexture()) { sGridTex = NULL ; @@ -414,7 +414,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) // Handle auto-rotation if necessary. const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD; - const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20; + const S32 ROTATE_H_MARGIN = gViewerWindow->getWorldViewWidth() / 20; const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped; BOOL rotated = FALSE; @@ -426,7 +426,7 @@ BOOL LLManipTranslate::handleHover(S32 x, S32 y, MASK mask) gAgent.cameraOrbitAround(rotate_angle); rotated = TRUE; } - else if (x > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN) + else if (x > gViewerWindow->getWorldViewWidth() - ROTATE_H_MARGIN) { gAgent.cameraOrbitAround(-rotate_angle); rotated = TRUE; @@ -960,8 +960,8 @@ void LLManipTranslate::highlightManipulators(S32 x, S32 y) LLVector2 manip_start_2d; LLVector2 manip_end_2d; LLVector2 manip_dir; - F32 half_width = gViewerWindow->getWindowWidth() / 2.f; - F32 half_height = gViewerWindow->getWindowHeight() / 2.f; + F32 half_width = gViewerWindow->getWorldViewWidth() / 2.f; + F32 half_height = gViewerWindow->getWorldViewHeight() / 2.f; LLVector2 mousePos((F32)x - half_width, (F32)y - half_height); LLVector2 mouse_delta; @@ -1225,7 +1225,7 @@ void LLManipTranslate::renderSnapGuides() { LLVector3 cam_to_selection = getPivotPoint() - LLViewerCamera::getInstance()->getOrigin(); F32 current_range = cam_to_selection.normVec(); - guide_size_meters = SNAP_GUIDE_SCREEN_SIZE * gViewerWindow->getWindowHeight() * current_range / LLViewerCamera::getInstance()->getPixelMeterRatio(); + guide_size_meters = SNAP_GUIDE_SCREEN_SIZE * gViewerWindow->getWorldViewHeight() * current_range / LLViewerCamera::getInstance()->getPixelMeterRatio(); F32 fraction_of_fov = mAxisArrowLength / (F32) LLViewerCamera::getInstance()->getViewHeightInPixels(); F32 apparent_angle = fraction_of_fov * LLViewerCamera::getInstance()->getView(); // radians @@ -1441,10 +1441,10 @@ void LLManipTranslate::renderSnapGuides() std::string help_text = "Move mouse cursor over ruler to snap"; LLColor4 help_text_color = LLColor4::white; help_text_color.mV[VALPHA] = clamp_rescale(mHelpTextTimer.getElapsedTimeF32(), sHelpTextVisibleTime, sHelpTextVisibleTime + sHelpTextFadeTime, line_alpha, 0.f); - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); help_text = "to snap to grid"; help_text_pos -= LLViewerCamera::getInstance()->getUpAxis() * mSnapOffsetMeters * 0.2f; - hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); + hud_render_utf8text(help_text, help_text_pos, *big_fontp, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, -0.5f * big_fontp->getWidthF32(help_text), 3.f, help_text_color, mObjectSelection->getSelectType() == SELECT_TYPE_HUD); } } } @@ -1522,7 +1522,7 @@ void LLManipTranslate::renderSnapGuides() float a = line_alpha; - LLColor4 col = gColors.getColor("SilhouetteChildColor"); + LLColor4 col = LLUIColorTable::instance().getColor("SilhouetteChildColor"); { //draw grid behind objects LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE); @@ -1800,7 +1800,7 @@ void LLManipTranslate::renderTranslationHandles() // Drag handles if (mObjectSelection->getSelectType() == SELECT_TYPE_HUD) { - mArrowLengthMeters = mAxisArrowLength / gViewerWindow->getWindowHeight(); + mArrowLengthMeters = mAxisArrowLength / gViewerWindow->getWorldViewHeight(); mArrowLengthMeters /= gAgent.mHUDCurZoom; } else diff --git a/indra/newview/llmediactrl.cpp b/indra/newview/llmediactrl.cpp new file mode 100644 index 0000000000..62b38f2b4a --- /dev/null +++ b/indra/newview/llmediactrl.cpp @@ -0,0 +1,937 @@ +/** + * @file LLMediaCtrl.cpp + * @brief Web browser UI control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + + +#include "llmediactrl.h" + +// viewer includes +#include "llfloaterhtml.h" +#include "llfloaterworldmap.h" +#include "lluictrlfactory.h" +#include "llurldispatcher.h" +#include "llurlsimstring.h" +#include "llviewborder.h" +#include "llviewercontrol.h" +#include "llviewermedia.h" +#include "llviewerwindow.h" +#include "llnotifications.h" +#include "llweb.h" +#include "llrender.h" +#include "llpluginclassmedia.h" +#include "llslurl.h" +#include "lluictrlfactory.h" // LLDefaultChildRegistry + +// linden library includes +#include "llfocusmgr.h" + +extern BOOL gRestoreGL; + +static LLDefaultChildRegistry::Register r("web_browser"); + +LLMediaCtrl::Params::Params() +: start_url("start_url"), + border_visible("border_visible", true), + ignore_ui_scale("ignore_ui_scale", true), + hide_loading("hide_loading", false), + caret_color("caret_color") +{} + +LLMediaCtrl::LLMediaCtrl( const Params& p) : + LLPanel( p ), + mTextureDepthBytes( 4 ), + mBorder(NULL), + mFrequentUpdates( true ), + mForceUpdate( false ), + mOpenLinksInExternalBrowser( false ), + mOpenLinksInInternalBrowser( false ), + mTrusted( false ), + mHomePageUrl( "" ), + mIgnoreUIScale( true ), + mAlwaysRefresh( false ), + mExternalUrl( "" ), + mMediaSource( 0 ), + mTakeFocusOnClick( true ), + mCurrentNavUrl( "" ), + mLastSetCursor( UI_CURSOR_ARROW ), + mStretchToFill( true ), + mMaintainAspectRatio ( true ), + mHideLoading (false) +{ + { + LLColor4 color = p.caret_color().get(); + setCaretColor( (unsigned int)color.mV[0], (unsigned int)color.mV[1], (unsigned int)color.mV[2] ); + } + + setIgnoreUIScale(p.ignore_ui_scale()); + + setHomePageUrl(p.start_url()); + + setBorderVisible(p.border_visible()); + + mHideLoading = p.hide_loading(); + + S32 screen_width = mIgnoreUIScale ? + llround((F32)getRect().getWidth() * LLUI::sGLScaleFactor.mV[VX]) : getRect().getWidth(); + S32 screen_height = mIgnoreUIScale ? + llround((F32)getRect().getHeight() * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight(); + + mMediaTextureID.generate(); + mMediaSource = LLViewerMedia::newMediaImpl(mHomePageUrl, mMediaTextureID, screen_width, screen_height, false, false, "text/html"); + if ( !mMediaSource ) + { + llwarns << "media source create failed " << llendl; + // return; + } + + mMediaSource->setVisible( getVisible() ); + + mMediaSource->addObserver( this ); + + // FIXME: How do we create a bevel now? +// LLRect border_rect( 0, getRect().getHeight() + 2, getRect().getWidth() + 2, 0 ); +// mBorder = new LLViewBorder( std::string("web control border"), border_rect, LLViewBorder::BEVEL_IN ); +// addChild( mBorder ); +} + +//////////////////////////////////////////////////////////////////////////////// +// note: this is now a singleton and destruction happens via initClass() now +LLMediaCtrl::~LLMediaCtrl() +{ + + if (mMediaSource) + { + mMediaSource->remObserver( this ); + mMediaSource = NULL; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setBorderVisible( BOOL border_visible ) +{ + if ( mBorder ) + { + mBorder->setVisible( border_visible ); + }; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setTakeFocusOnClick( bool take_focus ) +{ + mTakeFocusOnClick = take_focus; +} + +//////////////////////////////////////////////////////////////////////////////// +// set flag that forces the embedded browser to open links in the external system browser +void LLMediaCtrl::setOpenInExternalBrowser( bool valIn ) +{ + mOpenLinksInExternalBrowser = valIn; +}; + +//////////////////////////////////////////////////////////////////////////////// +// set flag that forces the embedded browser to open links in the internal browser floater +void LLMediaCtrl::setOpenInInternalBrowser( bool valIn ) +{ + mOpenLinksInInternalBrowser = valIn; +}; + +//////////////////////////////////////////////////////////////////////////////// +void LLMediaCtrl::setTrusted( bool valIn ) +{ + mTrusted = valIn; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleHover( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseMove(x, y); + + gViewerWindow->setCursor(mLastSetCursor); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleScrollWheel( S32 x, S32 y, S32 clicks ) +{ + if (mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->scrollEvent(0, clicks, MASK_NONE); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleMouseUp( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + { + mMediaSource->mouseUp(x, y); + + // *HACK: LLMediaImplLLMozLib automatically takes focus on mouseup, + // in addition to the onFocusReceived() call below. Undo this. JC + if (!mTakeFocusOnClick) + { + mMediaSource->focus(false); + gViewerWindow->focusClient(); + } + } + + gFocusMgr.setMouseCapture( NULL ); + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseDown(x, y); + + gFocusMgr.setMouseCapture( this ); + + if (mTakeFocusOnClick) + { + setFocus( TRUE ); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleDoubleClick( S32 x, S32 y, MASK mask ) +{ + convertInputCoords(x, y); + + if (mMediaSource) + mMediaSource->mouseLeftDoubleClick( x, y ); + + gFocusMgr.setMouseCapture( this ); + + if (mTakeFocusOnClick) + { + setFocus( TRUE ); + } + + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onFocusReceived() +{ + if (mMediaSource) + { + mMediaSource->focus(true); + + // Set focus for edit menu items + LLEditMenuHandler::gEditMenuHandler = mMediaSource; + } + + LLPanel::onFocusReceived(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onFocusLost() +{ + if (mMediaSource) + { + mMediaSource->focus(false); + + if( LLEditMenuHandler::gEditMenuHandler == mMediaSource ) + { + // Clear focus for edit menu items + LLEditMenuHandler::gEditMenuHandler = NULL; + } + } + + gViewerWindow->focusClient(); + + LLPanel::onFocusLost(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::postBuild () +{ + mVisibleSignal.connect(boost::bind(&LLMediaCtrl::onVisibilityChange, this, _2)); + return TRUE; +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleKeyHere( KEY key, MASK mask ) +{ + BOOL result = FALSE; + + // FIXME: THIS IS SO WRONG. + // Menu keys should be handled by the menu system and not passed to UI elements, but this is how LLTextEditor and LLLineEditor do it... + + if (mMediaSource) + { + if( MASK_CONTROL & mask ) + { + if( 'C' == key ) + { + mMediaSource->copy(); + result = TRUE; + } + else + if( 'V' == key ) + { + mMediaSource->paste(); + result = TRUE; + } + else + if( 'X' == key ) + { + mMediaSource->cut(); + result = TRUE; + } + } + + if(!result) + { + result = mMediaSource->handleKeyHere(key, mask); + } + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::handleVisibilityChange ( BOOL new_visibility ) +{ + llinfos << "visibility changed to " << (new_visibility?"true":"false") << llendl; + if(mMediaSource) + { + mMediaSource->setVisible( new_visibility ); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +BOOL LLMediaCtrl::handleUnicodeCharHere(llwchar uni_char) +{ + BOOL result = FALSE; + + // only accept 'printable' characters, sigh... + if (uni_char >= 32 // discard 'control' characters + && uni_char != 127) // SDL thinks this is 'delete' - yuck. + { + if (mMediaSource) + result = mMediaSource->handleUnicodeCharHere(uni_char); + } + + return result; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onVisibilityChange ( const LLSD& new_visibility ) +{ + // set state of frequent updates automatically if visibility changes + if ( new_visibility.asBoolean() ) + { + mFrequentUpdates = true; + } + else + { + mFrequentUpdates = false; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::reshape( S32 width, S32 height, BOOL called_from_parent ) +{ + S32 screen_width = mIgnoreUIScale ? llround((F32)width * LLUI::sGLScaleFactor.mV[VX]) : width; + S32 screen_height = mIgnoreUIScale ? llround((F32)height * LLUI::sGLScaleFactor.mV[VY]) : height; + +// llinfos << "reshape called with width = " << width << ", height = " << height << llendl; + + // when floater is minimized, these sizes are negative + if ( screen_height > 0 && screen_width > 0 ) + { + mMediaSource->setSize(screen_width, screen_height); + mForceUpdate = true; + } + + LLPanel::reshape( width, height, called_from_parent ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateBack() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->getMediaPlugin()->browse_back(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateForward() +{ + if (mMediaSource && mMediaSource->hasMedia()) + { + mMediaSource->getMediaPlugin()->browse_forward(); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::canNavigateBack() +{ + if (mMediaSource) + return mMediaSource->canNavigateBack(); + else + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::canNavigateForward() +{ + if (mMediaSource) + return mMediaSource->canNavigateForward(); + else + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::set404RedirectUrl( std::string redirect_url ) +{ + if(mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->set_status_redirect( 404, redirect_url ); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::clr404RedirectUrl() +{ + if(mMediaSource && mMediaSource->hasMedia()) + mMediaSource->getMediaPlugin()->set_status_redirect(404, ""); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateTo( std::string url_in, std::string mime_type) +{ + // don't browse to anything that starts with secondlife:// or sl:// + const std::string protocol1 = "secondlife://"; + const std::string protocol2 = "sl://"; + if ((LLStringUtil::compareInsensitive(url_in.substr(0, protocol1.length()), protocol1) == 0) || + (LLStringUtil::compareInsensitive(url_in.substr(0, protocol2.length()), protocol2) == 0)) + { + // TODO: Print out/log this attempt? + // llinfos << "Rejecting attempt to load restricted website :" << urlIn << llendl; + return; + } + + if (mMediaSource) + { + mCurrentNavUrl = url_in; + mMediaSource->navigateTo(url_in, mime_type, mime_type.empty()); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateToLocalPage( const std::string& subdir, const std::string& filename_in ) +{ + std::string language = LLUI::getLanguage(); + std::string delim = gDirUtilp->getDirDelimiter(); + std::string filename; + + filename += subdir; + filename += delim; + filename += filename_in; + + std::string expanded_filename = gDirUtilp->findSkinnedFilename("html", language, filename); + + if (! gDirUtilp->fileExists(expanded_filename)) + { + if (language != "en-us") + { + expanded_filename = gDirUtilp->findSkinnedFilename("html", "en-us", filename); + if (! gDirUtilp->fileExists(expanded_filename)) + { + llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; + return; + } + } + else + { + llwarns << "File " << subdir << delim << filename_in << "not found" << llendl; + return; + } + } + if (mMediaSource) + { + mCurrentNavUrl = expanded_filename; + mMediaSource->navigateTo(expanded_filename, "text/html", false); + } + +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::navigateHome() +{ + if( mHomePageUrl.length() ) + { + if (mMediaSource) + mMediaSource->navigateTo(mHomePageUrl); + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::setHomePageUrl( const std::string urlIn ) +{ + mHomePageUrl = urlIn; +} + +//////////////////////////////////////////////////////////////////////////////// +// +bool LLMediaCtrl::setCaretColor(unsigned int red, unsigned int green, unsigned int blue) +{ + //NOOP + return false; +} +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLMediaCtrl::getHomePageUrl() +{ + return mHomePageUrl; +} + +//////////////////////////////////////////////////////////////////////////////// +// +LLPluginClassMedia* LLMediaCtrl::getMediaPlugin() +{ + return mMediaSource.isNull() ? NULL : mMediaSource->getMediaPlugin(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::draw() +{ + LLPluginClassMedia* media_plugin = NULL; + + if(mMediaSource && mMediaSource->hasMedia()) + { + media_plugin = mMediaSource->getMediaPlugin(); + } + else + { + return; + } + + LLViewerMediaTexture* media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID); + + if (!media_texture ) + { + return; + } + + if ( gRestoreGL == 1 ) + { + LLRect r = getRect(); + reshape( r.getWidth(), r.getHeight(), FALSE ); + return; + }; + + // NOTE: optimization needed here - probably only need to do this once + // unless tearoffs change the parent which they probably do. + const LLUICtrl* ptr = findRootMostFocusRoot(); + if ( ptr && ptr->hasFocus() ) + { + setFrequentUpdates( true ); + } + else + { + setFrequentUpdates( false ); + }; + + // alpha off for this + LLGLSUIDefault gls_ui; + LLGLDisable gls_alphaTest( GL_ALPHA_TEST ); + + gGL.pushMatrix(); + { + if (mIgnoreUIScale) + { + glLoadIdentity(); + // font system stores true screen origin, need to scale this by UI scale factor + // to get render origin for this view (with unit scale) + gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]), + floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]), + LLFontGL::sCurOrigin.mZ); + } + + // scale texture to fit the space using texture coords + gGL.getTexUnit(0)->bind(media_texture); + gGL.color4fv( LLColor4::white.mV ); + F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth(); + F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight(); + + LLRect r = getRect(); + S32 width, height; + S32 x_offset = 0; + S32 y_offset = 0; + + if(mStretchToFill) + { + if(mMaintainAspectRatio) + { + F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight()); + F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight()); + if(media_aspect > view_aspect) + { + // max width, adjusted height + width = r.getWidth(); + height = llmin(llmax(S32(width / media_aspect), 0), r.getHeight()); + } + else + { + // max height, adjusted width + height = r.getHeight(); + width = llmin(llmax(S32(height * media_aspect), 0), r.getWidth()); + } + } + else + { + width = r.getWidth(); + height = r.getHeight(); + } + } + else + { + width = llmin(media_plugin->getWidth(), r.getWidth()); + height = llmin(media_plugin->getHeight(), r.getHeight()); + } + + x_offset = (r.getWidth() - width) / 2; + y_offset = (r.getHeight() - height) / 2; + + // draw the browser + gGL.setSceneBlendType(LLRender::BT_REPLACE); + gGL.begin( LLRender::QUADS ); + if (! media_plugin->getTextureCoordsOpenGL()) + { + // render using web browser reported width and height, instead of trying to invert GL scale + gGL.texCoord2f( max_u, 0.f ); + gGL.vertex2i( x_offset + width, y_offset + height ); + + gGL.texCoord2f( 0.f, 0.f ); + gGL.vertex2i( x_offset, y_offset + height ); + + gGL.texCoord2f( 0.f, max_v ); + gGL.vertex2i( x_offset, y_offset ); + + gGL.texCoord2f( max_u, max_v ); + gGL.vertex2i( x_offset + width, y_offset ); + } + else + { + // render using web browser reported width and height, instead of trying to invert GL scale + gGL.texCoord2f( max_u, max_v ); + gGL.vertex2i( x_offset + width, y_offset + height ); + + gGL.texCoord2f( 0.f, max_v ); + gGL.vertex2i( x_offset, y_offset + height ); + + gGL.texCoord2f( 0.f, 0.f ); + gGL.vertex2i( x_offset, y_offset ); + + gGL.texCoord2f( max_u, 0.f ); + gGL.vertex2i( x_offset + width, y_offset ); + } + gGL.end(); + gGL.setSceneBlendType(LLRender::BT_ALPHA); + } + gGL.popMatrix(); + + // highlight if keyboard focus here. (TODO: this needs some work) + if ( mBorder && mBorder->getVisible() ) + mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) ); + + + LLPanel::draw(); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::convertInputCoords(S32& x, S32& y) +{ + bool coords_opengl = false; + + if(mMediaSource && mMediaSource->hasMedia()) + { + coords_opengl = mMediaSource->getMediaPlugin()->getTextureCoordsOpenGL(); + } + + x = mIgnoreUIScale ? llround((F32)x * LLUI::sGLScaleFactor.mV[VX]) : x; + if ( ! coords_opengl ) + { + y = mIgnoreUIScale ? llround((F32)(y) * LLUI::sGLScaleFactor.mV[VY]) : y; + } + else + { + y = mIgnoreUIScale ? llround((F32)(getRect().getHeight() - y) * LLUI::sGLScaleFactor.mV[VY]) : getRect().getHeight() - y; + }; +} + +//////////////////////////////////////////////////////////////////////////////// +// static +bool LLMediaCtrl::onClickLinkExternalTarget(const LLSD& notification, const LLSD& response ) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + if ( 0 == option ) + { + // open in external browser because we don't support + // creation of our own secondary browser windows + LLWeb::loadURLExternal( notification["payload"]["external_url"].asString() ); + } + return false; +} + +//////////////////////////////////////////////////////////////////////////////// +// inherited from LLViewerMediaObserver +//virtual +void LLMediaCtrl::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_CONTENT_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_TIME_DURATION_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_SIZE_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; + LLRect r = getRect(); + reshape( r.getWidth(), r.getHeight(), FALSE ); + }; + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; + + std::string cursor = self->getCursorName(); + + if(cursor == "arrow") + mLastSetCursor = UI_CURSOR_ARROW; + else if(cursor == "ibeam") + mLastSetCursor = UI_CURSOR_IBEAM; + else if(cursor == "splith") + mLastSetCursor = UI_CURSOR_SIZEWE; + else if(cursor == "splitv") + mLastSetCursor = UI_CURSOR_SIZENS; + else if(cursor == "hand") + mLastSetCursor = UI_CURSOR_HAND; + else // for anything else, default to the arrow + mLastSetCursor = UI_CURSOR_ARROW; + }; + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN, url is " << self->getNavigateURI() << LL_ENDL; + if(mMediaSource && mHideLoading) + { + mMediaSource->suspendUpdates(true); + } + }; + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; + if(mMediaSource && mHideLoading) + { + mMediaSource->suspendUpdates(false); + } + }; + break; + + case MEDIA_EVENT_PROGRESS_UPDATED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; + onClickLinkHref(self); + }; + break; + + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; + onClickLinkNoFollow(self); + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; + }; + break; + }; + + // chain all events to any potential observers of this object. + emitEvent(self, event); +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onClickLinkHref( LLPluginClassMedia* self ) +{ + // retrieve the event parameters + std::string target = self->getClickTarget(); + std::string url = self->getClickURL(); + + // if there is a value for the target + if ( !target.empty() ) + { + if ( target == "_external" ) + { + mExternalUrl = url; + LLSD payload; + payload["external_url"] = mExternalUrl; + LLNotifications::instance().add( "WebLaunchExternalTarget", LLSD(), payload, onClickLinkExternalTarget); + return; + } + } + + const std::string protocol1( "http://" ); + const std::string protocol2( "https://" ); + if( mOpenLinksInExternalBrowser ) + { + if ( !url.empty() ) + { + if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || + LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) + { + LLWeb::loadURLExternal( url ); + } + } + } + else + if( mOpenLinksInInternalBrowser ) + { + if ( !url.empty() ) + { + if ( LLStringUtil::compareInsensitive( url.substr( 0, protocol1.length() ), protocol1 ) == 0 || + LLStringUtil::compareInsensitive( url.substr( 0, protocol2.length() ), protocol2 ) == 0 ) + { + // If we spawn a new LLFloaterHTML, assume we want it to + // follow this LLMediaCtrl's trust for whether or + // not to open secondlife:///app/ links. JC. +// const bool open_links_externally = false; +// LLFloaterHtml::getInstance()->show( +// event_in.mStringPayload, +// "Second Life Browser", +// open_links_externally, +// mTrusted); + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// +void LLMediaCtrl::onClickLinkNoFollow( LLPluginClassMedia* self ) +{ + std::string url = self->getClickURL(); + if (LLSLURL::isSLURLCommand(url) + && !mTrusted) + { + // block handling of this secondlife:///app/ URL + LLNotifications::instance().add("UnableToOpenCommandURL"); + return; + } + + LLURLDispatcher::dispatch(url, this, mTrusted); +} + +//////////////////////////////////////////////////////////////////////////////// +// +std::string LLMediaCtrl::getCurrentNavUrl() +{ + return mCurrentNavUrl; +} + diff --git a/indra/newview/llmediactrl.h b/indra/newview/llmediactrl.h new file mode 100644 index 0000000000..a19b3ad67b --- /dev/null +++ b/indra/newview/llmediactrl.h @@ -0,0 +1,182 @@ +/** + * @file llmediactrl.h + * @brief Web browser UI control + * + * $LicenseInfo:firstyear=2006&license=viewergpl$ + * + * Copyright (c) 2006-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLMediaCtrl_H +#define LL_LLMediaCtrl_H + +#include "llviewermedia.h" + +#include "lluictrl.h" +#include "llframetimer.h" +#include "lldynamictexture.h" + +class LLViewBorder; +class LLUICtrlFactory; + +//////////////////////////////////////////////////////////////////////////////// +// +class LLMediaCtrl : + public LLPanel, + public LLViewerMediaObserver, + public LLViewerMediaEventEmitter +{ + LOG_CLASS(LLMediaCtrl); + +public: + struct Params : public LLInitParam::Block + { + Optional start_url; + + Optional border_visible, + ignore_ui_scale, + hide_loading; + + Optional caret_color; + + Params(); + }; + +protected: + LLMediaCtrl(const Params&); + friend class LLUICtrlFactory; + +public: + virtual ~LLMediaCtrl(); + + void setBorderVisible( BOOL border_visible ); + + // For the tutorial window, we don't want to take focus on clicks, + // as the examples include how to move around with the arrow + // keys. Thus we keep focus on the app by setting this false. + // Defaults to true. + void setTakeFocusOnClick( bool take_focus ); + + // handle mouse related methods + virtual BOOL handleHover( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseUp( S32 x, S32 y, MASK mask ); + virtual BOOL handleMouseDown( S32 x, S32 y, MASK mask ); + virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); + virtual BOOL handleScrollWheel( S32 x, S32 y, S32 clicks ); + + // navigation + void navigateTo( std::string url_in, std::string mime_type = ""); + void navigateBack(); + void navigateHome(); + void navigateForward(); + void navigateToLocalPage( const std::string& subdir, const std::string& filename_in ); + bool canNavigateBack(); + bool canNavigateForward(); + void setOpenInExternalBrowser( bool valIn ); + void setOpenInInternalBrowser( bool valIn ); + std::string getCurrentNavUrl(); + + // By default, we do not handle "secondlife:///app/" SLURLs, because + // those can cause teleports, open windows, etc. We cannot be sure + // that each "click" is actually due to a user action, versus + // Javascript or some other mechanism. However, we need the search + // floater and login page to handle these URLs. Those are safe + // because we control the page content. See DEV-9530. JC. + void setTrusted( bool valIn ); + + void setHomePageUrl( const std::string urlIn ); + std::string getHomePageUrl(); + + // set/clear URL to visit when a 404 page is reached + void set404RedirectUrl( std::string redirect_url ); + void clr404RedirectUrl(); + + // accessor/mutator for flag that indicates if frequent updates to texture happen + bool getFrequentUpdates() { return mFrequentUpdates; }; + void setFrequentUpdates( bool frequentUpdatesIn ) { mFrequentUpdates = frequentUpdatesIn; }; + + void setIgnoreUIScale(bool ignore) { mIgnoreUIScale = ignore; } + bool getIgnoreUIScale() { return mIgnoreUIScale; } + + void setAlwaysRefresh(bool refresh) { mAlwaysRefresh = refresh; } + bool getAlwaysRefresh() { return mAlwaysRefresh; } + + void setForceUpdate(bool force_update) { mForceUpdate = force_update; } + bool getForceUpdate() { return mForceUpdate; } + + LLPluginClassMedia* getMediaPlugin(); + + bool setCaretColor( unsigned int red, unsigned int green, unsigned int blue ); + + + // over-rides + virtual BOOL handleKeyHere( KEY key, MASK mask); + virtual void handleVisibilityChange ( BOOL new_visibility ); + virtual BOOL handleUnicodeCharHere(llwchar uni_char); + virtual void reshape( S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void draw(); + virtual BOOL postBuild(); + + // focus overrides + void onFocusLost(); + void onFocusReceived(); + + // Incoming media event dispatcher + virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + // handlers for individual events (could be done inside the switch in handleMediaEvent, they're just individual functions for clarity) + void onClickLinkHref( LLPluginClassMedia* self ); + void onClickLinkNoFollow( LLPluginClassMedia* self ); + + protected: + void convertInputCoords(S32& x, S32& y); + + private: + void onVisibilityChange ( const LLSD& new_visibility ); + static bool onClickLinkExternalTarget( const LLSD&, const LLSD& ); + + const S32 mTextureDepthBytes; + LLUUID mMediaTextureID; + LLViewBorder* mBorder; + bool mFrequentUpdates; + bool mForceUpdate; + bool mOpenLinksInExternalBrowser; + bool mOpenLinksInInternalBrowser; + bool mTrusted; + std::string mHomePageUrl; + std::string mExternalUrl; + std::string mCurrentNavUrl; + bool mIgnoreUIScale; + bool mAlwaysRefresh; + viewer_media_t mMediaSource; + bool mTakeFocusOnClick; + ECursorType mLastSetCursor; + bool mStretchToFill; + bool mMaintainAspectRatio; + bool mHideLoading; +}; + +#endif // LL_LLMediaCtrl_H diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp index 215cc6940b..3c7716e9c2 100644 --- a/indra/newview/llmemoryview.cpp +++ b/indra/newview/llmemoryview.cpp @@ -35,34 +35,20 @@ #include "indra_constants.h" #include "llmemoryview.h" -#include "llrect.h" -#include "llerror.h" -#include "llgl.h" -#include "llmath.h" -#include "llfontgl.h" -#include "llmemtype.h" - -#include "llcharacter.h" -#include "llui.h" +#include "llappviewer.h" +#include "llallocator_heap_profile.h" +#include "llviewerwindow.h" #include "llviewercontrol.h" -#include "llstat.h" -#include "llfasttimer.h" +#include +#include - -LLMemoryView::LLMemoryView(const std::string& name, const LLRect& rect) -: LLView(name, rect, TRUE), -mDelay(120) +LLMemoryView::LLMemoryView(const LLMemoryView::Params& p) +: LLView(p), + //mDelay(120), + mAlloc(NULL) { - setVisible(FALSE); - mDumpTimer.reset(); - -#ifdef MEM_DUMP_DATA - // clear out file. - LLFILE *dump = LLFile::fopen("memusagedump.txt", "w"); - fclose(dump); -#endif } LLMemoryView::~LLMemoryView() @@ -94,62 +80,101 @@ BOOL LLMemoryView::handleHover(S32 x, S32 y, MASK mask) return FALSE; } -////////////////////////////////////////////////////////////////////////////// - -struct mtv_display_info { - S32 memtype; - const char *desc; - const LLColor4 *color; -}; - -static const LLColor4 red0(0.5f, 0.0f, 0.0f, 1.0f); - -static const struct mtv_display_info mtv_display_table[] = +void LLMemoryView::refreshProfile() { - { LLMemType::MTYPE_INIT, "Init", &LLColor4::white }, - { LLMemType::MTYPE_STARTUP, "Startup", &LLColor4::cyan1 }, - { LLMemType::MTYPE_MAIN, "Main", &LLColor4::cyan2 }, - { LLMemType::MTYPE_IMAGEBASE, "ImageBase", &LLColor4::yellow1 }, - { LLMemType::MTYPE_IMAGERAW, "ImageRaw", &LLColor4::yellow2 }, - { LLMemType::MTYPE_IMAGEFORMATTED, "ImageFmtd", &LLColor4::yellow3 }, - { LLMemType::MTYPE_APPFMTIMAGE, "ViewerImageFmt", &LLColor4::orange1 }, - { LLMemType::MTYPE_APPRAWIMAGE, "ViewerImageRaw", &LLColor4::orange2 }, - { LLMemType::MTYPE_APPAUXRAWIMAGE, "ViewerImageAux", &LLColor4::orange3 }, - { LLMemType::MTYPE_DRAWABLE, "Drawable", &LLColor4::green1 }, - { LLMemType::MTYPE_OBJECT, "ViewerObject", &LLColor4::green2 }, - { LLMemType::MTYPE_PIPELINE, "Pipeline", &LLColor4::green3 }, - { LLMemType::MTYPE_PARTICLES, "Particles", &LLColor4::green4 }, - { LLMemType::MTYPE_SPACE_PARTITION, "Space Partition", &LLColor4::blue2 }, - { LLMemType::MTYPE_VERTEX_DATA, "Vertex Buffer", &LLColor4::blue3 }, - { LLMemType::MTYPE_AVATAR, "Avatar", &LLColor4::purple1 }, - { LLMemType::MTYPE_AVATAR_MESH, "Avatar Mesh", &LLColor4::purple2 }, - { LLMemType::MTYPE_ANIMATION, "Animation", &LLColor4::purple3 }, - { LLMemType::MTYPE_REGIONS, "Regions", &LLColor4::blue1 }, - { LLMemType::MTYPE_VOLUME, "Volume", &LLColor4::pink1 }, - { LLMemType::MTYPE_PRIMITIVE, "Profile", &LLColor4::pink2 }, - { LLMemType::MTYPE_TEMP1, "Temp1", &LLColor4::red1 }, - { LLMemType::MTYPE_TEMP2, "Temp2", &LLColor4::magenta1 }, - { LLMemType::MTYPE_TEMP3, "Temp3", &LLColor4::red2 }, - { LLMemType::MTYPE_TEMP4, "Temp4", &LLColor4::magenta2 }, - { LLMemType::MTYPE_TEMP5, "Temp5", &LLColor4::red3 }, - { LLMemType::MTYPE_TEMP6, "Temp6", &LLColor4::magenta3 }, - { LLMemType::MTYPE_TEMP7, "Temp7", &LLColor4::red4 }, - { LLMemType::MTYPE_TEMP8, "Temp8", &LLColor4::magenta4 }, + /* + LLAllocator & alloc = LLAppViewer::instance()->getAllocator(); + if(alloc.isProfiling()) { + std::string profile_text = alloc.getRawProfile(); - { LLMemType::MTYPE_OTHER, "Other", &red0 }, -}; -static const int MTV_DISPLAY_NUM = LL_ARRAY_SIZE(mtv_display_table); + boost::algorithm::split(mLines, profile_text, boost::bind(std::equal_to(), '\n', _1)); + } else { + mLines.clear(); + } + */ + if (mAlloc == NULL) { + mAlloc = &LLAppViewer::instance()->getAllocator(); + } + + mLines.clear(); + + if(mAlloc->isProfiling()) + { + const LLAllocatorHeapProfile &prof = mAlloc->getProfile(); + for(size_t i = 0; i < prof.mLines.size(); ++i) + { + std::stringstream ss; + ss << "Unfreed Mem: " << (prof.mLines[i].mLiveSize >> 20) << " M Trace: "; + for(size_t k = 0; k < prof.mLines[i].mTrace.size(); ++k) + { + ss << LLMemType::getNameFromID(prof.mLines[i].mTrace[k]) << " "; + } + mLines.push_back(utf8string_to_wstring(ss.str())); + } + } +} void LLMemoryView::draw() { - std::string tdesc; - S32 width = getRect().getWidth(); - S32 height = getRect().getHeight(); + const S32 UPDATE_INTERVAL = 60; + const S32 MARGIN_AMT = 10; + static S32 curUpdate = UPDATE_INTERVAL; + static LLUIColor s_console_color = LLUIColorTable::instance().getColor("ConsoleBackground", LLColor4U::black); + + // setup update interval + if (curUpdate >= UPDATE_INTERVAL) + { + refreshProfile(); + curUpdate = 0; + } + curUpdate++; + + // setup window properly + S32 height = (S32) (gViewerWindow->getVirtualWindowRect().getHeight()*0.75f); + S32 width = (S32) (gViewerWindow->getVirtualWindowRect().getWidth() * 0.9f); + setRect(LLRect().setLeftTopAndSize(getRect().mLeft, getRect().mTop, width, height)); + // setup window color + F32 console_opacity = llclamp(gSavedSettings.getF32("ConsoleBackgroundOpacity"), 0.f, 1.f); + LLColor4 color = s_console_color; + color.mV[VALPHA] *= console_opacity; + LLGLSUIDefault gls_ui; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gl_rect_2d(0, height, width, 0, LLColor4(0.f, 0.f, 0.f, 0.25f)); + gl_rect_2d(0, height, width, 0, color); + LLFontGL * font = LLFontGL::getFontSansSerifSmall(); + + // draw remaining lines + F32 y_pos = 0.f; + F32 y_off = 0.f; + + F32 line_height = font->getLineHeight(); + S32 target_width = width - 2 * MARGIN_AMT; + + // cut off lines on bottom + U32 max_lines = U32((height - 2 * line_height) / line_height); + std::vector::const_iterator end = mLines.end(); + if(mLines.size() > max_lines) { + end = mLines.begin() + max_lines; + } + + y_pos = height - MARGIN_AMT - line_height; + y_off = 0.f; + for (std::vector::const_iterator i = mLines.begin(); i != end; ++i) + { + font->render(*i, 0, MARGIN_AMT, y_pos - y_off, + LLColor4::white, + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::NORMAL, + LLFontGL::DROP_SHADOW, + S32_MAX, + target_width + ); + y_off += line_height; + } + #if MEM_TRACK_TYPE S32 left, top, right, bottom; @@ -267,40 +292,3 @@ void LLMemoryView::draw() LLView::draw(); } - -void LLMemoryView::setDataDumpInterval(float delay) -{ - mDelay = delay; -} - -void LLMemoryView::dumpData() -{ -#if MEM_TRACK_TYPE && MEM_DUMP_DATA - if (mDelay && (mDumpTimer.getElapsedTimeF32() > mDelay )) - { - // reset timer - mDumpTimer.reset(); - // append dump info to text file - LLFILE *dump = LLFile::fopen("memusagedump.txt", "a"); - - if (dump) - { - // write out total memory usage - fprintf (dump, "Total memory in use = %09d (%03d MB)\n", LLMemType::sTotalMem, LLMemType::sTotalMem>>20); - fprintf (dump, "High Water Mark = %09d (%03d MB)\n\n", LLMemType::sMaxTotalMem, LLMemType::sMaxTotalMem>>20); - // dump out usage of 'new' for each memory type - for (S32 i=0; i>20, LLMemType::sMaxMemCount[i], LLMemType::sMaxMemCount[i]>>20, LLMemType::sNewCount[i]); - fprintf (dump, "%s\n", outData.c_str()); - } - } - fprintf (dump, "\n\n"); - - fclose(dump); - } - } -#endif -} diff --git a/indra/newview/llmemoryview.h b/indra/newview/llmemoryview.h index 81466bd6b0..774a52b88b 100644 --- a/indra/newview/llmemoryview.h +++ b/indra/newview/llmemoryview.h @@ -35,10 +35,20 @@ #include "llview.h" +class LLAllocator; + class LLMemoryView : public LLView { public: - LLMemoryView(const std::string& name, const LLRect& rect); + struct Params : public LLInitParam::Block + { + Params() + { + mouse_opaque = true; + visible = false; + } + }; + LLMemoryView(const LLMemoryView::Params&); virtual ~LLMemoryView(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); @@ -46,14 +56,12 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual void draw(); -private: - void setDataDumpInterval(float delay); - void dumpData(); - - float mDelay; - LLFrameTimer mDumpTimer; + void refreshProfile(); private: + std::vector mLines; + LLAllocator* mAlloc; + }; #endif diff --git a/indra/newview/llmenucommands.cpp b/indra/newview/llmenucommands.cpp index ac77a920a5..1666ec1336 100644 --- a/indra/newview/llmenucommands.cpp +++ b/indra/newview/llmenucommands.cpp @@ -35,6 +35,7 @@ #include "llmenucommands.h" #include "imageids.h" +#include "llfloaterreg.h" #include "llfontgl.h" #include "llrect.h" #include "llerror.h" @@ -43,15 +44,13 @@ #include "llagent.h" #include "llcallingcard.h" -#include "llchatbar.h" #include "llviewercontrol.h" #include "llfirstuse.h" #include "llfloaterchat.h" #include "llfloaterdirectory.h" -#include "llfloatermap.h" #include "llfloaterworldmap.h" #include "llgivemoney.h" -#include "llinventoryview.h" +#include "lllineeditor.h" #include "llnotify.h" #include "llstatusbar.h" #include "llimview.h" @@ -67,14 +66,7 @@ #include "llworld.h" #include "llworldmap.h" #include "llfocusmgr.h" - -void handle_track_avatar(const LLUUID& agent_id, const std::string& name) -{ - LLAvatarTracker::instance().track(agent_id, name); - - LLFloaterDirectory::hide(NULL); - LLFloaterWorldMap::show(NULL, TRUE); -} +#include "llnearbychatbar.h" void handle_pay_by_id(const LLUUID& agent_id) { @@ -88,55 +80,23 @@ void handle_mouselook(void*) } -void handle_map(void*) -{ - LLFloaterWorldMap::toggle(NULL); -} - -void handle_mini_map(void*) -{ - LLFloaterMap::toggleInstance(); -} - - -void handle_find(void*) -{ - LLFloaterDirectory::toggleFind(NULL); -} - - -void handle_events(void*) -{ - LLFloaterDirectory::toggleEvents(NULL); -} - - -void handle_inventory(void*) -{ - // We're using the inventory, possibly for the - // first time. - LLFirstUse::useInventory(); - - LLInventoryView::toggleVisibility(NULL); -} - - void handle_chat(void*) { // give focus to chatbar if it's open but not focused - if (gSavedSettings.getBOOL("ChatVisible") && gFocusMgr.childHasKeyboardFocus(gChatBar)) + if (gSavedSettings.getBOOL("ChatVisible") && + gFocusMgr.childHasKeyboardFocus(LLNearbyChatBar::getInstance()->getChatBox())) { - LLChatBar::stopChat(); + LLNearbyChatBar::stopChat(); } else { - LLChatBar::startChat(NULL); + LLNearbyChatBar::startChat(NULL); } } void handle_slash_key(void*) { - // LLChatBar::startChat("/"); + // LLBottomTray::startChat("/"); // // Don't do this, it results in a double-slash in the input field. // Another "/" will be automatically typed for us, because the WM_KEYDOWN event @@ -146,5 +106,5 @@ void handle_slash_key(void*) // menu accelerators that put input focus into a field. And Mac works // the same way. JC - LLChatBar::startChat(NULL); + LLNearbyChatBar::startChat(NULL); } diff --git a/indra/newview/llmenucommands.h b/indra/newview/llmenucommands.h index 03f7a2571c..368c6fe752 100644 --- a/indra/newview/llmenucommands.h +++ b/indra/newview/llmenucommands.h @@ -35,14 +35,8 @@ class LLUUID; -void handle_track_avatar(const LLUUID& agent_id, const std::string& name); void handle_pay_by_id(const LLUUID& agent_id); void handle_mouselook(void*); -void handle_map(void*); -void handle_mini_map(void*); -void handle_find(void*); -void handle_events(void*); -void handle_inventory(void*); void handle_chat(void*); void handle_return_key(void*); void handle_slash_key(void*); diff --git a/indra/newview/llmetricperformancetester.cpp b/indra/newview/llmetricperformancetester.cpp new file mode 100644 index 0000000000..93288c98d7 --- /dev/null +++ b/indra/newview/llmetricperformancetester.cpp @@ -0,0 +1,258 @@ +/** + * @file llmetricperformancetester.cpp + * @brief LLMetricPerformanceTester class implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "indra_constants.h" +#include "llerror.h" +#include "llmath.h" +#include "llfontgl.h" +#include "llsdserialize.h" +#include "llstat.h" +#include "lltreeiterators.h" +#include "llmetricperformancetester.h" + +LLMetricPerformanceTester::name_tester_map_t LLMetricPerformanceTester::sTesterMap ; + +//static +void LLMetricPerformanceTester::initClass() +{ +} +//static +void LLMetricPerformanceTester::cleanClass() +{ + for(name_tester_map_t::iterator iter = sTesterMap.begin() ; iter != sTesterMap.end() ; ++iter) + { + delete iter->second ; + } + sTesterMap.clear() ; +} + +//static +void LLMetricPerformanceTester::addTester(LLMetricPerformanceTester* tester) +{ + if(!tester) + { + llerrs << "invalid tester!" << llendl ; + return ; + } + + std::string name = tester->getName() ; + if(getTester(name)) + { + llerrs << "Tester name is used by some other tester: " << name << llendl ; + return ; + } + + sTesterMap.insert(std::make_pair(name, tester)); + + return ; +} + +//static +LLMetricPerformanceTester* LLMetricPerformanceTester::getTester(std::string label) +{ + name_tester_map_t::iterator found_it = sTesterMap.find(label) ; + if(found_it != sTesterMap.end()) + { + return found_it->second ; + } + + return NULL ; +} + +LLMetricPerformanceTester::LLMetricPerformanceTester(std::string name, BOOL use_default_performance_analysis) + : mName(name), + mBaseSessionp(NULL), + mCurrentSessionp(NULL), + mCount(0), + mUseDefaultPerformanceAnalysis(use_default_performance_analysis) +{ + if(mName == std::string()) + { + llerrs << "invalid name." << llendl ; + } + + LLMetricPerformanceTester::addTester(this) ; +} + +/*virtual*/ +LLMetricPerformanceTester::~LLMetricPerformanceTester() +{ + if(mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if(mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } +} + +void LLMetricPerformanceTester::incLabel() +{ + mCurLabel = llformat("%s-%d", mName.c_str(), mCount++) ; +} +void LLMetricPerformanceTester::preOutputTestResults(LLSD* sd) +{ + incLabel() ; + (*sd)[mCurLabel]["Name"] = mName ; +} +void LLMetricPerformanceTester::postOutputTestResults(LLSD* sd) +{ + LLMutexLock lock(LLFastTimer::sLogLock); + LLFastTimer::sLogQueue.push((*sd)); +} + +void LLMetricPerformanceTester::outputTestResults() +{ + LLSD sd ; + preOutputTestResults(&sd) ; + + outputTestRecord(&sd) ; + + postOutputTestResults(&sd) ; +} + +void LLMetricPerformanceTester::addMetricString(std::string str) +{ + mMetricStrings.push_back(str) ; +} + +const std::string& LLMetricPerformanceTester::getMetricString(U32 index) const +{ + return mMetricStrings[index] ; +} + +void LLMetricPerformanceTester::prePerformanceAnalysis() +{ + mCount = 0 ; + incLabel() ; +} + +// +//default analyzing the performance +// +/*virtual*/ +void LLMetricPerformanceTester::analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) +{ + if(mUseDefaultPerformanceAnalysis)//use default performance analysis + { + prePerformanceAnalysis() ; + + BOOL in_base = (*base).has(mCurLabel) ; + BOOL in_current = (*current).has(mCurLabel) ; + + while(in_base || in_current) + { + LLSD::String label = mCurLabel ; + + if(in_base && in_current) + { + *os << llformat("%s\n", label.c_str()) ; + + for(U32 index = 0 ; index < mMetricStrings.size() ; index++) + { + switch((*current)[label][ mMetricStrings[index] ].type()) + { + case LLSD::TypeInteger: + compareTestResults(os, mMetricStrings[index], + (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; + break ; + case LLSD::TypeReal: + compareTestResults(os, mMetricStrings[index], + (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; + break; + default: + llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ; + } + } + } + + incLabel() ; + in_base = (*base).has(mCurLabel) ; + in_current = (*current).has(mCurLabel) ; + } + }//end of default + else + { + //load the base session + prePerformanceAnalysis() ; + mBaseSessionp = loadTestSession(base) ; + + //load the current session + prePerformanceAnalysis() ; + mCurrentSessionp = loadTestSession(current) ; + + if(!mBaseSessionp || !mCurrentSessionp) + { + llerrs << "memory error during loading test sessions." << llendl ; + } + + //compare + compareTestSessions(os) ; + + //release memory + if(mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if(mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } + } +} + +//virtual +void LLMetricPerformanceTester::compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) +{ + *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; +} + +//virtual +void LLMetricPerformanceTester::compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) +{ + *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; +} + +//virtual +LLMetricPerformanceTester::LLTestSession::~LLTestSession() +{ +} + diff --git a/indra/newview/llmetricperformancetester.h b/indra/newview/llmetricperformancetester.h new file mode 100644 index 0000000000..ab5ccaeb8e --- /dev/null +++ b/indra/newview/llmetricperformancetester.h @@ -0,0 +1,159 @@ +/** + * @file LLMetricPerformanceTester.h + * @brief LLMetricPerformanceTester class definition + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_METRICPERFORMANCETESTER_H +#define LL_METRICPERFORMANCETESTER_H + +class LLMetricPerformanceTester +{ +public: + // + //name passed to the constructor is a unique string for each tester. + //an error is reported if the name is already used by some other tester. + // + LLMetricPerformanceTester(std::string name, BOOL use_default_performance_analysis) ; + virtual ~LLMetricPerformanceTester(); + + // + //return the name of the tester + // + std::string getName() const { return mName ;} + // + //return the number of the test metrics in this tester + // + S32 getNumOfMetricStrings() const { return mMetricStrings.size() ;} + // + //return the metric string at the index + // + const std::string& getMetricString(U32 index) const ; + + // + //this function to compare the test results. + //by default, it compares the test results against the baseline one by one, item by item, + //in the increasing order of the LLSD label counter, starting from the first one. + //you can define your own way to analyze performance by passing FALSE to "use_default_performance_analysis", + //and implement two abstract virtual functions below: loadTestSession(...) and compareTestSessions(...). + // + void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ; + +protected: + // + //insert metric strings used in the tester. + // + void addMetricString(std::string str) ; + + // + //increase LLSD label by 1 + // + void incLabel() ; + + // + //the function to write a set of test results to the log LLSD. + // + void outputTestResults() ; + + // + //compare the test results. + //you can write your own to overwrite the default one. + // + virtual void compareTestResults(std::ofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; + virtual void compareTestResults(std::ofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; + + // + //for performance analysis use + //it defines an interface for the two abstract virtual functions loadTestSession(...) and compareTestSessions(...). + //please make your own test session class derived from it. + // + class LLTestSession + { + public: + virtual ~LLTestSession() ; + }; + + // + //load a test session for log LLSD + //you need to implement it only when you define your own way to analyze performance. + //otherwise leave it empty. + // + virtual LLMetricPerformanceTester::LLTestSession* loadTestSession(LLSD* log) = 0 ; + // + //compare the base session and the target session + //you need to implement it only when you define your own way to analyze performance. + //otherwise leave it empty. + // + virtual void compareTestSessions(std::ofstream* os) = 0 ; + // + //the function to write a set of test results to the log LLSD. + //you have to write you own version of this function. + // + virtual void outputTestRecord(LLSD* sd) = 0 ; + +private: + void preOutputTestResults(LLSD* sd) ; + void postOutputTestResults(LLSD* sd) ; + void prePerformanceAnalysis() ; + +protected: + // + //the unique name string of the tester + // + std::string mName ; + // + //the current label counter for the log LLSD + // + std::string mCurLabel ; + S32 mCount ; + + BOOL mUseDefaultPerformanceAnalysis ; + LLTestSession* mBaseSessionp ; + LLTestSession* mCurrentSessionp ; + + //metrics strings + std::vector< std::string > mMetricStrings ; + +//static members +private: + static void addTester(LLMetricPerformanceTester* tester) ; + +public: + typedef std::map< std::string, LLMetricPerformanceTester* > name_tester_map_t; + static name_tester_map_t sTesterMap ; + + static LLMetricPerformanceTester* getTester(std::string label) ; + static BOOL hasMetricPerformanceTesters() {return !sTesterMap.empty() ;} + + static void initClass() ; + static void cleanClass() ; +}; + +#endif + diff --git a/indra/newview/llmimetypes.cpp b/indra/newview/llmimetypes.cpp index bfbc81aa66..525e89cdff 100644 --- a/indra/newview/llmimetypes.cpp +++ b/indra/newview/llmimetypes.cpp @@ -46,6 +46,8 @@ std::string sDefaultWidgetType; // Returned when we don't know what widget set to use std::string sDefaultImpl; // Returned when we don't know what impl to use +std::string sXMLFilename; + // Squirrel away XML filename so we know how to reset ///////////////////////////////////////////////////////////////////////////// @@ -146,6 +148,8 @@ bool LLMIMETypes::parseMIMETypes(const std::string& xml_filename) sWidgetMap[set_name] = info; } } + + sXMLFilename = xml_filename; return true; } @@ -267,3 +271,23 @@ bool LLMIMETypes::findAllowLooping(const std::string& mime_type) } return allow_looping; } + +// static +bool LLMIMETypes::isTypeHandled(const std::string& mime_type) +{ + mime_info_map_t::const_iterator it = sMap.find(mime_type); + if (it != sMap.end()) + { + return true; + } + return false; +} + +// static +void LLMIMETypes::reload(void*) +{ + sMap.clear(); + sWidgetMap.clear(); + (void)LLMIMETypes::parseMIMETypes(sXMLFilename); +} + diff --git a/indra/newview/llmimetypes.h b/indra/newview/llmimetypes.h index 7a50c29429..b217ce7a81 100644 --- a/indra/newview/llmimetypes.h +++ b/indra/newview/llmimetypes.h @@ -72,6 +72,12 @@ public: static bool findAllowLooping(const std::string& mime_type); // accessor for flag to enable/disable media looping checkbox + static bool isTypeHandled(const std::string& mime_type); + // determines if the specific mime type is handled by the media system + + static void reload(void*); + // re-loads the MIME types file from the file path last passed into parseMIMETypes + public: struct LLMIMEInfo { diff --git a/indra/newview/llmorphview.cpp b/indra/newview/llmorphview.cpp index 18fd20d12a..f562e45770 100644 --- a/indra/newview/llmorphview.cpp +++ b/indra/newview/llmorphview.cpp @@ -47,7 +47,7 @@ #include "lltoolmgr.h" #include "lltoolmorph.h" #include "llviewercamera.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llviewerwindow.h" #include "pipeline.h" @@ -67,9 +67,8 @@ const F32 CAMERA_DIST_STEP = 1.5f; //----------------------------------------------------------------------------- // LLMorphView() //----------------------------------------------------------------------------- -LLMorphView::LLMorphView(const std::string& name, const LLRect& rect) - : - LLView(name, rect, FALSE, FOLLOWS_ALL), +LLMorphView::LLMorphView(const LLMorphView::Params& p) +: LLView(p), mCameraTargetJoint( NULL ), mCameraOffset(-0.5f, 0.05f, 0.07f ), mCameraTargetOffset(0.f, 0.f, 0.05f ), @@ -78,8 +77,7 @@ LLMorphView::LLMorphView(const std::string& name, const LLRect& rect) mCameraYaw( 0.f ), mCameraDist( -1.f ), mCameraDrivenByKeys( FALSE ) -{ -} +{} //----------------------------------------------------------------------------- // initialize() @@ -110,7 +108,7 @@ void LLMorphView::initialize() //----------------------------------------------------------------------------- void LLMorphView::shutdown() { - LLVOAvatar::onCustomizeEnd(); + LLVOAvatarSelf::onCustomizeEnd(); LLVOAvatar *avatarp = gAgent.getAvatarObject(); if(avatarp && !avatarp->isDead()) @@ -137,7 +135,7 @@ void LLMorphView::setVisible(BOOL visible) llassert( !gFloaterCustomize ); gFloaterCustomize = new LLFloaterCustomize(); gFloaterCustomize->fetchInventory(); - gFloaterCustomize->open(); /*Flawfinder: ignore*/ + gFloaterCustomize->openFloater(); // Must do this _after_ gFloaterView is initialized. gFloaterCustomize->switchToDefaultSubpart(); diff --git a/indra/newview/llmorphview.h b/indra/newview/llmorphview.h index 1dd8ef7a5f..493f906c6b 100644 --- a/indra/newview/llmorphview.h +++ b/indra/newview/llmorphview.h @@ -43,7 +43,15 @@ class LLFloaterCustomize; class LLMorphView : public LLView { public: - LLMorphView(const std::string& name, const LLRect& rect); + struct Params : public LLInitParam::Block + { + Params() + { + mouse_opaque(false); + follows.flags(FOLLOWS_ALL); + } + }; + LLMorphView(const LLMorphView::Params&); void initialize(); void shutdown(); diff --git a/indra/newview/llmoveview.cpp b/indra/newview/llmoveview.cpp index a180047875..11c8b03f7f 100644 --- a/indra/newview/llmoveview.cpp +++ b/indra/newview/llmoveview.cpp @@ -36,14 +36,24 @@ // Library includes #include "indra_constants.h" +#include "llparcel.h" // Viewer includes + #include "llagent.h" -#include "llviewercontrol.h" +#include "llvoavatarself.h" // to check gAgent.getAvatarObject()->isSitting() +#include "llbottomtray.h" #include "llbutton.h" -#include "llviewerwindow.h" +#include "llfirsttimetipmanager.h" +#include "llfloaterreg.h" +#include "llfloaterfirsttimetip.h" #include "lljoystickbutton.h" #include "lluictrlfactory.h" +#include "llviewerwindow.h" +#include "llviewercontrol.h" +#include "llselectmgr.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" // // Constants @@ -53,72 +63,89 @@ const F32 MOVE_BUTTON_DELAY = 0.0f; const F32 YAW_NUDGE_RATE = 0.05f; // fraction of normal speed const F32 NUDGE_TIME = 0.25f; // in seconds +const std::string BOTTOM_TRAY_BUTTON_NAME = "movement_btn"; + // // Member functions // // protected LLFloaterMove::LLFloaterMove(const LLSD& key) -: LLFloater(std::string("move floater")) +: LLFloater(key), + mForwardButton(NULL), + mBackwardButton(NULL), + mTurnLeftButton(NULL), + mTurnRightButton(NULL), + mMoveUpButton(NULL), + mMoveDownButton(NULL), + mStopFlyingButton(NULL), + mModeActionsPanel(NULL) +{ +} + +// virtual +BOOL LLFloaterMove::postBuild() { setIsChrome(TRUE); - - const BOOL DONT_OPEN = FALSE; - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_moveview.xml", NULL, DONT_OPEN); - + + mForwardButton = getChild("forward btn"); mForwardButton->setHeldDownDelay(MOVE_BUTTON_DELAY); mBackwardButton = getChild("backward btn"); mBackwardButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mSlideLeftButton = getChild("slide left btn"); - mSlideLeftButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - - mSlideRightButton = getChild("slide right btn"); - mSlideRightButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mTurnLeftButton = getChild("turn left btn"); mTurnLeftButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mTurnLeftButton->setHeldDownCallback( turnLeft ); - + mTurnLeftButton->setHeldDownCallback(boost::bind(&LLFloaterMove::turnLeft, this)); mTurnRightButton = getChild("turn right btn"); mTurnRightButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mTurnRightButton->setHeldDownCallback( turnRight ); + mTurnRightButton->setHeldDownCallback(boost::bind(&LLFloaterMove::turnRight, this)); mMoveUpButton = getChild("move up btn"); - childSetAction("move up btn",moveUp,NULL); mMoveUpButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mMoveUpButton->setHeldDownCallback( moveUp ); + mMoveUpButton->setHeldDownCallback(boost::bind(&LLFloaterMove::moveUp, this)); mMoveDownButton = getChild("move down btn"); - childSetAction("move down btn",moveDown,NULL); mMoveDownButton->setHeldDownDelay(MOVE_BUTTON_DELAY); - mMoveDownButton->setHeldDownCallback( moveDown ); + mMoveDownButton->setHeldDownCallback(boost::bind(&LLFloaterMove::moveDown, this)); + + + mStopFlyingButton = getChild("stop_fly_btn"); + + mModeActionsPanel = getChild("panel_modes"); + + LLButton* btn; + btn = getChild("mode_walk_btn"); + btn->setCommitCallback(boost::bind(&LLFloaterMove::onWalkButtonClick, this)); + + btn = getChild("mode_run_btn"); + btn->setCommitCallback(boost::bind(&LLFloaterMove::onRunButtonClick, this)); + + btn = getChild("mode_fly_btn"); + btn->setCommitCallback(boost::bind(&LLFloaterMove::onFlyButtonClick, this)); + + btn = getChild("stop_fly_btn"); + btn->setCommitCallback(boost::bind(&LLFloaterMove::onStopFlyingButtonClick, this)); + + + + showFlyControls(false); + + initModeTooltips(); + + updatePosition(); + + initModeButtonMap(); + + initMovementMode(); + + LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(LLFloaterMove::sUpdateFlyingStatus); + + return TRUE; } -// virtual -void LLFloaterMove::onClose(bool app_quitting) -{ - LLFloater::onClose(app_quitting); - - if (!app_quitting) - { - gSavedSettings.setBOOL("ShowMovementControls", FALSE); - } -} - -// -// Static member functions -// - -void LLFloaterMove::onOpen() -{ - LLFloater::onOpen(); - gSavedSettings.setBOOL("ShowMovementControls", TRUE); -} - -// protected static +// static F32 LLFloaterMove::getYawRate( F32 time ) { if( time < NUDGE_TIME ) @@ -132,32 +159,449 @@ F32 LLFloaterMove::getYawRate( F32 time ) } } -// protected static -void LLFloaterMove::turnLeft(void *) + +// static +void LLFloaterMove::setFlyingMode(BOOL fly) { - F32 time = getInstance()->mTurnLeftButton->getHeldDownTime(); + LLFloaterMove* instance = LLFloaterReg::findTypedInstance("moveview"); + if (instance) + { + instance->setFlyingModeImpl(fly); + instance->showModeButtons(!fly); + } + if (fly) + { + LLPanelStandStopFlying::setStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STOP_FLYING); + } + else + { + LLPanelStandStopFlying::clearStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STOP_FLYING); + } +} +//static +void LLFloaterMove::setAlwaysRunMode(bool run) +{ + LLFloaterMove* instance = LLFloaterReg::findTypedInstance("moveview"); + if (instance) + { + instance->setAlwaysRunModeImpl(run); + } +} + +void LLFloaterMove::setFlyingModeImpl(BOOL fly) +{ + updateButtonsWithMovementMode(fly ? MM_FLY : (gAgent.getAlwaysRun() ? MM_RUN : MM_WALK)); +} + +void LLFloaterMove::setAlwaysRunModeImpl(bool run) +{ + if (!gAgent.getFlying()) + { + updateButtonsWithMovementMode(run ? MM_RUN : MM_WALK); + } +} + +//static +void LLFloaterMove::setSittingMode(BOOL bSitting) +{ + if (bSitting) + { + LLPanelStandStopFlying::setStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STAND); + } + else + { + LLPanelStandStopFlying::clearStandStopFlyingMode(LLPanelStandStopFlying::SSFM_STAND); + } + enableInstance(!bSitting); +} + +// protected +void LLFloaterMove::turnLeft() +{ + F32 time = mTurnLeftButton->getHeldDownTime(); gAgent.moveYaw( getYawRate( time ) ); } -// protected static -void LLFloaterMove::turnRight(void *) +// protected +void LLFloaterMove::turnRight() { - F32 time = getInstance()->mTurnRightButton->getHeldDownTime(); + F32 time = mTurnRightButton->getHeldDownTime(); gAgent.moveYaw( -getYawRate( time ) ); } -// protected static -void LLFloaterMove::moveUp(void *) +// protected +void LLFloaterMove::moveUp() { // Jumps or flys up, depending on fly state gAgent.moveUp(1); } -// protected static -void LLFloaterMove::moveDown(void *) +// protected +void LLFloaterMove::moveDown() { // Crouches or flys down, depending on fly state gAgent.moveUp(-1); } +////////////////////////////////////////////////////////////////////////// +// Private Section: +////////////////////////////////////////////////////////////////////////// + +void LLFloaterMove::onWalkButtonClick() +{ + setMovementMode(MM_WALK); +} +void LLFloaterMove::onRunButtonClick() +{ + setMovementMode(MM_RUN); +} +void LLFloaterMove::onFlyButtonClick() +{ + setMovementMode(MM_FLY); +} +void LLFloaterMove::onStopFlyingButtonClick() +{ + setMovementMode(gAgent.getAlwaysRun() ? MM_RUN : MM_WALK); +} + +void LLFloaterMove::setMovementMode(const EMovementMode mode) +{ + gAgent.setFlying(MM_FLY == mode); + + switch (mode) + { + case MM_RUN: + gAgent.setAlwaysRun(); + gAgent.setRunning(); + break; + case MM_WALK: + gAgent.clearAlwaysRun(); + gAgent.clearRunning(); + break; + default: + //do nothing for other modes (MM_FLY) + break; + } + // tell the simulator. + gAgent.sendWalkRun(gAgent.getAlwaysRun()); + + updateButtonsWithMovementMode(mode); + + bool bHideModeButtons = MM_FLY == mode + || (gAgent.getAvatarObject() && gAgent.getAvatarObject()->isSitting()); + + showModeButtons(!bHideModeButtons); + + showQuickTips(mode); +} + +void LLFloaterMove::updateButtonsWithMovementMode(const EMovementMode newMode) +{ + showFlyControls(MM_FLY == newMode); + setModeTooltip(newMode); + setModeButtonToggleState(newMode); +} + +void LLFloaterMove::showFlyControls(bool bShow) +{ + mMoveUpButton->setVisible(bShow); + mMoveDownButton->setVisible(bShow); + + // *TODO: mantipov: mStopFlyingButton from the FloaterMove is not used now. + // It was not completly removed until functionality is reviewed by LL + mStopFlyingButton->setVisible(FALSE); +} + +void LLFloaterMove::initModeTooltips() +{ + control_tooltip_map_t walkTipMap; + walkTipMap.insert(std::make_pair(mForwardButton, getString("walk_forward_tooltip"))); + walkTipMap.insert(std::make_pair(mBackwardButton, getString("walk_back_tooltip"))); + mModeControlTooltipsMap[MM_WALK] = walkTipMap; + + control_tooltip_map_t runTipMap; + runTipMap.insert(std::make_pair(mForwardButton, getString("run_forward_tooltip"))); + runTipMap.insert(std::make_pair(mBackwardButton, getString("run_back_tooltip"))); + mModeControlTooltipsMap[MM_RUN] = runTipMap; + + control_tooltip_map_t flyTipMap; + flyTipMap.insert(std::make_pair(mForwardButton, getString("fly_forward_tooltip"))); + flyTipMap.insert(std::make_pair(mBackwardButton, getString("fly_back_tooltip"))); + mModeControlTooltipsMap[MM_FLY] = flyTipMap; + + setModeTooltip(MM_WALK); +} + +void LLFloaterMove::initModeButtonMap() +{ + mModeControlButtonMap[MM_WALK] = getChild("mode_walk_btn"); + mModeControlButtonMap[MM_RUN] = getChild("mode_run_btn"); + mModeControlButtonMap[MM_FLY] = getChild("mode_fly_btn"); +} + +void LLFloaterMove::initMovementMode() +{ + EMovementMode initMovementMode = gAgent.getAlwaysRun() ? MM_RUN : MM_WALK; + if (gAgent.getFlying()) + { + initMovementMode = MM_FLY; + } + setMovementMode(initMovementMode); + + if (gAgent.getAvatarObject()) + { + setEnabled(!gAgent.getAvatarObject()->isSitting()); + } +} + +void LLFloaterMove::setModeTooltip(const EMovementMode mode) +{ + llassert_always(mModeControlTooltipsMap.end() != mModeControlTooltipsMap.find(mode)); + control_tooltip_map_t controlsTipMap = mModeControlTooltipsMap[mode]; + control_tooltip_map_t::const_iterator it = controlsTipMap.begin(); + for (; it != controlsTipMap.end(); ++it) + { + LLView* ctrl = it->first; + std::string tooltip = it->second; + ctrl->setToolTip(tooltip); + } +} + +/** + * Updates position of the floater to be center aligned with Move button. + * + * Because Tip floater created as dependent floater this method + * must be called before "showQuickTips()" to get Tip floater be positioned at the right side of the floater + */ +void LLFloaterMove::updatePosition() +{ + LLBottomTray* tray = LLBottomTray::getInstance(); + if (!tray) return; + + LLButton* movement_btn = tray->getChild(BOTTOM_TRAY_BUTTON_NAME); + + //align centers of a button and a floater + S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2; + + S32 y = 0; + if (!mModeActionsPanel->getVisible()) + { + y = mModeActionsPanel->getRect().getHeight(); + } + setOrigin(x, y); +} + +//static +void LLFloaterMove::sUpdateFlyingStatus() +{ + LLFloaterMove *floater = LLFloaterReg::findTypedInstance("moveview"); + if (floater) floater->mModeControlButtonMap[MM_FLY]->setEnabled(gAgent.canFly()); + +} + +void LLFloaterMove::showModeButtons(BOOL bShow) +{ + if (mModeActionsPanel->getVisible() == bShow) + return; + mModeActionsPanel->setVisible(bShow); + + LLRect rect = getRect(); + + static S32 height = mModeActionsPanel->getRect().getHeight(); + S32 newHeight = getRect().getHeight(); + if (!bShow) + { + newHeight -= height; + } + else + { + newHeight += height; + } + rect.setLeftTopAndSize(rect.mLeft, rect.mTop, rect.getWidth(), newHeight); + reshape(rect.getWidth(), rect.getHeight()); + setRect(rect); +} +//static +void LLFloaterMove::enableInstance(BOOL bEnable) +{ + LLFloaterMove* instance = LLFloaterReg::findTypedInstance("moveview"); + if (instance) + { + instance->setEnabled(bEnable); + instance->showModeButtons(bEnable); + } +} + +void LLFloaterMove::onOpen(const LLSD& key) +{ + updatePosition(); + + sUpdateFlyingStatus(); +} + +void LLFloaterMove::showQuickTips(const EMovementMode mode) +{ + LLFirstTimeTipsManager::EFirstTimeTipType tipType = LLFirstTimeTipsManager::FTT_MOVE_WALK; + switch (mode) + { + case MM_FLY: tipType = LLFirstTimeTipsManager::FTT_MOVE_FLY; break; + case MM_RUN: tipType = LLFirstTimeTipsManager::FTT_MOVE_RUN; break; + case MM_WALK: tipType = LLFirstTimeTipsManager::FTT_MOVE_WALK; break; + default: llwarns << "Quick Tip type was not detected, FTT_MOVE_WALK will be used" << llendl; + } + + LLFirstTimeTipsManager::showTipsFor(tipType, this, LLFirstTimeTipsManager::TPA_POS_LEFT_ALIGN_TOP); +} + +void LLFloaterMove::setModeButtonToggleState(const EMovementMode mode) +{ + llassert_always(mModeControlButtonMap.end() != mModeControlButtonMap.find(mode)); + + mode_control_button_map_t::const_iterator it = mModeControlButtonMap.begin(); + for (; it != mModeControlButtonMap.end(); ++it) + { + it->second->setToggleState(FALSE); + } + + mModeControlButtonMap[mode]->setToggleState(TRUE); +} + + + +/************************************************************************/ +/* LLPanelStandStopFlying */ +/************************************************************************/ +LLPanelStandStopFlying::LLPanelStandStopFlying() : + mStandButton(NULL), + mStopFlyingButton(NULL) +{ + // make sure we have the only instance of this class + static bool b = true; + llassert_always(b); + b=false; +} + +// static +inline LLPanelStandStopFlying* LLPanelStandStopFlying::getInstance() +{ + static LLPanelStandStopFlying* panel = getStandStopFlyingPanel(); + return panel; +} + +//static +void LLPanelStandStopFlying::setStandStopFlyingMode(EStandStopFlyingMode mode) +{ + LLPanelStandStopFlying* panel = getInstance(); + + panel->mStandButton->setVisible(SSFM_STAND == mode); + panel->mStopFlyingButton->setVisible(SSFM_STOP_FLYING == mode); + + //visibility of it should be updated after updating visibility of the buttons + panel->setVisible(TRUE); +} + +//static +void LLPanelStandStopFlying::clearStandStopFlyingMode(EStandStopFlyingMode mode) +{ + LLPanelStandStopFlying* panel = getInstance(); + switch(mode) { + case SSFM_STAND: + panel->mStandButton->setVisible(FALSE); + break; + case SSFM_STOP_FLYING: + panel->mStopFlyingButton->setVisible(FALSE); + break; + default: + llerrs << "Unexpected EStandStopFlyingMode is passed: " << mode << llendl; + } + +} + +BOOL LLPanelStandStopFlying::postBuild() +{ + mStandButton = getChild("stand_btn"); + mStandButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStandButtonClick, this)); + mStandButton->setCommitCallback(boost::bind(&LLFloaterMove::enableInstance, TRUE)); + mStandButton->setVisible(FALSE); + + mStopFlyingButton = getChild("stop_fly_btn"); + mStopFlyingButton->setCommitCallback(boost::bind(&LLFloaterMove::setFlyingMode, FALSE)); + mStopFlyingButton->setCommitCallback(boost::bind(&LLPanelStandStopFlying::onStopFlyingButtonClick, this)); + mStopFlyingButton->setVisible(FALSE); + + return TRUE; +} + +//virtual +void LLPanelStandStopFlying::setVisible(BOOL visible) +{ + //we dont need to show the panel if these buttons are not activated + if (visible && !mStandButton->getVisible() && !mStopFlyingButton->getVisible()) visible = false; + + if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) visible = false; + + if (visible) + { + updatePosition(); + } + + LLPanel::setVisible(visible); +} + +////////////////////////////////////////////////////////////////////////// +// Private Section +////////////////////////////////////////////////////////////////////////// + +//static +LLPanelStandStopFlying* LLPanelStandStopFlying::getStandStopFlyingPanel() +{ + LLPanelStandStopFlying* panel = new LLPanelStandStopFlying(); + LLUICtrlFactory::getInstance()->buildPanel(panel, "panel_stand_stop_flying.xml"); + + panel->setVisible(FALSE); + LLUI::getRootView()->addChild(panel); + + llinfos << "Build LLPanelStandStopFlying panel" << llendl; + + panel->updatePosition(); + return panel; +} + +void LLPanelStandStopFlying::onStandButtonClick() +{ + LLSelectMgr::getInstance()->deselectAllForStandingUp(); + gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + + setFocus(FALSE); // EXT-482 + setVisible(FALSE); +} + +void LLPanelStandStopFlying::onStopFlyingButtonClick() +{ + gAgent.setFlying(FALSE); + + setFocus(FALSE); // EXT-482 + setVisible(FALSE); +} + +/** + * Updates position of the Stand & Stop Flying panel to be center aligned with Move button. + */ +void LLPanelStandStopFlying::updatePosition() +{ + + LLBottomTray* tray = LLBottomTray::getInstance(); + if (!tray) return; + + LLButton* movement_btn = tray->getChild(BOTTOM_TRAY_BUTTON_NAME); + + //align centers of a button and a floater + S32 x = movement_btn->calcScreenRect().getCenterX() - getRect().getWidth()/2; + + S32 y = tray->getRect().getHeight(); + + setOrigin(x, y); +} + + // EOF diff --git a/indra/newview/llmoveview.h b/indra/newview/llmoveview.h index e772551efe..6e6af9b693 100644 --- a/indra/newview/llmoveview.h +++ b/indra/newview/llmoveview.h @@ -44,40 +44,118 @@ class LLJoystickAgentSlide; // Classes // class LLFloaterMove -: public LLFloater, - public LLFloaterSingleton +: public LLFloater { - friend class LLUISingleton >; - -protected: + friend class LLFloaterReg; + +private: LLFloaterMove(const LLSD& key); ~LLFloaterMove() {} - public: - /*virtual*/ void onOpen(); - /*virtual*/ void onClose(bool app_quitting); + /*virtual*/ BOOL postBuild(); static F32 getYawRate(F32 time); + static void setFlyingMode(BOOL fly); + void setFlyingModeImpl(BOOL fly); + static void setAlwaysRunMode(bool run); + void setAlwaysRunModeImpl(bool run); + static void setSittingMode(BOOL bSitting); + static void enableInstance(BOOL bEnable); + /*virtual*/ void onOpen(const LLSD& key); + + // *HACK: due to hard enough to have this control aligned with "Move" button while resizing + // let update its position in each frame + /*virtual*/ void draw(){updatePosition(); LLFloater::draw();} + + static void sUpdateFlyingStatus(); protected: - static void turnLeftNudge(void* userdata); - static void turnLeft(void* userdata); - - static void turnRightNudge(void* userdata); - static void turnRight(void* userdata); + void turnLeft(); + void turnRight(); - static void moveUp(void* userdata); - static void moveDown(void* userdata); + void moveUp(); + void moveDown(); + +private: + typedef enum movement_mode_t + { + MM_WALK, + MM_RUN, + MM_FLY + } EMovementMode; + void onWalkButtonClick(); + void onRunButtonClick(); + void onFlyButtonClick(); + void onStopFlyingButtonClick(); + void initMovementMode(); + void setMovementMode(const EMovementMode mode); + void showFlyControls(bool bShow); + void initModeTooltips(); + void setModeTooltip(const EMovementMode mode); + void showQuickTips(const EMovementMode mode); + void initModeButtonMap(); + void setModeButtonToggleState(const EMovementMode mode); + void updateButtonsWithMovementMode(const EMovementMode newMode); + void updatePosition(); + void showModeButtons(BOOL bShow); public: + LLJoystickAgentTurn* mForwardButton; LLJoystickAgentTurn* mBackwardButton; - LLJoystickAgentSlide* mSlideLeftButton; - LLJoystickAgentSlide* mSlideRightButton; LLButton* mTurnLeftButton; LLButton* mTurnRightButton; LLButton* mMoveUpButton; LLButton* mMoveDownButton; +private: + LLButton* mStopFlyingButton; + LLPanel* mModeActionsPanel; + + typedef std::map control_tooltip_map_t; + typedef std::map mode_control_tooltip_map_t; + mode_control_tooltip_map_t mModeControlTooltipsMap; + + typedef std::map mode_control_button_map_t; + mode_control_button_map_t mModeControlButtonMap; + +}; + + +/** + * This class contains Stand Up and Stop Flying buttons displayed above Move button in bottom tray + */ +class LLPanelStandStopFlying : public LLPanel +{ +public: + typedef enum stand_stop_flying_mode_t + { + SSFM_STAND, + SSFM_STOP_FLYING + } EStandStopFlyingMode; + + static LLPanelStandStopFlying* getInstance(); + static void setStandStopFlyingMode(EStandStopFlyingMode mode); + static void clearStandStopFlyingMode(EStandStopFlyingMode mode); + /*virtual*/ BOOL postBuild(); + /*virtual*/ void setVisible(BOOL visible); + + // *HACK: due to hard enough to have this control aligned with "Move" button while resizing + // let update its position in each frame + /*virtual*/ void draw(){updatePosition(); LLPanel::draw();} + + +protected: + LLPanelStandStopFlying(); + + +private: + static LLPanelStandStopFlying* getStandStopFlyingPanel(); + void onStandButtonClick(); + void onStopFlyingButtonClick(); + void updatePosition(); + + LLButton* mStandButton; + LLButton* mStopFlyingButton; }; diff --git a/indra/newview/llmutelist.cpp b/indra/newview/llmutelist.cpp index a840b59140..b47d6f4214 100644 --- a/indra/newview/llmutelist.cpp +++ b/indra/newview/llmutelist.cpp @@ -71,6 +71,7 @@ #include "lluistring.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" +#include "lltrans.h" namespace { @@ -111,11 +112,6 @@ static LLDispatchEmptyMuteList sDispatchEmptyMuteList; //----------------------------------------------------------------------------- // LLMute() //----------------------------------------------------------------------------- -const char BY_NAME_SUFFIX[] = " (by name)"; -const char AGENT_SUFFIX[] = " (resident)"; -const char OBJECT_SUFFIX[] = " (object)"; -const char GROUP_SUFFIX[] = " (group)"; - LLMute::LLMute(const LLUUID& id, const std::string& name, EType type, U32 flags) : mID(id), @@ -149,16 +145,16 @@ std::string LLMute::getDisplayName() const { case BY_NAME: default: - name_with_suffix += BY_NAME_SUFFIX; + name_with_suffix += " " + LLTrans::getString("MuteByName"); break; case AGENT: - name_with_suffix += AGENT_SUFFIX; + name_with_suffix += " " + LLTrans::getString("MuteAgent"); break; case OBJECT: - name_with_suffix += OBJECT_SUFFIX; + name_with_suffix += " " + LLTrans::getString("MuteObject"); break; case GROUP: - name_with_suffix += GROUP_SUFFIX; + name_with_suffix += " " + LLTrans::getString("MuteGroup"); break; } return name_with_suffix; @@ -169,7 +165,7 @@ void LLMute::setFromDisplayName(const std::string& display_name) size_t pos = 0; mName = display_name; - pos = mName.rfind(GROUP_SUFFIX); + pos = mName.rfind(" " + LLTrans::getString("MuteGroup")); if (pos != std::string::npos) { mName.erase(pos); @@ -177,7 +173,7 @@ void LLMute::setFromDisplayName(const std::string& display_name) return; } - pos = mName.rfind(OBJECT_SUFFIX); + pos = mName.rfind(" " + LLTrans::getString("MuteObject")); if (pos != std::string::npos) { mName.erase(pos); @@ -185,7 +181,7 @@ void LLMute::setFromDisplayName(const std::string& display_name) return; } - pos = mName.rfind(AGENT_SUFFIX); + pos = mName.rfind(" " + LLTrans::getString("MuteAgent")); if (pos != std::string::npos) { mName.erase(pos); @@ -193,7 +189,7 @@ void LLMute::setFromDisplayName(const std::string& display_name) return; } - pos = mName.rfind(BY_NAME_SUFFIX); + pos = mName.rfind(" " + LLTrans::getString("MuteByName")); if (pos != std::string::npos) { mName.erase(pos); @@ -501,11 +497,8 @@ void LLMuteList::updateRemove(const LLMute& mute) gAgent.sendReliableMessage(); } -void notify_automute_callback(const LLUUID& agent_id, const std::string& first_name, const std::string& last_name, BOOL is_group, void* user_data) +void notify_automute_callback(const LLUUID& agent_id, const std::string& first_name, const std::string& last_name, BOOL is_group, LLMuteList::EAutoReason reason) { - U32 temp_data = (U32) (uintptr_t) user_data; - LLMuteList::EAutoReason reason = (LLMuteList::EAutoReason)temp_data; - std::string notif_name; switch (reason) { @@ -561,18 +554,18 @@ BOOL LLMuteList::autoRemove(const LLUUID& agent_id, const EAutoReason reason, co if (gCacheName->getName(agent_id, cache_first, cache_last)) { // name in cache, call callback directly - notify_automute_callback(agent_id, cache_first, cache_last, FALSE, (void *)reason); + notify_automute_callback(agent_id, cache_first, cache_last, FALSE, reason); } else { // not in cache, lookup name from cache - gCacheName->getNameFromUUID(agent_id, FALSE, notify_automute_callback, (void *)reason); + gCacheName->get(agent_id, FALSE, boost::bind(¬ify_automute_callback, _1, _2, _3, _4, reason)); } } else { // call callback directly - notify_automute_callback(agent_id, first_name, last_name, FALSE, (void *)reason); + notify_automute_callback(agent_id, first_name, last_name, FALSE, reason); } } diff --git a/indra/newview/llnamebox.cpp b/indra/newview/llnamebox.cpp index 98c7a4b631..2f4a266198 100644 --- a/indra/newview/llnamebox.cpp +++ b/indra/newview/llnamebox.cpp @@ -41,25 +41,19 @@ #include "lluuid.h" #include "llcachename.h" -#include "llagent.h" // statics std::set LLNameBox::sInstances; +static LLDefaultChildRegistry::Register r("name_box"); -LLNameBox::LLNameBox(const std::string& name, const LLRect& rect, const LLUUID& name_id, BOOL is_group, const LLFontGL* font, BOOL mouse_opaque) -: LLTextBox(name, rect, std::string("(retrieving)"), font, mouse_opaque), - mNameID(name_id) + +LLNameBox::LLNameBox(const Params& p) +: LLTextBox(p) { + mNameID = LLUUID::null; LLNameBox::sInstances.insert(this); - if(!name_id.isNull()) - { - setNameID(name_id, is_group); - } - else - { - setText(LLStringUtil::null); - } + setText(LLStringUtil::null); } LLNameBox::~LLNameBox() diff --git a/indra/newview/llnamebox.h b/indra/newview/llnamebox.h index f76850bd3c..3edb36883f 100644 --- a/indra/newview/llnamebox.h +++ b/indra/newview/llnamebox.h @@ -44,10 +44,15 @@ class LLNameBox : public LLTextBox { public: - LLNameBox(const std::string& name, const LLRect& rect, const LLUUID& name_id = LLUUID::null, BOOL is_group = FALSE, const LLFontGL* font = NULL, BOOL mouse_opaque = TRUE ); - // By default, follows top and left and is mouse-opaque. - // If no text, text = name. - // If no font, uses default system font. + struct Params : public LLInitParam::Block + { + Optional is_group; + + Params() + : is_group("is_group", false) + {} + }; + virtual ~LLNameBox(); void setNameID(const LLUUID& name_id, BOOL is_group); @@ -57,6 +62,10 @@ public: static void refreshAll(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group); +protected: + LLNameBox (const Params&); + + friend class LLUICtrlFactory; private: static std::set sInstances; diff --git a/indra/newview/llnameeditor.cpp b/indra/newview/llnameeditor.cpp index e4a65734d8..65601da7da 100644 --- a/indra/newview/llnameeditor.cpp +++ b/indra/newview/llnameeditor.cpp @@ -34,7 +34,6 @@ #include "llnameeditor.h" #include "llcachename.h" -#include "llagent.h" #include "llfontgl.h" @@ -43,40 +42,22 @@ #include "llstring.h" #include "llui.h" -static LLRegisterWidget r("name_editor"); +static LLDefaultChildRegistry::Register r("name_editor"); // statics std::set LLNameEditor::sInstances; -LLNameEditor::LLNameEditor(const std::string& name, const LLRect& rect, - const LLUUID& name_id, - BOOL is_group, - const LLFontGL* glfont, - S32 max_text_length, - void (*commit_callback)(LLUICtrl* caller, void* user_data), - void (*keystroke_callback)(LLLineEditor* caller, void* user_data), - void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data), - void* userdata, - LLLinePrevalidateFunc prevalidate_func) -: LLLineEditor(name, rect, - std::string("(retrieving)"), - glfont, - max_text_length, - commit_callback, - keystroke_callback, - focus_lost_callback, - userdata, - prevalidate_func), - mNameID(name_id) +LLNameEditor::LLNameEditor(const LLNameEditor::Params& p) +: LLLineEditor(p) { LLNameEditor::sInstances.insert(this); - if(!name_id.isNull()) + + if(!p.name_id().isNull()) { - setNameID(name_id, is_group); + setNameID(p.name_id, p.is_group); } } - LLNameEditor::~LLNameEditor() { LLNameEditor::sInstances.erase(this); @@ -141,35 +122,3 @@ LLSD LLNameEditor::getValue() const return LLSD(mNameID); } -LLView* LLNameEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("name_editor"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - S32 max_text_length = 128; - node->getAttributeS32("max_length", max_text_length); - - LLFontGL* font = LLView::selectFont(node); - - LLUICtrlCallback commit_callback = NULL; - - LLNameEditor* line_editor = new LLNameEditor(name, - rect, - LLUUID::null, FALSE, - font, - max_text_length, - commit_callback); - - std::string label; - if(node->getAttributeString("label", label)) - { - line_editor->setLabel(label); - } - line_editor->setColorParameters(node); - line_editor->initFromXML(node, parent); - - return line_editor; -} diff --git a/indra/newview/llnameeditor.h b/indra/newview/llnameeditor.h index bc5a67866c..99e03a1166 100644 --- a/indra/newview/llnameeditor.h +++ b/indra/newview/llnameeditor.h @@ -46,24 +46,23 @@ class LLNameEditor : public LLLineEditor { public: - LLNameEditor(const std::string& name, const LLRect& rect, - const LLUUID& name_id = LLUUID::null, - BOOL is_group = FALSE, - const LLFontGL* glfont = NULL, - S32 max_text_length = 254, - void (*commit_callback)(LLUICtrl* caller, void* user_data) = NULL, - void (*keystroke_callback)(LLLineEditor* caller, void* user_data) = NULL, - void (*focus_lost_callback)(LLFocusableElement* caller, void* user_data) = NULL, - void* userdata = NULL, - LLLinePrevalidateFunc prevalidate_func = NULL); - // By default, follows top and left and is mouse-opaque. - // If no text, text = name. - // If no font, uses default system font. + struct Params : public LLInitParam::Block + { + Optional is_group; + Optional name_id; + Params() + : is_group("is_group"), + name_id("name_id") + {} + }; + +protected: + LLNameEditor(const Params&); + friend class LLUICtrlFactory; +public: virtual ~LLNameEditor(); - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - void setNameID(const LLUUID& name_id, BOOL is_group); void refresh(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index baf06567c1..1b82c2dc18 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -37,53 +37,47 @@ #include "llnamelistctrl.h" #include "llcachename.h" -#include "llagent.h" #include "llinventory.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" +#include "llscrolllistcolumn.h" +#include "llsdparam.h" -static LLRegisterWidget r("name_list"); +static LLDefaultChildRegistry::Register r("name_list"); -// statics -std::set LLNameListCtrl::sInstances; - -LLNameListCtrl::LLNameListCtrl(const std::string& name, - const LLRect& rect, - LLUICtrlCallback cb, - void* userdata, - BOOL allow_multiple_selection, - BOOL draw_border, - S32 name_column_index, - const std::string& tooltip) -: LLScrollListCtrl(name, rect, cb, userdata, allow_multiple_selection, - draw_border), - mNameColumnIndex(name_column_index), - mAllowCallingCardDrop(FALSE) +void LLNameListCtrl::NameTypeNames::declareValues() { - setToolTip(tooltip); - LLNameListCtrl::sInstances.insert(this); + declare("INDIVIDUAL", LLNameListCtrl::INDIVIDUAL); + declare("GROUP", LLNameListCtrl::GROUP); + declare("SPECIAL", LLNameListCtrl::SPECIAL); } - -// virtual -LLNameListCtrl::~LLNameListCtrl() +LLNameListCtrl::Params::Params() +: name_column(""), + allow_calling_card_drop("allow_calling_card_drop", false) { - LLNameListCtrl::sInstances.erase(this); + name = "name_list"; } +LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) +: LLScrollListCtrl(p), + mAllowCallingCardDrop(p.allow_calling_card_drop), + mNameColumn(p.name_column.column_name), + mNameColumnIndex(p.name_column.column_index) +{} // public -BOOL LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, +void LLNameListCtrl::addNameItem(const LLUUID& agent_id, EAddPosition pos, BOOL enabled, std::string& suffix) { //llinfos << "LLNameListCtrl::addNameItem " << agent_id << llendl; std::string fullname; - BOOL result = gCacheName->getFullName(agent_id, fullname); + gCacheName->getFullName(agent_id, fullname); fullname.append(suffix); addStringUUIDItem(fullname, agent_id, pos, enabled); - - return result; } // virtual, public @@ -138,75 +132,70 @@ BOOL LLNameListCtrl::handleDragAndDrop( void LLNameListCtrl::addGroupNameItem(const LLUUID& group_id, EAddPosition pos, BOOL enabled) { - //llinfos << "LLNameListCtrl::addGroupNameItem " << group_id << llendl; - std::string group_name; - gCacheName->getGroupName(group_id, group_name); - addStringUUIDItem(group_name, group_id, pos, enabled); + NameItem item; + item.value = group_id; + item.enabled = enabled; + item.target = GROUP; + + addNameItemRow(item, pos); } // public -void LLNameListCtrl::addGroupNameItem(LLScrollListItem* item, EAddPosition pos) - +void LLNameListCtrl::addGroupNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos) { - //llinfos << "LLNameListCtrl::addGroupNameItem " << item->getUUID() << llendl; - - std::string group_name; - gCacheName->getGroupName(item->getUUID(), group_name); - - LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); - ((LLScrollListText*)cell)->setText( std::string(group_name) ); - - addItem(item, pos); + item.target = GROUP; + addNameItemRow(item, pos); } -BOOL LLNameListCtrl::addNameItem(LLScrollListItem* item, EAddPosition pos) +void LLNameListCtrl::addNameItem(LLNameListCtrl::NameItem& item, EAddPosition pos) { - //llinfos << "LLNameListCtrl::addNameItem " << item->getUUID() << llendl; - - std::string fullname; - BOOL result = gCacheName->getFullName(item->getUUID(), fullname); - - LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); - ((LLScrollListText*)cell)->setText( fullname ); - - addItem(item, pos); - - // this column is resizable - LLScrollListColumn* columnp = getColumn(mNameColumnIndex); - if (columnp && columnp->mHeader) - { - columnp->mHeader->setHasResizableElement(TRUE); - } - - return result; + item.target = INDIVIDUAL; + addNameItemRow(item, pos); } -LLScrollListItem* LLNameListCtrl::addElement(const LLSD& value, EAddPosition pos, void* userdata) +LLScrollListItem* LLNameListCtrl::addElement(const LLSD& element, EAddPosition pos, void* userdata) { - LLScrollListItem* item = LLScrollListCtrl::addElement(value, pos, userdata); + LLNameListCtrl::NameItem item_params; + LLParamSDParser::instance().readSD(element, item_params); + item_params.userdata = userdata; + return addNameItemRow(item_params, pos); +} + + +LLScrollListItem* LLNameListCtrl::addNameItemRow(const LLNameListCtrl::NameItem& name_item, EAddPosition pos) +{ + LLScrollListItem* item = LLScrollListCtrl::addRow(name_item, pos); + if (!item) return NULL; // use supplied name by default - std::string fullname = value["name"].asString(); - if (value["target"].asString() == "GROUP") + std::string fullname = name_item.name; + switch(name_item.target) { - gCacheName->getGroupName(item->getUUID(), fullname); + case GROUP: + gCacheName->getGroupName(name_item.value().asUUID(), fullname); // fullname will be "nobody" if group not found - } - else if (value["target"].asString() == "SPECIAL") - { + break; + case SPECIAL: // just use supplied name - } - else // normal resident - { - std::string name; - if (gCacheName->getFullName(item->getUUID(), name)) + break; + case INDIVIDUAL: { - fullname = name; + std::string name; + if (gCacheName->getFullName(name_item.value().asUUID(), name)) + { + fullname = name; + } + break; } + default: + break; } - LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); - ((LLScrollListText*)cell)->setText( fullname ); + LLScrollListCell* cell = item->getColumn(mNameColumnIndex); + if (cell) + { + cell->setValue(fullname); + } dirtyColumns(); @@ -259,9 +248,11 @@ void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first, if (item->getUUID() == id) { LLScrollListCell* cell = (LLScrollListCell*)item->getColumn(0); - cell = (LLScrollListCell*)item->getColumn(mNameColumnIndex); - - ((LLScrollListText*)cell)->setText( fullname ); + cell = item->getColumn(mNameColumnIndex); + if (cell) + { + cell->setValue(fullname); + } } } @@ -273,186 +264,24 @@ void LLNameListCtrl::refresh(const LLUUID& id, const std::string& first, void LLNameListCtrl::refreshAll(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) { - std::set::iterator it; - for (it = LLNameListCtrl::sInstances.begin(); - it != LLNameListCtrl::sInstances.end(); - ++it) + LLInstanceTracker::instance_iter it; + for (it = beginInstances(); it != endInstances(); ++it) { LLNameListCtrl* ctrl = *it; ctrl->refresh(id, first, last, is_group); } } -// virtual -LLXMLNodePtr LLNameListCtrl::getXML(bool save_children) const +void LLNameListCtrl::updateColumns() { - LLXMLNodePtr node = LLScrollListCtrl::getXML(); + LLScrollListCtrl::updateColumns(); - node->createChild("allow_calling_card_drop", TRUE)->setBoolValue(mAllowCallingCardDrop); - - if (mNameColumnIndex != 0) + if (!mNameColumn.empty()) { - node->createChild("name_column_index", TRUE)->setIntValue(mNameColumnIndex); - } - - // Don't save contents, probably filled by code - - return node; -} - -LLView* LLNameListCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("name_list"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - BOOL multi_select = FALSE; - node->getAttributeBOOL("multi_select", multi_select); - - BOOL draw_border = TRUE; - node->getAttributeBOOL("draw_border", draw_border); - - BOOL draw_heading = FALSE; - node->getAttributeBOOL("draw_heading", draw_heading); - - S32 name_column_index = 0; - node->getAttributeS32("name_column_index", name_column_index); - - LLUICtrlCallback callback = NULL; - - LLNameListCtrl* name_list = new LLNameListCtrl(name, - rect, - callback, - NULL, - multi_select, - draw_border, - name_column_index); - - name_list->setDisplayHeading(draw_heading); - if (node->hasAttribute("heading_height")) - { - S32 heading_height; - node->getAttributeS32("heading_height", heading_height); - name_list->setHeadingHeight(heading_height); - } - - BOOL allow_calling_card_drop = FALSE; - if (node->getAttributeBOOL("allow_calling_card_drop", allow_calling_card_drop)) - { - name_list->setAllowCallingCardDrop(allow_calling_card_drop); - } - - name_list->setScrollListParameters(node); - - name_list->initFromXML(node, parent); - - LLSD columns; - S32 index = 0; - //S32 total_static = 0; - LLXMLNodePtr child; - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("column")) + LLScrollListColumn* name_column = getColumn(mNameColumn); + if (name_column) { - std::string labelname(""); - child->getAttributeString("label", labelname); - - std::string columnname(labelname); - child->getAttributeString("name", columnname); - - BOOL columndynamicwidth = FALSE; - child->getAttributeBOOL("dynamicwidth", columndynamicwidth); - - std::string sortname(columnname); - child->getAttributeString("sort", sortname); - - S32 columnwidth = -1; - if (child->hasAttribute("relwidth")) - { - F32 columnrelwidth = 0.f; - child->getAttributeF32("relwidth", columnrelwidth); - columns[index]["relwidth"] = columnrelwidth; - } - else - { - child->getAttributeS32("width", columnwidth); - columns[index]["width"] = columnwidth; - } - - LLFontGL::HAlign h_align = LLFontGL::LEFT; - h_align = LLView::selectFontHAlign(child); - - //if(!columndynamicwidth) total_static += llmax(0, columnwidth); - - columns[index]["name"] = columnname; - columns[index]["label"] = labelname; - columns[index]["halign"] = (S32)h_align; - columns[index]["dynamicwidth"] = columndynamicwidth; - columns[index]["sort"] = sortname; - - index++; + mNameColumnIndex = name_column->mIndex; } } - name_list->setColumnHeadings(columns); - - - for (child = node->getFirstChild(); child.notNull(); child = child->getNextSibling()) - { - if (child->hasName("row")) - { - LLUUID id; - child->getAttributeUUID("id", id); - - LLSD row; - - row["id"] = id; - - S32 column_idx = 0; - LLXMLNodePtr row_child; - for (row_child = node->getFirstChild(); row_child.notNull(); row_child = row_child->getNextSibling()) - { - if (row_child->hasName("column")) - { - std::string value = row_child->getTextContents(); - - std::string columnname(""); - row_child->getAttributeString("name", columnname); - - std::string font(""); - row_child->getAttributeString("font", font); - - std::string font_style(""); - row_child->getAttributeString("font-style", font_style); - - row["columns"][column_idx]["column"] = columnname; - row["columns"][column_idx]["value"] = value; - row["columns"][column_idx]["font"] = font; - row["columns"][column_idx]["font-style"] = font_style; - column_idx++; - } - } - name_list->addElement(row); - } - } - - std::string contents = node->getTextContents(); - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("\t\n"); - tokenizer tokens(contents, sep); - tokenizer::iterator token_iter = tokens.begin(); - - while(token_iter != tokens.end()) - { - const std::string& line = *token_iter; - name_list->addCommentText(line); - ++token_iter; - } - - return name_list; } - - - diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 1b7795ddff..070b6c4f4f 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -39,35 +39,68 @@ class LLNameListCtrl -: public LLScrollListCtrl +: public LLScrollListCtrl, protected LLInstanceTracker { public: - LLNameListCtrl(const std::string& name, - const LLRect& rect, - LLUICtrlCallback callback, - void* userdata, - BOOL allow_multiple_selection, - BOOL draw_border = TRUE, - S32 name_column_index = 0, - const std::string& tooltip = LLStringUtil::null); - virtual ~LLNameListCtrl(); + typedef enum e_name_type + { + INDIVIDUAL, + GROUP, + SPECIAL + } ENameType; - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); + // provide names for enums + struct NameTypeNames : public LLInitParam::TypeValuesHelper + { + static void declareValues(); + }; + struct NameItem : public LLInitParam::Block + { + Optional name; + Optional target; + + NameItem() + : name("name"), + target("target", INDIVIDUAL) + {} + }; + + struct NameColumn : public LLInitParam::Choice + { + Alternative column_index; + Alternative column_name; + NameColumn() + : column_name("name_column"), + column_index("name_column_index", 0) + {} + }; + + struct Params : public LLInitParam::Block + { + Optional name_column; + Optional allow_calling_card_drop; + Params(); + }; + +protected: + LLNameListCtrl(const Params&); + friend class LLUICtrlFactory; +public: // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. - BOOL addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM, + void addNameItem(const LLUUID& agent_id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE, std::string& suffix = LLStringUtil::null); - BOOL addNameItem(LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM); + void addNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM); - virtual LLScrollListItem* addElement(const LLSD& value, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); + /*virtual*/ LLScrollListItem* addElement(const LLSD& element, EAddPosition pos = ADD_BOTTOM, void* userdata = NULL); + LLScrollListItem* addNameItemRow(const NameItem& value, EAddPosition pos = ADD_BOTTOM); // Add a user to the list by name. It will be added, the name // requested from the cache, and updated as necessary. void addGroupNameItem(const LLUUID& group_id, EAddPosition pos = ADD_BOTTOM, BOOL enabled = TRUE); - void addGroupNameItem(LLScrollListItem* item, EAddPosition pos = ADD_BOTTOM); + void addGroupNameItem(NameItem& item, EAddPosition pos = ADD_BOTTOM); void removeNameItem(const LLUUID& agent_id); @@ -84,10 +117,11 @@ public: void setAllowCallingCardDrop(BOOL b) { mAllowCallingCardDrop = b; } + /*virtual*/ void updateColumns(); private: - static std::set sInstances; - S32 mNameColumnIndex; - BOOL mAllowCallingCardDrop; + S32 mNameColumnIndex; + std::string mNameColumn; + BOOL mAllowCallingCardDrop; }; #endif diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp new file mode 100644 index 0000000000..e40568a0cb --- /dev/null +++ b/indra/newview/llnavigationbar.cpp @@ -0,0 +1,648 @@ +/** + * @file llnavigationbar.cpp + * @brief Navigation bar implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnavigationbar.h" + +#include +#include +#include +#include + +#include "llagent.h" +#include "llviewerregion.h" +#include "lllandmarkactions.h" +#include "lllocationhistory.h" +#include "lllocationinputctrl.h" +#include "llteleporthistory.h" +#include "llsearcheditor.h" +#include "llsidetray.h" +#include "llslurl.h" +#include "llurlsimstring.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llworldmap.h" +#include "llappviewer.h" +#include "llviewercontrol.h" +#include "llfloatermediabrowser.h" + +#include "llinventorymodel.h" +#include "lllandmarkactions.h" + +#include "llfavoritesbar.h" +#include "llagentui.h" + +//-- LLTeleportHistoryMenuItem ----------------------------------------------- + +/** + * Item look varies depending on the type (backward/current/forward). + */ +class LLTeleportHistoryMenuItem : public LLMenuItemCallGL +{ +public: + typedef enum e_item_type + { + TYPE_BACKWARD, + TYPE_CURRENT, + TYPE_FORWARD, + } EType; + + struct Params : public LLInitParam::Block + { + Mandatory item_type; + + Params() {} + Params(EType type, std::string title); + }; + + /*virtual*/ void draw(); + /*virtual*/ void onMouseEnter(S32 x, S32 y, MASK mask); + /*virtual*/ void onMouseLeave(S32 x, S32 y, MASK mask); + +private: + LLTeleportHistoryMenuItem(const Params&); + friend class LLUICtrlFactory; + + static const S32 ICON_WIDTH = 16; + static const S32 ICON_HEIGHT = 16; + static const std::string ICON_IMG_BACKWARD; + static const std::string ICON_IMG_FORWARD; + + LLIconCtrl* mArrowIcon; +}; + +const std::string LLTeleportHistoryMenuItem::ICON_IMG_BACKWARD("teleport_history_backward.tga"); +const std::string LLTeleportHistoryMenuItem::ICON_IMG_FORWARD("teleport_history_forward.tga"); + +LLTeleportHistoryMenuItem::Params::Params(EType type, std::string title) +{ + item_type(type); + font.name("SANSSERIF"); + + if (type == TYPE_CURRENT) + font.style("BOLD"); + else + title = " " + title; + + name(title); + label(title); +} + +LLTeleportHistoryMenuItem::LLTeleportHistoryMenuItem(const Params& p) +: LLMenuItemCallGL(p), + mArrowIcon(NULL) +{ + LLIconCtrl::Params icon_params; + icon_params.name("icon"); + icon_params.rect(LLRect(0, ICON_HEIGHT, ICON_WIDTH, 0)); + icon_params.mouse_opaque(false); + icon_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + icon_params.visible(false); + + mArrowIcon = LLUICtrlFactory::create (icon_params); + + // no image for the current item + if (p.item_type == TYPE_BACKWARD) + mArrowIcon->setValue(ICON_IMG_BACKWARD); + else if (p.item_type == TYPE_FORWARD) + mArrowIcon->setValue(ICON_IMG_FORWARD); + + addChild(mArrowIcon); +} + +void LLTeleportHistoryMenuItem::draw() +{ + // Draw menu item itself. + LLMenuItemCallGL::draw(); + + // Draw children if any. *TODO: move this to LLMenuItemGL? + LLUICtrl::draw(); +} + +void LLTeleportHistoryMenuItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + mArrowIcon->setVisible(TRUE); +} + +void LLTeleportHistoryMenuItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mArrowIcon->setVisible(FALSE); +} + +//-- LNavigationBar ---------------------------------------------------------- + +/* +TODO: +- Load navbar height from saved settings (as it's done for status bar) or think of a better way. +*/ + +S32 NAVIGATION_BAR_HEIGHT = 60; // *HACK +LLNavigationBar* LLNavigationBar::sInstance = 0; + +LLNavigationBar* LLNavigationBar::getInstance() +{ + if (!sInstance) + sInstance = new LLNavigationBar(); + + return sInstance; +} + +LLNavigationBar::LLNavigationBar() +: mTeleportHistoryMenu(NULL), + mBtnBack(NULL), + mBtnForward(NULL), + mBtnHome(NULL), + mCmbLocation(NULL), + mLeSearch(NULL), + mPurgeTPHistoryItems(false) +{ + setIsChrome(TRUE); + + mParcelMgrConnection = LLViewerParcelMgr::getInstance()->setTeleportFinishedCallback( + boost::bind(&LLNavigationBar::onTeleportFinished, this, _1)); + + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_navigation_bar.xml"); + + // set a listener function for LoginComplete event + LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLNavigationBar::handleLoginComplete, this)); + + // Necessary for focus movement among child controls + setFocusRoot(TRUE); +} + +LLNavigationBar::~LLNavigationBar() +{ + mParcelMgrConnection.disconnect(); + sInstance = 0; +} + +BOOL LLNavigationBar::postBuild() +{ + mBtnBack = getChild("back_btn"); + mBtnForward = getChild("forward_btn"); + mBtnHome = getChild("home_btn"); + + mCmbLocation= getChild("location_combo"); + mLeSearch = getChild("search_input"); + + if (!mBtnBack || !mBtnForward || !mBtnHome || + !mCmbLocation || !mLeSearch) + { + llwarns << "Malformed navigation bar" << llendl; + return FALSE; + } + + mBtnBack->setEnabled(FALSE); + mBtnBack->setClickedCallback(boost::bind(&LLNavigationBar::onBackButtonClicked, this)); + mBtnBack->setHeldDownCallback(boost::bind(&LLNavigationBar::onBackOrForwardButtonHeldDown, this, _2)); + + mBtnForward->setEnabled(FALSE); + mBtnForward->setClickedCallback(boost::bind(&LLNavigationBar::onForwardButtonClicked, this)); + mBtnForward->setHeldDownCallback(boost::bind(&LLNavigationBar::onBackOrForwardButtonHeldDown, this, _2)); + + mBtnHome->setClickedCallback(boost::bind(&LLNavigationBar::onHomeButtonClicked, this)); + + mCmbLocation->setSelectionCallback(boost::bind(&LLNavigationBar::onLocationSelection, this)); + + mLeSearch->setCommitCallback(boost::bind(&LLNavigationBar::onSearchCommit, this)); + + mDefaultNbRect = getRect(); + mDefaultFpRect = getChild("favorite")->getRect(); + + // we'll be notified on teleport history changes + LLTeleportHistory::getInstance()->setHistoryChangedCallback( + boost::bind(&LLNavigationBar::onTeleportHistoryChanged, this)); + + return TRUE; +} + +void LLNavigationBar::draw() +{ + if(mPurgeTPHistoryItems) + { + LLTeleportHistory::getInstance()->purgeItems(); + onTeleportHistoryChanged(); + mPurgeTPHistoryItems = false; + } + LLPanel::draw(); +} + +void LLNavigationBar::onBackButtonClicked() +{ + LLTeleportHistory::getInstance()->goBack(); +} + +void LLNavigationBar::onBackOrForwardButtonHeldDown(const LLSD& param) +{ + if (param["count"].asInteger() == 0) + showTeleportHistoryMenu(); +} + +void LLNavigationBar::onForwardButtonClicked() +{ + LLTeleportHistory::getInstance()->goForward(); +} + +void LLNavigationBar::onHomeButtonClicked() +{ + gAgent.teleportHome(); +} + +void LLNavigationBar::onSearchCommit() +{ + invokeSearch(mLeSearch->getValue().asString()); +} + +void LLNavigationBar::onTeleportHistoryMenuItemClicked(const LLSD& userdata) +{ + int idx = userdata.asInteger(); + LLTeleportHistory::getInstance()->goToItem(idx); +} + +// This is called when user presses enter in the location input +// or selects a location from the typed locations dropdown. +void LLNavigationBar::onLocationSelection() +{ + std::string typed_location = mCmbLocation->getSimple(); + + // Will not teleport to empty location. + if (typed_location.empty()) + return; + + std::string region_name; + LLVector3 local_coords(128, 128, 0); + S32 x = 0, y = 0, z = 0; + + // Is the typed location a SLURL? + if (LLSLURL::isSLURL(typed_location)) + { + // Yes. Extract region name and local coordinates from it. + if (LLURLSimString::parse(LLSLURL::stripProtocol(typed_location), ®ion_name, &x, &y, &z)) + local_coords.set(x, y, z); + else + return; + } + else + { + //If it is not slurl let's look for landmarks + LLInventoryModel::item_array_t landmark_items = LLLandmarkActions::fetchLandmarksByName(typed_location, FALSE); + if ( !landmark_items.empty() ) + { + gAgent.teleportViaLandmark(landmark_items[0]->getAssetUUID()); + return; + } + //No landmark match, check if it is a region name + region_name = parseLocation(typed_location, &x, &y, &z); + if (region_name != typed_location) + local_coords.set(x, y, z); + + // Treat it as region name. + // region_name = typed_location; + } + + // Resolve the region name to its global coordinates. + // If resolution succeeds we'll teleport. + LLWorldMap::url_callback_t cb = boost::bind( + &LLNavigationBar::onRegionNameResponse, this, + typed_location, region_name, local_coords, _1, _2, _3, _4); + LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false); +} + +void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos) +{ + // Location is valid. Add it to the typed locations history. + LLLocationHistory* lh = LLLocationHistory::getInstance(); + + std::string location; + /*NOTE: + * We can't use gAgent.getPositionAgent() in case of local teleport to build location. + * At this moment gAgent.getPositionAgent() contains previous coordinates. + * according to EXT-65 agent position is being reseted on each frame. + */ + LLAgentUI::buildLocationString(location, LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM, + gAgent.getPosAgentFromGlobal(global_agent_pos)); + + //Touch it, if it is at list already, add new location otherwise + if ( !lh->touchItem(location) ) { + std::string tooltip = LLSLURL::buildSLURLfromPosGlobal( + gAgent.getRegion()->getName(), global_agent_pos, false); + + lh->addItem(location, tooltip); + } + llinfos << "Saving after on teleport finish" << llendl; + lh->save(); + +} + +void LLNavigationBar::onTeleportHistoryChanged() +{ + // Update navigation controls. + LLTeleportHistory* h = LLTeleportHistory::getInstance(); + int cur_item = h->getCurrentItemIndex(); + mBtnBack->setEnabled(cur_item > 0); + mBtnForward->setEnabled(cur_item < ((int)h->getItems().size() - 1)); +} + +void LLNavigationBar::rebuildTeleportHistoryMenu() +{ + // Has the pop-up menu been built? + if (mTeleportHistoryMenu) + { + // Clear it. + mTeleportHistoryMenu->empty(); + } + else + { + // Create it. + LLMenuGL::Params menu_p; + menu_p.name("popup"); + menu_p.can_tear_off(false); + menu_p.visible(false); + menu_p.bg_visible(true); + menu_p.scrollable(true); + mTeleportHistoryMenu = LLUICtrlFactory::create(menu_p); + + addChild(mTeleportHistoryMenu); + } + + // Populate the menu with teleport history items. + LLTeleportHistory* hist = LLTeleportHistory::getInstance(); + const LLTeleportHistory::slurl_list_t& hist_items = hist->getItems(); + int cur_item = hist->getCurrentItemIndex(); + + // Items will be shown in the reverse order, just like in Firefox. + for (int i = (int)hist_items.size()-1; i >= 0; i--) + { + LLTeleportHistoryMenuItem::EType type; + if (i < cur_item) + type = LLTeleportHistoryMenuItem::TYPE_BACKWARD; + else if (i > cur_item) + type = LLTeleportHistoryMenuItem::TYPE_FORWARD; + else + type = LLTeleportHistoryMenuItem::TYPE_CURRENT; + + LLTeleportHistoryMenuItem::Params item_params(type, hist_items[i].getTitle()); + item_params.on_click.function(boost::bind(&LLNavigationBar::onTeleportHistoryMenuItemClicked, this, i)); + mTeleportHistoryMenu->addChild(LLUICtrlFactory::create(item_params)); + } +} + +void LLNavigationBar::onRegionNameResponse( + std::string typed_location, + std::string region_name, + LLVector3 local_coords, + U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport) +{ + // Invalid location? + if (!region_handle) + { + invokeSearch(typed_location); + return; + } + + // Teleport to the location. + LLVector3d region_pos = from_region_handle(region_handle); + LLVector3d global_pos = region_pos + (LLVector3d) local_coords; + + llinfos << "Teleporting to: " << global_pos << llendl; + gAgent.teleportViaLocation(global_pos); +} + +void LLNavigationBar::showTeleportHistoryMenu() +{ + // Don't show the popup if teleport history is empty. + if (LLTeleportHistory::getInstance()->isEmpty()) + { + lldebugs << "Teleport history is empty, will not show the menu." << llendl; + return; + } + + rebuildTeleportHistoryMenu(); + + if (mTeleportHistoryMenu == NULL) + return; + + // *TODO: why to draw/update anything before showing the menu? + mTeleportHistoryMenu->buildDrawLabels(); + mTeleportHistoryMenu->updateParent(LLMenuGL::sMenuContainer); + LLRect btnBackRect = mBtnBack->getRect(); + LLMenuGL::showPopup(this, mTeleportHistoryMenu, btnBackRect.mLeft, btnBackRect.mBottom); + + // *HACK pass the mouse capturing to the drop-down menu + gFocusMgr.setMouseCapture( NULL ); +} + +void LLNavigationBar::handleLoginComplete() +{ + mCmbLocation->handleLoginComplete(); +} + +void LLNavigationBar::invokeSearch(std::string search_text) +{ + LLFloaterReg::showInstance("search", LLSD().insert("panel", "all").insert("id", LLSD(search_text))); +} + +std::string LLNavigationBar::parseLocation(const std::string & location, S32* x, S32* y, S32* z) { + /* + * This regular expression extracts numbers from the following string + * construct: "(num1, num2, num3)", where num1, num2 and num3 are decimal + * numbers. Leading and trailing spaces are also caught by the expression. + */ + const boost::regex re("\\s*\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)\\s*"); + + boost::smatch m; + if (boost::regex_search(location, m, re)) { + // string representations of parsed by regex++ numbers + std::string xstr(m[1].first, m[1].second); + std::string ystr(m[2].first, m[2].second); + std::string zstr(m[3].first, m[3].second); + + *x = atoi(xstr.c_str()); + *y = atoi(ystr.c_str()); + *z = atoi(zstr.c_str()); + //erase commas in coordinates + std::string region_parcel = boost::regex_replace(location, re, ""); + // cut region name + return region_parcel.substr(0, region_parcel.find_first_of(',')); + } + + *x = *y = *z = 0; + + return location; +} + +void LLNavigationBar::clearHistoryCache() +{ + mCmbLocation->removeall(); + LLLocationHistory* lh = LLLocationHistory::getInstance(); + lh->removeItems(); + lh->save(); + mPurgeTPHistoryItems= true; +} + +void LLNavigationBar::showNavigationPanel(BOOL visible) +{ + bool fpVisible = gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"); + + LLFavoritesBarCtrl* fb = getChild("favorite"); + LLPanel* navPanel = getChild("navigation_panel"); + + LLRect nbRect(getRect()); + LLRect fbRect(fb->getRect()); + + navPanel->setVisible(visible); + + if (visible) + { + if (fpVisible) + { + // Navigation Panel must be shown. Favorites Panel is visible. + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), mDefaultNbRect.getHeight()); + fbRect.setLeftTopAndSize(fbRect.mLeft, mDefaultFpRect.mTop, fbRect.getWidth(), fbRect.getHeight()); + + // this is duplicated in 'else' section because it should be called BEFORE fb->reshape + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + + fb->reshape(fbRect.getWidth(), fbRect.getHeight()); + fb->setRect(fbRect); + } + else + { + // Navigation Panel must be shown. Favorites Panel is hidden. + + S32 height = mDefaultNbRect.getHeight() - mDefaultFpRect.getHeight(); + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), height); + + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + } + } + else + { + if (fpVisible) + { + // Navigation Panel must be hidden. Favorites Panel is visible. + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), fbRect.getHeight()); + fbRect.setLeftTopAndSize(fbRect.mLeft, fbRect.getHeight(), fbRect.getWidth(), fbRect.getHeight()); + + // this is duplicated in 'else' section because it should be called BEFORE fb->reshape + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + + fb->reshape(fbRect.getWidth(), fbRect.getHeight()); + fb->setRect(fbRect); + } + else + { + // Navigation Panel must be hidden. Favorites Panel is hidden. + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), 0); + + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + } + } + + if(LLSideTray::instanceCreated()) + { + LLSideTray::getInstance()->resetPanelRect(); + } +} + +void LLNavigationBar::showFavoritesPanel(BOOL visible) +{ + bool npVisible = gSavedSettings.getBOOL("ShowNavbarNavigationPanel"); + + LLFavoritesBarCtrl* fb = getChild("favorite"); + + LLRect nbRect(getRect()); + LLRect fbRect(fb->getRect()); + + if (visible) + { + if (npVisible) + { + // Favorites Panel must be shown. Navigation Panel is visible. + + S32 fbHeight = fbRect.getHeight(); + S32 newHeight = nbRect.getHeight() + fbHeight; + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), newHeight); + fbRect.setLeftTopAndSize(mDefaultFpRect.mLeft, mDefaultFpRect.mTop, fbRect.getWidth(), fbRect.getHeight()); + } + else + { + // Favorites Panel must be shown. Navigation Panel is hidden. + + S32 fpHeight = mDefaultFpRect.getHeight(); + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), fpHeight); + fbRect.setLeftTopAndSize(fbRect.mLeft, fpHeight, fbRect.getWidth(), fpHeight); + } + + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + + fb->reshape(fbRect.getWidth(), fbRect.getHeight()); + fb->setRect(fbRect); + } + else + { + if (npVisible) + { + // Favorites Panel must be hidden. Navigation Panel is visible. + + S32 fbHeight = fbRect.getHeight(); + S32 newHeight = nbRect.getHeight() - fbHeight; + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), newHeight); + } + else + { + // Favorites Panel must be hidden. Navigation Panel is hidden. + + nbRect.setLeftTopAndSize(nbRect.mLeft, nbRect.mTop, nbRect.getWidth(), 0); + } + + reshape(nbRect.getWidth(), nbRect.getHeight()); + setRect(nbRect); + } + + fb->setVisible(visible); + if(LLSideTray::instanceCreated()) + { + LLSideTray::getInstance()->resetPanelRect(); + } +} diff --git a/indra/newview/llnavigationbar.h b/indra/newview/llnavigationbar.h new file mode 100644 index 0000000000..6932847854 --- /dev/null +++ b/indra/newview/llnavigationbar.h @@ -0,0 +1,111 @@ +/** + * @file llnavigationbar.h + * @brief Navigation bar definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNAVIGATIONBAR_H +#define LL_LLNAVIGATIONBAR_H + +#include "llpanel.h" + +extern S32 NAVIGATION_BAR_HEIGHT; + +class LLButton; +class LLLocationInputCtrl; +class LLMenuGL; +class LLSearchEditor; + +/** + * Web browser-like navigation bar. + */ +class LLNavigationBar +: public LLPanel +{ + LOG_CLASS(LLNavigationBar); + +public: + static LLNavigationBar* getInstance(); + virtual ~LLNavigationBar(); + + /*virtual*/ void draw(); + /*virtual*/ BOOL postBuild(); + + void handleLoginComplete(); + void clearHistoryCache(); + + void showNavigationPanel(BOOL visible); + void showFavoritesPanel(BOOL visible); + +private: + LLNavigationBar(); + + void rebuildTeleportHistoryMenu(); + void showTeleportHistoryMenu(); + void invokeSearch(std::string search_text); + + /** + * Get region name and local coordinates from typed location + */ + static std::string parseLocation(const std::string & location, S32* x, S32* y, S32* z); + + // callbacks + void onTeleportHistoryMenuItemClicked(const LLSD& userdata); + void onTeleportHistoryChanged(); + void onBackButtonClicked(); + void onBackOrForwardButtonHeldDown(const LLSD& param); + void onForwardButtonClicked(); + void onHomeButtonClicked(); + void onHelpButtonClicked(); + void onLocationSelection(); + void onLocationPrearrange(const LLSD& data); + void onSearchCommit(); + void onTeleportFinished(const LLVector3d& global_agent_pos); + void onRegionNameResponse( + std::string typed_location, + std::string region_name, + LLVector3 local_coords, + U64 region_handle, const std::string& url, + const LLUUID& snapshot_id, bool teleport); + + static LLNavigationBar *sInstance; + + LLMenuGL* mTeleportHistoryMenu; + LLButton* mBtnBack; + LLButton* mBtnForward; + LLButton* mBtnHome; + LLSearchEditor* mLeSearch; + LLLocationInputCtrl* mCmbLocation; + LLRect mDefaultNbRect; + LLRect mDefaultFpRect; + boost::signals2::connection mParcelMgrConnection; + bool mPurgeTPHistoryItems; +}; + +#endif diff --git a/indra/newview/llnearbychat.cpp b/indra/newview/llnearbychat.cpp new file mode 100644 index 0000000000..3856a86da0 --- /dev/null +++ b/indra/newview/llnearbychat.cpp @@ -0,0 +1,486 @@ +/** + * @file LLNearbyChat.cpp + * @brief Nearby chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnearbychat.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" +#include "llrootview.h" +//#include "llchatitemscontainerctrl.h" +#include "lliconctrl.h" +#include "llsidetray.h" +#include "llfocusmgr.h" +#include "llresizebar.h" +#include "llresizehandle.h" +#include "llmenugl.h" +#include "llviewermenu.h"//for gMenuHolder + +#include "llnearbychathandler.h" +#include "llchannelmanager.h" + +//for LLViewerTextEditor support +#include "llagent.h" // gAgent +#include "llfloaterscriptdebug.h" +#include "llviewertexteditor.h" +#include "llstylemap.h" + +#include "lldraghandle.h" + + +static const S32 RESIZE_BAR_THICKNESS = 3; + +LLNearbyChat::LLNearbyChat(const LLSD& key) : + LLFloater(key), + mEChatTearofState(CHAT_PINNED), + mChatCaptionPanel(NULL), + mChatHistoryEditor(NULL) +{ +} + +LLNearbyChat::~LLNearbyChat() +{ +} + +BOOL LLNearbyChat::postBuild() +{ + //resize bars + setCanResize(true); + + mResizeBar[LLResizeBar::BOTTOM]->setVisible(false); + mResizeBar[LLResizeBar::LEFT]->setVisible(false); + mResizeBar[LLResizeBar::RIGHT]->setVisible(false); + + mResizeBar[LLResizeBar::BOTTOM]->setResizeLimits(120,500); + mResizeBar[LLResizeBar::TOP]->setResizeLimits(120,500); + mResizeBar[LLResizeBar::LEFT]->setResizeLimits(220,600); + mResizeBar[LLResizeBar::RIGHT]->setResizeLimits(220,600); + + mResizeHandle[0]->setVisible(false); + mResizeHandle[1]->setVisible(false); + mResizeHandle[2]->setVisible(false); + mResizeHandle[3]->setVisible(false); + + getDragHandle()->setVisible(false); + + //menu + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + + enable_registrar.add("NearbyChat.Check", boost::bind(&LLNearbyChat::onNearbyChatCheckContextMenuItem, this, _2)); + registrar.add("NearbyChat.Action", boost::bind(&LLNearbyChat::onNearbyChatContextMenuItemClicked, this, _2)); + + + LLMenuGL* menu = LLUICtrlFactory::getInstance()->createFromFile("menu_nearby_chat.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + + if(menu) + mPopupMenuHandle = menu->getHandle(); + + gSavedSettings.declareS32("nearbychat_showicons_and_names",2,"NearByChat header settings",true); + + mChatCaptionPanel = getChild("chat_caption", false); + mChatHistoryEditor = getChild("Chat History Editor"); + + reshape(getRect().getWidth(), getRect().getHeight(), FALSE); + + return LLFloater::postBuild(); +} + + +LLColor4 nearbychat_get_text_color(const LLChat& chat) +{ + LLColor4 text_color; + + if(chat.mMuted) + { + text_color.setVec(0.8f, 0.8f, 0.8f, 1.f); + } + else + { + switch(chat.mSourceType) + { + case CHAT_SOURCE_SYSTEM: + text_color = LLUIColorTable::instance().getColor("SystemChatColor"); + break; + case CHAT_SOURCE_AGENT: + if (chat.mFromID.isNull()) + { + text_color = LLUIColorTable::instance().getColor("SystemChatColor"); + } + else + { + if(gAgentID == chat.mFromID) + { + text_color = LLUIColorTable::instance().getColor("UserChatColor"); + } + else + { + text_color = LLUIColorTable::instance().getColor("AgentChatColor"); + } + } + break; + case CHAT_SOURCE_OBJECT: + if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) + { + text_color = LLUIColorTable::instance().getColor("ScriptErrorColor"); + } + else if ( chat.mChatType == CHAT_TYPE_OWNER ) + { + text_color = LLUIColorTable::instance().getColor("llOwnerSayChatColor"); + } + else + { + text_color = LLUIColorTable::instance().getColor("ObjectChatColor"); + } + break; + default: + text_color.setToWhite(); + } + + if (!chat.mPosAgent.isExactlyZero()) + { + LLVector3 pos_agent = gAgent.getPositionAgent(); + F32 distance = dist_vec(pos_agent, chat.mPosAgent); + if (distance > gAgent.getNearChatRadius()) + { + // diminish far-off chat + text_color.mV[VALPHA] = 0.8f; + } + } + } + + return text_color; +} + +void nearbychat_add_timestamped_line(LLViewerTextEditor* edit, LLChat chat, const LLColor4& color) +{ + std::string line = chat.mFromName; + line +=": "; + line +=chat.mText; + + bool prepend_newline = true; + if (gSavedSettings.getBOOL("ChatShowTimestamps")) + { + edit->appendTime(prepend_newline); + prepend_newline = false; + } + + // If the msg is from an agent (not yourself though), + // extract out the sender name and replace it with the hotlinked name. + if (chat.mSourceType == CHAT_SOURCE_AGENT && + chat.mFromID != LLUUID::null) + { + chat.mURL = llformat("secondlife:///app/agent/%s/about",chat.mFromID.asString().c_str()); + } + + // If the chat line has an associated url, link it up to the name. + if (!chat.mURL.empty() + && (line.length() > chat.mFromName.length() && line.find(chat.mFromName,0) == 0)) + { + std::string start_line = line.substr(0, chat.mFromName.length() + 1); + line = line.substr(chat.mFromName.length() + 1); + edit->appendStyledText(start_line, false, prepend_newline, LLStyleMap::instance().lookup(chat.mFromID,chat.mURL)); + prepend_newline = false; + } + + S32 font_size = gSavedSettings.getS32("ChatFontSize"); + + std::string font_name = ""; + + if (0 == font_size) + font_name = "small"; + else if (2 == font_size) + font_name = "sansserifbig"; + + edit->appendColoredText(line, false, prepend_newline, color, font_name); +} + + + +void LLNearbyChat::addMessage(const LLChat& chat) +{ + LLColor4 color = nearbychat_get_text_color(chat); + + + if (chat.mChatType == CHAT_TYPE_DEBUG_MSG) + { + LLFloaterScriptDebug::addScriptLine(chat.mText, + chat.mFromName, + color, + chat.mFromID); + if (!gSavedSettings.getBOOL("ScriptErrorsAsChat")) + { + return; + } + } + + // could flash the chat button in the status bar here. JC + + + mChatHistoryEditor->setParseHTML(TRUE); + mChatHistoryEditor->setParseHighlights(TRUE); + + if (!chat.mMuted) + nearbychat_add_timestamped_line(mChatHistoryEditor, chat, color); +} + +void LLNearbyChat::onNearbySpeakers() +{ + LLSD param; + param["people_panel_tab_name"] = "nearby_panel"; + LLSideTray::getInstance()->showPanel("panel_people",param); +} + +void LLNearbyChat::onTearOff() +{ + if(mEChatTearofState == CHAT_PINNED) + float_panel(); + else + pinn_panel(); +} + +void LLNearbyChat::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + + LLFloater::reshape(width, height, called_from_parent); + + LLRect resize_rect; + resize_rect.setLeftTopAndSize( 0, height, width, RESIZE_BAR_THICKNESS); + if (mResizeBar[LLResizeBar::TOP]) + { + mResizeBar[LLResizeBar::TOP]->reshape(width,RESIZE_BAR_THICKNESS); + mResizeBar[LLResizeBar::TOP]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( 0, RESIZE_BAR_THICKNESS, width, RESIZE_BAR_THICKNESS); + if (mResizeBar[LLResizeBar::BOTTOM]) + { + mResizeBar[LLResizeBar::BOTTOM]->reshape(width,RESIZE_BAR_THICKNESS); + mResizeBar[LLResizeBar::BOTTOM]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( 0, height, RESIZE_BAR_THICKNESS, height); + if (mResizeBar[LLResizeBar::LEFT]) + { + mResizeBar[LLResizeBar::LEFT]->reshape(RESIZE_BAR_THICKNESS,height); + mResizeBar[LLResizeBar::LEFT]->setRect(resize_rect); + } + + resize_rect.setLeftTopAndSize( width - RESIZE_BAR_THICKNESS, height, RESIZE_BAR_THICKNESS, height); + if (mResizeBar[LLResizeBar::RIGHT]) + { + mResizeBar[LLResizeBar::RIGHT]->reshape(RESIZE_BAR_THICKNESS,height); + mResizeBar[LLResizeBar::RIGHT]->setRect(resize_rect); + } + + // *NOTE: we must check mChatCaptionPanel and mChatHistoryEditor against NULL because reshape is called from the + // LLView::initFromParams BEFORE postBuild is called and child controls are not exist yet + LLRect caption_rect; + if (NULL != mChatCaptionPanel) + { + caption_rect = mChatCaptionPanel->getRect(); + caption_rect.setLeftTopAndSize( 2, height - RESIZE_BAR_THICKNESS, width - 4, caption_rect.getHeight()); + mChatCaptionPanel->reshape( width - 4, caption_rect.getHeight(), 1); + mChatCaptionPanel->setRect(caption_rect); + } + + if (NULL != mChatHistoryEditor) + { + LLRect scroll_rect = mChatHistoryEditor->getRect(); + scroll_rect.setLeftTopAndSize( 2, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS, width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2); + mChatHistoryEditor->reshape( width - 4, height - caption_rect.getHeight() - RESIZE_BAR_THICKNESS*2, 1); + mChatHistoryEditor->setRect(scroll_rect); + } + + // + if(mEChatTearofState == CHAT_PINNED) + { + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + LLRect panel_rect; + panel_rect.setLeftTopAndSize( parent_rect.mLeft+2, parent_rect.mBottom+height+4, width, height); + setRect(panel_rect); + } + else + { + LLRect panel_rect; + panel_rect.setLeftTopAndSize( getRect().mLeft, getRect().mTop, width, height); + setRect(panel_rect); + } + +} + +BOOL LLNearbyChat::handleMouseDown (S32 x, S32 y, MASK mask) +{ + LLUICtrl* nearby_speakers_btn = mChatCaptionPanel->getChild("nearby_speakers_btn"); + LLUICtrl* tearoff_btn = mChatCaptionPanel->getChild("tearoff_btn"); + LLUICtrl* close_btn = mChatCaptionPanel->getChild("close_btn"); + + S32 caption_local_x = x - mChatCaptionPanel->getRect().mLeft; + S32 caption_local_y = y - mChatCaptionPanel->getRect().mBottom; + + S32 local_x = caption_local_x - nearby_speakers_btn->getRect().mLeft; + S32 local_y = caption_local_y - nearby_speakers_btn->getRect().mBottom; + if(nearby_speakers_btn->pointInView(local_x, local_y)) + { + + onNearbySpeakers(); + bringToFront( x, y ); + return true; + } + local_x = caption_local_x - tearoff_btn->getRect().mLeft; + local_y = caption_local_y- tearoff_btn->getRect().mBottom; + if(tearoff_btn->pointInView(local_x, local_y)) + { + onTearOff(); + bringToFront( x, y ); + return true; + } + + local_x = caption_local_x - close_btn->getRect().mLeft; + local_y = caption_local_y - close_btn->getRect().mBottom; + if(close_btn->pointInView(local_x, local_y)) + { + setVisible(false); + bringToFront( x, y ); + return true; + } + + if(mEChatTearofState == CHAT_UNPINNED && mChatCaptionPanel->pointInView(caption_local_x, caption_local_y) ) + { + //start draggind + gFocusMgr.setMouseCapture(this); + mStart_Y = y; + mStart_X = x; + bringToFront( x, y ); + return true; + } + + return LLFloater::handleMouseDown(x,y,mask); +} + +BOOL LLNearbyChat::handleMouseUp(S32 x, S32 y, MASK mask) +{ + if( hasMouseCapture() ) + { + // Release the mouse + gFocusMgr.setMouseCapture( NULL ); + mStart_X = 0; + mStart_Y = 0; + return true; + } + + return LLFloater::handleMouseUp(x,y,mask); +} + +BOOL LLNearbyChat::handleHover(S32 x, S32 y, MASK mask) +{ + if( hasMouseCapture() ) + { + translate(x-mStart_X,y-mStart_Y); + return true; + } + return LLFloater::handleHover(x,y,mask); +} + +void LLNearbyChat::pinn_panel() +{ + mEChatTearofState = CHAT_PINNED; + LLIconCtrl* tearoff_btn = mChatCaptionPanel->getChild("tearoff_btn",false); + + tearoff_btn->setValue("inv_item_landmark_visited.tga"); + + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + LLRect panel_rect; + panel_rect.setLeftTopAndSize( parent_rect.mLeft+2, parent_rect.mBottom+getRect().getHeight()+4, getRect().getWidth(), getRect().getHeight()); + setRect(panel_rect); + + mResizeBar[LLResizeBar::BOTTOM]->setVisible(false); + mResizeBar[LLResizeBar::LEFT]->setVisible(false); + mResizeBar[LLResizeBar::RIGHT]->setVisible(false); + + getDragHandle()->setVisible(false); + +} + +void LLNearbyChat::float_panel() +{ + mEChatTearofState = CHAT_UNPINNED; + LLIconCtrl* tearoff_btn = mChatCaptionPanel->getChild("tearoff_btn", false); + + tearoff_btn->setValue("inv_item_landmark.tga"); + mResizeBar[LLResizeBar::BOTTOM]->setVisible(true); + mResizeBar[LLResizeBar::LEFT]->setVisible(true); + mResizeBar[LLResizeBar::RIGHT]->setVisible(true); + + getDragHandle()->setVisible(true); + + translate(4,4); +} + +void LLNearbyChat::onNearbyChatContextMenuItemClicked(const LLSD& userdata) +{ +} +bool LLNearbyChat::onNearbyChatCheckContextMenuItem(const LLSD& userdata) +{ + std::string str = userdata.asString(); + if(str == "nearby_people") + onNearbySpeakers(); + return false; +} + +BOOL LLNearbyChat::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if(mChatCaptionPanel->pointInView(x - mChatCaptionPanel->getRect().mLeft, y - mChatCaptionPanel->getRect().mBottom) ) + { + LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); + + if(menu) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, menu, x, y); + } + return true; + } + return LLFloater::handleRightMouseDown(x, y, mask); +} + +void LLNearbyChat::onOpen(const LLSD& key ) +{ + LLNotificationsUI::LLScreenChannel* chat_channel = LLNotificationsUI::LLChannelManager::getInstance()->getChannelByID(LLUUID(gSavedSettings.getString("NearByChatChannelUUID"))); + if(chat_channel) + { + chat_channel->removeToastsFromChannel(); + } +} diff --git a/indra/newview/llnearbychat.h b/indra/newview/llnearbychat.h new file mode 100644 index 0000000000..efa2e479e6 --- /dev/null +++ b/indra/newview/llnearbychat.h @@ -0,0 +1,97 @@ +/** + * @file llnearbychat.h + * @brief nearby chat history scrolling panel implementation + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNEARBYCHAT_H_ +#define LL_LLNEARBYCHAT_H_ + +#include "llfloater.h" +#include "llscrollbar.h" +#include "llchat.h" + +class LLResizeBar; +class LLViewerTextEditor; + +class LLNearbyChat: public LLFloater +{ +public: + // enumerations used by the chat system + typedef enum e_chat_tearof_state + { + CHAT_PINNED = 0, + CHAT_UNPINNED = 1, + } EChatTearofState; + + enum { RESIZE_BAR_COUNT=4 }; + + LLNearbyChat(const LLSD& key); + ~LLNearbyChat(); + + BOOL postBuild (); + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + BOOL handleMouseUp (S32 x, S32 y, MASK mask); + BOOL handleHover (S32 x, S32 y, MASK mask); + + BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + void addMessage (const LLChat& message); + + void onNearbySpeakers (); + void onTearOff(); + + void onNearbyChatContextMenuItemClicked(const LLSD& userdata); + bool onNearbyChatCheckContextMenuItem(const LLSD& userdata); + + virtual void onClose (bool app_quitting) { if(app_quitting) destroy(); else setVisible(false); } + + virtual void onOpen (const LLSD& key); + +private: + + void pinn_panel(); + void float_panel(); + +private: + EChatTearofState mEChatTearofState; + S32 mStart_X; + S32 mStart_Y; + + //LLResizeBar* mResizeBar[RESIZE_BAR_COUNT]; + LLHandle mPopupMenuHandle; + LLPanel* mChatCaptionPanel; + LLViewerTextEditor* mChatHistoryEditor; +}; + +#endif + + diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp new file mode 100644 index 0000000000..d4a9be0355 --- /dev/null +++ b/indra/newview/llnearbychatbar.cpp @@ -0,0 +1,639 @@ +/** + * @file llnearbychatbar.cpp + * @brief LLNearbyChatBar class implementation + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnearbychatbar.h" +#include "llbottomtray.h" +#include "llagent.h" +#include "llgesturemgr.h" +#include "llmultigesture.h" +#include "llkeyboard.h" +#include "llanimationstates.h" +#include "llviewerstats.h" +#include "llcommandhandler.h" +#include "llviewercontrol.h" + +S32 LLNearbyChatBar::sLastSpecialChatChannel = 0; + +// legacy calllback glue +void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel); + +static LLDefaultChildRegistry::Register r("gesture_combo_box"); + +struct LLChatTypeTrigger { + std::string name; + EChatType type; +}; + +static LLChatTypeTrigger sChatTypeTriggers[] = { + { "/whisper" , CHAT_TYPE_WHISPER}, + { "/shout" , CHAT_TYPE_SHOUT} +}; + +LLGestureComboBox::LLGestureComboBox(const LLGestureComboBox::Params& p) + : LLComboBox(p) + , mGestureLabelTimer() + , mLabel(p.label) +{ + setCommitCallback(boost::bind(&LLGestureComboBox::onCommitGesture, this)); + + // now register us as observer since we have a place to put the results + LLGestureManager::instance().addObserver(this); + + // refresh list from current active gestures + refreshGestures(); +} + +LLGestureComboBox::~LLGestureComboBox() +{ + LLGestureManager::instance().removeObserver(this); +} + +void LLGestureComboBox::refreshGestures() +{ + //store current selection so we can maintain it + LLSD cur_gesture = getValue(); + selectFirstItem(); + // clear + clearRows(); + mGestures.clear(); + + LLGestureManager::item_map_t::iterator it; + LLSD::Integer idx(0); + for (it = LLGestureManager::instance().mActive.begin(); it != LLGestureManager::instance().mActive.end(); ++it) + { + LLMultiGesture* gesture = (*it).second; + if (gesture) + { + addSimpleElement(gesture->mName, ADD_BOTTOM, LLSD(idx)); + mGestures.push_back(gesture); + idx++; + } + } + + sortByName(); + // Insert label after sorting, at top, with separator below it + addSeparator(ADD_TOP); + addSimpleElement(mLabel, ADD_TOP); + + if (cur_gesture.isDefined()) + { + selectByValue(cur_gesture); + } + else + { + selectFirstItem(); + } +} + +void LLGestureComboBox::onCommitGesture() +{ + LLCtrlListInterface* gestures = getListInterface(); + if (gestures) + { + S32 index = gestures->getFirstSelectedIndex(); + if (index == 0) + { + return; + } + + index = gestures->getSelectedValue().asInteger(); + LLMultiGesture* gesture = mGestures.at(index); + if(gesture) + { + LLGestureManager::instance().playGesture(gesture); + if(!gesture->mReplaceText.empty()) + { + LLNearbyChatBar::sendChatFromViewer(gesture->mReplaceText, CHAT_TYPE_NORMAL, FALSE); + } + } + } + + mGestureLabelTimer.start(); + // free focus back to chat bar + setFocus(FALSE); +} + +//virtual +void LLGestureComboBox::draw() +{ + // HACK: Leave the name of the gesture in place for a few seconds. + const F32 SHOW_GESTURE_NAME_TIME = 2.f; + if (mGestureLabelTimer.getStarted() && mGestureLabelTimer.getElapsedTimeF32() > SHOW_GESTURE_NAME_TIME) + { + LLCtrlListInterface* gestures = getListInterface(); + if (gestures) gestures->selectFirstItem(); + mGestureLabelTimer.stop(); + } + + LLComboBox::draw(); +} + +LLNearbyChatBar::LLNearbyChatBar() + : LLPanel() + , mChatBox(NULL) +{ +} + +//virtual +BOOL LLNearbyChatBar::postBuild() +{ + mChatBox = getChild("chat_box"); + + mChatBox->setCommitCallback(boost::bind(&LLNearbyChatBar::onChatBoxCommit, this)); + mChatBox->setKeystrokeCallback(&onChatBoxKeystroke, this); + mChatBox->setFocusLostCallback(&onChatBoxFocusLost, this); + + mChatBox->setIgnoreArrowKeys(TRUE); + mChatBox->setCommitOnFocusLost( FALSE ); + mChatBox->setRevertOnEsc( FALSE ); + mChatBox->setIgnoreTab(TRUE); + mChatBox->setPassDelete(TRUE); + mChatBox->setReplaceNewlinesWithSpaces(FALSE); + mChatBox->setMaxTextLength(1023); + mChatBox->setEnableLineHistory(TRUE); + + mTalkBtn = getChild("talk"); + + // Speak button should be initially disabled because + // it takes some time between logging in to world and connecting to voice channel. + mTalkBtn->setEnabled(FALSE); + + // Registering Chat Bar to receive Voice client status change notifications. + gVoiceClient->addObserver(this); + + return TRUE; +} + +//static +LLNearbyChatBar* LLNearbyChatBar::getInstance() +{ + return LLBottomTray::getInstance() ? LLBottomTray::getInstance()->getNearbyChatBar() : NULL; +} + +//static +bool LLNearbyChatBar::instanceExists() +{ + return LLBottomTray::instanceExists() && LLBottomTray::getInstance()->getNearbyChatBar() != NULL; +} + +std::string LLNearbyChatBar::getCurrentChat() +{ + return mChatBox ? mChatBox->getText() : LLStringUtil::null; +} + +// virtual +BOOL LLNearbyChatBar::handleKeyHere( KEY key, MASK mask ) +{ + BOOL handled = FALSE; + + // ALT-RETURN is reserved for windowed/fullscreen toggle + if( KEY_RETURN == key && mask == MASK_CONTROL) + { + // shout + sendChat(CHAT_TYPE_SHOUT); + handled = TRUE; + } + + return handled; +} + +BOOL LLNearbyChatBar::matchChatTypeTrigger(const std::string& in_str, std::string* out_str) +{ + U32 in_len = in_str.length(); + S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers); + + for (S32 n = 0; n < cnt; n++) + { + if (in_len > sChatTypeTriggers[n].name.length()) + continue; + + std::string trigger_trunc = sChatTypeTriggers[n].name; + LLStringUtil::truncate(trigger_trunc, in_len); + + if (!LLStringUtil::compareInsensitive(in_str, trigger_trunc)) + { + *out_str = sChatTypeTriggers[n].name; + return TRUE; + } + } + + return FALSE; +} + +void LLNearbyChatBar::onChatBoxKeystroke(LLLineEditor* caller, void* userdata) +{ + + LLNearbyChatBar* self = (LLNearbyChatBar *)userdata; + + LLWString raw_text = self->mChatBox->getWText(); + + // Can't trim the end, because that will cause autocompletion + // to eat trailing spaces that might be part of a gesture. + LLWStringUtil::trimHead(raw_text); + + S32 length = raw_text.length(); + + if( (length > 0) && (raw_text[0] != '/') ) // forward slash is used for escape (eg. emote) sequences + { + gAgent.startTyping(); + } + else + { + gAgent.stopTyping(); + } + + /* Doesn't work -- can't tell the difference between a backspace + that killed the selection vs. backspace at the end of line. + if (length > 1 + && text[0] == '/' + && key == KEY_BACKSPACE) + { + // the selection will already be deleted, but we need to trim + // off the character before + std::string new_text = raw_text.substr(0, length-1); + self->mInputEditor->setText( new_text ); + self->mInputEditor->setCursorToEnd(); + length = length - 1; + } + */ + + KEY key = gKeyboard->currentKey(); + + // Ignore "special" keys, like backspace, arrows, etc. + if (length > 1 + && raw_text[0] == '/' + && key < KEY_SPECIAL) + { + // we're starting a gesture, attempt to autocomplete + + std::string utf8_trigger = wstring_to_utf8str(raw_text); + std::string utf8_out_str(utf8_trigger); + + if (LLGestureManager::instance().matchPrefix(utf8_trigger, &utf8_out_str)) + { + std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size()); + self->mChatBox->setText(utf8_trigger + rest_of_match); // keep original capitalization for user-entered part + S32 outlength = self->mChatBox->getLength(); // in characters + + // Select to end of line, starting from the character + // after the last one the user typed. + self->mChatBox->setSelection(length, outlength); + } + else if (matchChatTypeTrigger(utf8_trigger, &utf8_out_str)) + { + std::string rest_of_match = utf8_out_str.substr(utf8_trigger.size()); + self->mChatBox->setText(utf8_trigger + rest_of_match + " "); // keep original capitalization for user-entered part + self->mChatBox->setCursorToEnd(); + } + + //llinfos << "GESTUREDEBUG " << trigger + // << " len " << length + // << " outlen " << out_str.getLength() + // << llendl; + } +} + +// static +void LLNearbyChatBar::onChatBoxFocusLost(LLFocusableElement* caller, void* userdata) +{ + // stop typing animation + gAgent.stopTyping(); +} + +EChatType LLNearbyChatBar::processChatTypeTriggers(EChatType type, std::string &str) +{ + U32 length = str.length(); + S32 cnt = sizeof(sChatTypeTriggers) / sizeof(*sChatTypeTriggers); + + for (S32 n = 0; n < cnt; n++) + { + if (length >= sChatTypeTriggers[n].name.length()) + { + std::string trigger = str.substr(0, sChatTypeTriggers[n].name.length()); + + if (!LLStringUtil::compareInsensitive(trigger, sChatTypeTriggers[n].name)) + { + U32 trigger_length = sChatTypeTriggers[n].name.length(); + + // It's to remove space after trigger name + if (length > trigger_length && str[trigger_length] == ' ') + trigger_length++; + + str = str.substr(trigger_length, length); + + if (CHAT_TYPE_NORMAL == type) + return sChatTypeTriggers[n].type; + else + break; + } + } + } + + return type; +} + +void LLNearbyChatBar::sendChat( EChatType type ) +{ + if (mChatBox) + { + LLWString text = mChatBox->getConvertedText(); + if (!text.empty()) + { + // store sent line in history, duplicates will get filtered + mChatBox->updateHistory(); + // Check if this is destined for another channel + S32 channel = 0; + stripChannelNumber(text, &channel); + + std::string utf8text = wstring_to_utf8str(text); + // Try to trigger a gesture, if not chat to a script. + std::string utf8_revised_text; + if (0 == channel) + { + // discard returned "found" boolean + LLGestureManager::instance().triggerAndReviseString(utf8text, &utf8_revised_text); + } + else + { + utf8_revised_text = utf8text; + } + + utf8_revised_text = utf8str_trim(utf8_revised_text); + + type = processChatTypeTriggers(type, utf8_revised_text); + + if (!utf8_revised_text.empty()) + { + // Chat with animation + sendChatFromViewer(utf8_revised_text, type, TRUE); + } + } + + mChatBox->setText(LLStringExplicit("")); + } + + gAgent.stopTyping(); + + // If the user wants to stop chatting on hitting return, lose focus + // and go out of chat mode. + if (gSavedSettings.getBOOL("CloseChatOnReturn")) + { + stopChat(); + } +} + +void LLNearbyChatBar::onChatBoxCommit() +{ + if (mChatBox->getText().length() > 0) + { + sendChat(CHAT_TYPE_NORMAL); + } + + gAgent.stopTyping(); +} + +void LLNearbyChatBar::sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate) +{ + sendChatFromViewer(utf8str_to_wstring(utf8text), type, animate); +} + +void LLNearbyChatBar::sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate) +{ + // Look for "/20 foo" channel chats. + S32 channel = 0; + LLWString out_text = stripChannelNumber(wtext, &channel); + std::string utf8_out_text = wstring_to_utf8str(out_text); + std::string utf8_text = wstring_to_utf8str(wtext); + + utf8_text = utf8str_trim(utf8_text); + if (!utf8_text.empty()) + { + utf8_text = utf8str_truncate(utf8_text, MAX_STRING - 1); + } + + // Don't animate for chats people can't hear (chat to scripts) + if (animate && (channel == 0)) + { + if (type == CHAT_TYPE_WHISPER) + { + lldebugs << "You whisper " << utf8_text << llendl; + gAgent.sendAnimationRequest(ANIM_AGENT_WHISPER, ANIM_REQUEST_START); + } + else if (type == CHAT_TYPE_NORMAL) + { + lldebugs << "You say " << utf8_text << llendl; + gAgent.sendAnimationRequest(ANIM_AGENT_TALK, ANIM_REQUEST_START); + } + else if (type == CHAT_TYPE_SHOUT) + { + lldebugs << "You shout " << utf8_text << llendl; + gAgent.sendAnimationRequest(ANIM_AGENT_SHOUT, ANIM_REQUEST_START); + } + else + { + llinfos << "send_chat_from_viewer() - invalid volume" << llendl; + return; + } + } + else + { + if (type != CHAT_TYPE_START && type != CHAT_TYPE_STOP) + { + lldebugs << "Channel chat: " << utf8_text << llendl; + } + } + + send_chat_from_viewer(utf8_out_text, type, channel); +} + +// static +void LLNearbyChatBar::startChat(const char* line) +{ + LLBottomTray *bt = LLBottomTray::getInstance(); + + if (!bt) + return; + + LLNearbyChatBar* cb = bt->getNearbyChatBar(); + + if (!cb ) + return; + + bt->setVisible(TRUE); + cb->mChatBox->setFocus(TRUE); + + if (line) + { + std::string line_string(line); + cb->mChatBox->setText(line_string); + } + + cb->mChatBox->setCursorToEnd(); +} + +// Exit "chat mode" and do the appropriate focus changes +// static +void LLNearbyChatBar::stopChat() +{ + LLBottomTray *bt = LLBottomTray::getInstance(); + + if (!bt) + return; + + LLNearbyChatBar* cb = bt->getNearbyChatBar(); + + if (!cb) + return; + + cb->mChatBox->setFocus(FALSE); + + // stop typing animation + gAgent.stopTyping(); +} + +// If input of the form "/20foo" or "/20 foo", returns "foo" and channel 20. +// Otherwise returns input and channel 0. +LLWString LLNearbyChatBar::stripChannelNumber(const LLWString &mesg, S32* channel) +{ + if (mesg[0] == '/' + && mesg[1] == '/') + { + // This is a "repeat channel send" + *channel = sLastSpecialChatChannel; + return mesg.substr(2, mesg.length() - 2); + } + else if (mesg[0] == '/' + && mesg[1] + && LLStringOps::isDigit(mesg[1])) + { + // This a special "/20" speak on a channel + S32 pos = 0; + + // Copy the channel number into a string + LLWString channel_string; + llwchar c; + do + { + c = mesg[pos+1]; + channel_string.push_back(c); + pos++; + } + while(c && pos < 64 && LLStringOps::isDigit(c)); + + // Move the pointer forward to the first non-whitespace char + // Check isspace before looping, so we can handle "/33foo" + // as well as "/33 foo" + while(c && iswspace(c)) + { + c = mesg[pos+1]; + pos++; + } + + sLastSpecialChatChannel = strtol(wstring_to_utf8str(channel_string).c_str(), NULL, 10); + *channel = sLastSpecialChatChannel; + return mesg.substr(pos, mesg.length() - pos); + } + else + { + // This is normal chat. + *channel = 0; + return mesg; + } +} + +void LLNearbyChatBar::setPTTState(bool state) +{ + mTalkBtn->setSpeakBtnToggleState(state); +} + +void send_chat_from_viewer(const std::string& utf8_out_text, EChatType type, S32 channel) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_ChatFromViewer); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_ChatData); + msg->addStringFast(_PREHASH_Message, utf8_out_text); + msg->addU8Fast(_PREHASH_Type, type); + msg->addS32("Channel", channel); + + gAgent.sendReliableMessage(); + + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CHAT_COUNT); +} + +class LLChatHandler : public LLCommandHandler +{ +public: + // not allowed from outside the app + LLChatHandler() : LLCommandHandler("chat", true) { } + + // Your code here + bool handle(const LLSD& tokens, const LLSD& query_map, + LLMediaCtrl* web) + { + if (tokens.size() < 2) return false; + S32 channel = tokens[0].asInteger(); + std::string mesg = tokens[1].asString(); + send_chat_from_viewer(mesg, CHAT_TYPE_NORMAL, channel); + return true; + } +}; + +void LLNearbyChatBar::onChange(EStatusType status, const std::string &channelURI, bool proximal) +{ + // Time it takes to connect to voice channel might be pretty long, + // so don't expect user login or STATUS_VOICE_ENABLED to be followed by STATUS_JOINED. + BOOL enable = FALSE; + + switch (status) + { + // Do not add STATUS_VOICE_ENABLED because voice chat is + // inactive until STATUS_JOINED + case STATUS_JOINED: + enable = TRUE; + break; + default: + enable = FALSE; + break; + } + + mTalkBtn->setEnabled(enable); +} + +// Creating the object registers with the dispatcher. +LLChatHandler gChatHandler; + + diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h new file mode 100644 index 0000000000..19177e37b3 --- /dev/null +++ b/indra/newview/llnearbychatbar.h @@ -0,0 +1,118 @@ +/** + * @file llnearbychatbar.h + * @brief LLNearbyChatBar class definition + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNEARBYCHATBAR_H +#define LL_LLNEARBYCHATBAR_H + +#include "llpanel.h" +#include "llcombobox.h" +#include "llgesturemgr.h" +#include "llchat.h" +#include "llchiclet.h" +#include "llvoiceclient.h" + +class LLGestureComboBox + : public LLComboBox + , public LLGestureManagerObserver +{ +public: + struct Params : public LLInitParam::Block { }; +protected: + LLGestureComboBox(const Params&); + friend class LLUICtrlFactory; +public: + ~LLGestureComboBox(); + + void refreshGestures(); + void onCommitGesture(); + virtual void draw(); + + // LLGestureManagerObserver trigger + virtual void changed() { refreshGestures(); } + +protected: + LLFrameTimer mGestureLabelTimer; + std::vector mGestures; + std::string mLabel; +}; + +class LLNearbyChatBar +: public LLPanel +, public LLVoiceClientStatusObserver +{ +public: + // constructor for inline chat-bars (e.g. hosted in chat history window) + LLNearbyChatBar(); + ~LLNearbyChatBar() {} + + virtual BOOL postBuild(); + + static LLNearbyChatBar* getInstance(); + + static bool instanceExists(); + + LLLineEditor* getChatBox() { return mChatBox; } + + std::string getCurrentChat(); + virtual BOOL handleKeyHere( KEY key, MASK mask ); + + void setPTTState(bool state); + static void startChat(const char* line); + static void stopChat(); + + static void sendChatFromViewer(const std::string &utf8text, EChatType type, BOOL animate); + static void sendChatFromViewer(const LLWString &wtext, EChatType type, BOOL animate); + + /** + * Implements LLVoiceClientStatusObserver::onChange() + */ + /*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal); + +protected: + static BOOL matchChatTypeTrigger(const std::string& in_str, std::string* out_str); + static void onChatBoxKeystroke(LLLineEditor* caller, void* userdata); + static void onChatBoxFocusLost(LLFocusableElement* caller, void* userdata); + + void sendChat( EChatType type ); + void onChatBoxCommit(); + + static LLWString stripChannelNumber(const LLWString &mesg, S32* channel); + EChatType processChatTypeTriggers(EChatType type, std::string &str); + + // Which non-zero channel did we last chat on? + static S32 sLastSpecialChatChannel; + + LLLineEditor* mChatBox; + LLTalkButton* mTalkBtn; +}; + +#endif diff --git a/indra/newview/llnearbychathandler.cpp b/indra/newview/llnearbychathandler.cpp new file mode 100644 index 0000000000..a1912655a3 --- /dev/null +++ b/indra/newview/llnearbychathandler.cpp @@ -0,0 +1,129 @@ +/** + * @file LLNearbyChatHandler.cpp + * @brief Nearby chat notification managment + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llnearbychathandler.h" + +#include "llchatitemscontainerctrl.h" +#include "llnearbychat.h" +#include "llrecentpeople.h" + +#include "llviewercontrol.h" + +#include "llfloaterreg.h"//for LLFloaterReg::getTypedInstance + +//add LLNearbyChatHandler to LLNotificationsUI namespace +namespace LLNotificationsUI{ + + +LLNearbyChatHandler::LLNearbyChatHandler(e_notification_type type, const LLSD& id) +{ + mType = type; + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat", LLSD()); + ///////////////////////////////////////////////////// + LLChannelManager::Params p; //TODO: check and correct + p.id = LLUUID(gSavedSettings.getString("NearByChatChannelUUID")); + p.channel_right_bound = nearby_chat->getRect().mRight; + p.channel_width = nearby_chat->getRect().mRight - 16; //HACK: 16 - ? + ///////////////////////////////////////////////////// + + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); + mChannel->setFollows(FOLLOWS_LEFT | FOLLOWS_BOTTOM | FOLLOWS_TOP); + mChannel->setOverflowFormatString("You have %d unread nearby chat messages"); +} +LLNearbyChatHandler::~LLNearbyChatHandler() +{ +} +void LLNearbyChatHandler::processChat(const LLChat& chat_msg) +{ + if(chat_msg.mMuted == TRUE) + return; + if(chat_msg.mSourceType == CHAT_SOURCE_AGENT && chat_msg.mFromID.notNull()) + LLRecentPeople::instance().add(chat_msg.mFromID); + + if(chat_msg.mText.empty()) + return;//don't process empty messages + + LLNearbyChat* nearby_chat = LLFloaterReg::getTypedInstance("nearby_chat", LLSD()); + nearby_chat->addMessage(chat_msg); + if(nearby_chat->getVisible()) + return;//no need in toast if chat is visible + + LLUUID id; + id.generate(); + + LLChatItemCtrl* item = LLChatItemCtrl::createInstance(); + + item->setMessage(chat_msg); + //static S32 chat_item_width = nearby_chat->getRect().getWidth() - 16; + static S32 chat_item_width = 304; + item->setWidth(chat_item_width); + item->setHeaderVisibility((EShowItemHeader)gSavedSettings.getS32("nearbychat_showicons_and_names")); + + item->setVisible(true); + + LLToast::Params p; + p.id = id; + p.panel = item; + p.on_toast_destroy = boost::bind(&LLNearbyChatHandler::onToastDestroy, this, _1); + p.on_mouse_enter = boost::bind(&LLNearbyChatHandler::removeNearbyToastsAndShowChat, this); + mChannel->addToast(p); +} + +void LLNearbyChatHandler::onToastDestroy(LLToast* toast) +{ + if(toast) + toast->closeFloater(); +} + +void LLNearbyChatHandler::onChicletClick(void) +{ +} +void LLNearbyChatHandler::onChicletClose(void) +{ +} + +void LLNearbyChatHandler::removeNearbyToastsAndShowChat() +{ + /* + if(mChannel) + mChannel->removeToastsFromChannel(); + + LLFloaterReg::showTypedInstance("nearby_chat", LLSD()); + */ +} + +} + diff --git a/indra/newview/llnearbychathandler.h b/indra/newview/llnearbychathandler.h new file mode 100644 index 0000000000..8fcd03689d --- /dev/null +++ b/indra/newview/llnearbychathandler.h @@ -0,0 +1,59 @@ +/** + * @file llnearbychathandler.h + * @brief nearby chat notify + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNEARBYCHATHANDLER_H +#define LL_LLNEARBYCHATHANDLER_H + +#include "llnotificationhandler.h" + +//add LLNearbyChatHandler to LLNotificationsUI namespace +namespace LLNotificationsUI{ + +class LLNearbyChatHandler : public LLChatHandler +{ +public: + LLNearbyChatHandler(e_notification_type type,const LLSD& id); + virtual ~LLNearbyChatHandler(); + + + virtual void processChat(const LLChat& chat_msg); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: + void removeNearbyToastsAndShowChat(); +}; + +} + +#endif /* LL_LLNEARBYCHATHANDLER_H */ diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp index 23d32fee81..7b0b0c2fb7 100644 --- a/indra/newview/llnetmap.cpp +++ b/indra/newview/llnetmap.cpp @@ -1,7 +1,7 @@ /** * @file llnetmap.cpp * @author James Cook - * @brief Display of surrounding regions, objects, and agents. View contained by LLFloaterMap. + * @brief Display of surrounding regions, objects, and agents. * * $LicenseInfo:firstyear=2001&license=viewergpl$ * @@ -36,83 +36,46 @@ #include "llnetmap.h" #include "indra_constants.h" -#include "llui.h" -#include "llmath.h" // clampf() +#include "llmath.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llrender.h" - -#include "llagent.h" -#include "llcallingcard.h" -#include "llcolorscheme.h" -#include "llviewercontrol.h" -#include "llfloateravatarinfo.h" -#include "llfloaterworldmap.h" -#include "llframetimer.h" -#include "lltracker.h" -#include "llmenugl.h" -#include "llsurface.h" -#include "lltextbox.h" -#include "lluictrlfactory.h" -#include "lluuid.h" -#include "llviewercamera.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" -#include "llviewermenu.h" -#include "llviewerobjectlist.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" -#include "llvoavatar.h" -#include "llworld.h" -#include "llworldmapview.h" // shared draw code -#include "llappviewer.h" // Only for constants! +#include "llui.h" #include "llglheaders.h" -using namespace LLOldEvents; +#include "llagent.h" +#include "llappviewer.h" // for gDisconnected +#include "llcallingcard.h" // LLAvatarTracker +#include "lltracker.h" +#include "llsurface.h" +#include "llviewercamera.h" +#include "llviewercontrol.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerregion.h" +#include "llworld.h" +#include "llworldmapview.h" // shared draw code + +static LLDefaultChildRegistry::Register r1("net_map"); const F32 MAP_SCALE_MIN = 64; const F32 MAP_SCALE_MID = 172; const F32 MAP_SCALE_MAX = 512; const F32 MAP_SCALE_INCREMENT = 16; const F32 MAP_MIN_PICK_DIST = 4; -const F32 MAP_MINOR_DIR_THRESHOLD = 0.08f; +const F32 MAX_PRIM_RADIUS = 256.0f; // Don't try to draw giant mega-prims on the mini map -const S32 TRACKING_RADIUS = 3; - -LLNetMap::LLNetMap(const std::string& name) : - LLPanel(name), - mScale(128.f), - mObjectMapTPM(1.f), - mObjectMapPixels(255.f), - mTargetPanX( 0.f ), - mTargetPanY( 0.f ), - mCurPanX( 0.f ), - mCurPanY( 0.f ), - mUpdateNow( FALSE ) +LLNetMap::LLNetMap (const Params & p) : + LLUICtrl (p), + mScale(128.0f), + mBackgroundColor (p.bg_color()), + mRotateMap(FALSE) { - mScale = gSavedSettings.getF32("MiniMapScale"); - mPixelsPerMeter = mScale / LLWorld::getInstance()->getRegionWidthInMeters(); - mObjectImageCenterGlobal = gAgent.getCameraPositionGlobal(); - - // Register event listeners for popup menu - (new LLScaleMap())->registerListener(this, "MiniMap.ZoomLevel"); - (new LLStopTracking())->registerListener(this, "MiniMap.StopTracking"); - (new LLEnableTracking())->registerListener(this, "MiniMap.EnableTracking"); - (new LLShowAgentProfile())->registerListener(this, "MiniMap.ShowProfile"); - (new LLEnableProfile())->registerListener(this, "MiniMap.EnableProfile"); - - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_mini_map.xml"); - - updateMinorDirections(); - - LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_mini_map.xml", this); - if (!menu) - { - menu = new LLMenuGL(LLStringUtil::null); - } - menu->setVisible(FALSE); - mPopupMenuHandle = menu->getHandle(); + mPixelsPerMeter = mScale / REGION_WIDTH_METERS; } LLNetMap::~LLNetMap() @@ -121,26 +84,21 @@ LLNetMap::~LLNetMap() void LLNetMap::setScale( F32 scale ) { - mScale = scale; - if (mScale == 0.f) - { - mScale = 0.1f; - } - gSavedSettings.setF32("MiniMapScale", mScale); - + mScale = llclamp(scale, 0.1f, 16.f*1024.f); // [reasonably small , unreasonably large] + if (mObjectImagep.notNull()) { - F32 width = (F32)(getRect().getWidth()); - F32 height = (F32)(getRect().getHeight()); - F32 diameter = sqrt(width * width + height * height); - F32 region_widths = diameter / mScale; + F32 half_width = (F32)(getRect().getWidth() / 2); + F32 half_height = (F32)(getRect().getHeight() / 2); + F32 radius = sqrt( half_width * half_width + half_height * half_height ); + F32 region_widths = (2.f*radius)/mScale; F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters(); F32 num_pixels = (F32)mObjectImagep->getWidth(); - mObjectMapTPM = num_pixels / meters; - mObjectMapPixels = diameter; + mObjectMapTPM = num_pixels/meters; + mObjectMapPixels = 2.f*radius; } - mPixelsPerMeter = mScale / LLWorld::getInstance()->getRegionWidthInMeters(); + mPixelsPerMeter = mScale / REGION_WIDTH_METERS; mUpdateNow = TRUE; } @@ -157,21 +115,27 @@ void LLNetMap::translatePan( F32 delta_x, F32 delta_y ) void LLNetMap::draw() { static LLFrameTimer map_timer; - + static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); + static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white); + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white); + static LLUIColor map_frustum_color = LLUIColorTable::instance().getColor("MapFrustumColor", LLColor4::white); + static LLUIColor map_frustum_rotating_color = LLUIColorTable::instance().getColor("MapFrustumRotatingColor", LLColor4::white); + if (mObjectImagep.isNull()) { createObjectImage(); } - + mCurPanX = lerp(mCurPanX, mTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); mCurPanY = lerp(mCurPanY, mTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); + // Prepare a scissor region F32 rotation = 0; - // Prepare a scissor region { LLGLEnable scissor(GL_SCISSOR_TEST); - + { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); LLLocalClipRect clip(getLocalRect()); @@ -179,11 +143,9 @@ void LLNetMap::draw() glMatrixMode(GL_MODELVIEW); // Draw background rectangle - if(isBackgroundVisible()) - { - gGL.color4fv(isBackgroundOpaque() ? getBackgroundColor().mV : getTransparentColor().mV); - gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0); - } + LLColor4 background_color = mBackgroundColor.get(); + gGL.color4fv( background_color.mV ); + gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0); } // region 0,0 is in the middle @@ -194,8 +156,7 @@ void LLNetMap::draw() gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f); - BOOL rotate_map = gSavedSettings.getBOOL( "MiniMapRotate" ); - if( rotate_map ) + if( mRotateMap ) { // rotate subsequent draws to agent rotation rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); @@ -204,9 +165,6 @@ void LLNetMap::draw() // figure out where agent is S32 region_width = llround(LLWorld::getInstance()->getRegionWidthInMeters()); - LLColor4 this_region_color = gColors.getColor( "NetMapThisRegion" ); - LLColor4 live_region_color = gColors.getColor( "NetMapLiveRegion" ); - LLColor4 dead_region_color = gColors.getColor( "NetMapDeadRegion" ); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -224,10 +182,18 @@ void LLNetMap::draw() F32 top = bottom + mScale ; F32 right = left + mScale ; - gGL.color4fv(regionp == gAgent.getRegion() ? this_region_color.mV : live_region_color.mV); + if (regionp == gAgent.getRegion()) + { + gGL.color4f(1.f, 1.f, 1.f, 1.f); + } + else + { + gGL.color4f(0.8f, 0.8f, 0.8f, 1.f); + } + if (!regionp->isAlive()) { - gGL.color4fv(dead_region_color.mV); + gGL.color4f(1.f, 0.5f, 0.5f, 1.f); } @@ -319,57 +285,86 @@ void LLNetMap::draw() // Mouse pointer in local coordinates S32 local_mouse_x; S32 local_mouse_y; + //localMouse(&local_mouse_x, &local_mouse_y); LLUI::getCursorPositionLocal(this, &local_mouse_x, &local_mouse_y); mClosestAgentToCursor.setNull(); F32 closest_dist = F32_MAX; // Draw avatars - LLColor4 avatar_color = gColors.getColor( "MapAvatar" ); - LLColor4 friend_color = gColors.getColor( "MapFriend" ); - std::vector avatar_ids; - std::vector positions; - LLWorld::getInstance()->getAvatars(&avatar_ids, &positions); - for(U32 i=0; igetRegionList().begin(); + iter != LLWorld::getInstance()->getRegionList().end(); ++iter) { + LLViewerRegion* regionp = *iter; + const LLVector3d& origin_global = regionp->getOriginGlobal(); + + S32 count = regionp->mMapAvatars.count(); + S32 i; + LLVector3 pos_local; + U32 compact_local; + U8 bits; // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest. // just be careful to sort the avatar IDs along with the positions. -MG - pos_map = globalPosToView(positions[i], rotate_map); - - LLWorldMapView::drawAvatar( - pos_map.mV[VX], pos_map.mV[VY], - is_agent_friend(avatar_ids[i]) ? friend_color : avatar_color, - pos_map.mV[VZ]); - - F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); - if(dist_to_cursor < MAP_MIN_PICK_DIST && dist_to_cursor < closest_dist) + for (i = 0; i < count; i++) { - closest_dist = dist_to_cursor; - mClosestAgentToCursor = avatar_ids[i]; + compact_local = regionp->mMapAvatars.get(i); + + bits = compact_local & 0xFF; + pos_local.mV[VZ] = F32(bits) * 4.f; + compact_local >>= 8; + + bits = compact_local & 0xFF; + pos_local.mV[VY] = (F32)bits; + compact_local >>= 8; + + bits = compact_local & 0xFF; + pos_local.mV[VX] = (F32)bits; + + pos_global.setVec( pos_local ); + pos_global += origin_global; + + pos_map = globalPosToView(pos_global); + + BOOL show_as_friend = FALSE; + if( i < regionp->mMapAvatarIDs.count()) + { + show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL); + } + LLWorldMapView::drawAvatar( + pos_map.mV[VX], pos_map.mV[VY], + show_as_friend ? map_avatar_friend_color : map_avatar_color, + pos_map.mV[VZ]); + + F32 dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y)); + if(dist_to_cursor < MAP_MIN_PICK_DIST && dist_to_cursor < closest_dist) + { + closest_dist = dist_to_cursor; + mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i); + } } } // Draw dot for autopilot target if (gAgent.getAutoPilot()) { - drawTracking( gAgent.getAutoPilotTargetGlobal(), rotate_map, gTrackColor ); + drawTracking( gAgent.getAutoPilotTargetGlobal(), map_track_color ); } else { LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); if ( LLTracker::TRACKING_AVATAR == tracking_status ) { - drawTracking( LLAvatarTracker::instance().getGlobalPos(), rotate_map, gTrackColor ); + drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color ); } else if ( LLTracker::TRACKING_LANDMARK == tracking_status || LLTracker::TRACKING_LOCATION == tracking_status ) { - drawTracking( LLTracker::getTrackedPositionGlobal(), rotate_map, gTrackColor ); + drawTracking( LLTracker::getTrackedPositionGlobal(), map_track_color ); } } // Draw dot for self avatar position pos_global = gAgent.getPositionGlobal(); - pos_map = globalPosToView(pos_global, rotate_map); + pos_map = globalPosToView(pos_global); LLUIImagePtr you = LLWorldMapView::sAvatarYouSmallImage; you->draw( llround(pos_map.mV[VX]) - you->getWidth()/2, @@ -391,9 +386,9 @@ void LLNetMap::draw() gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - if( rotate_map ) + if( mRotateMap ) { - gGL.color4fv(gColors.getColor("NetMapFrustum").mV); + gGL.color4fv((map_frustum_color()).mV); gGL.begin( LLRender::TRIANGLES ); gGL.vertex2f( ctr_x, ctr_y ); @@ -403,7 +398,7 @@ void LLNetMap::draw() } else { - gGL.color4fv(gColors.getColor("NetMapFrustumRotating").mV); + gGL.color4fv((map_frustum_rotating_color()).mV); // If we don't rotate the map, we have to rotate the frustum. gGL.pushMatrix(); @@ -418,27 +413,11 @@ void LLNetMap::draw() } } - // Rotation of 0 means that North is up - setDirectionPos( getChild("e_label"), rotation); - setDirectionPos( getChild("n_label"), rotation + F_PI_BY_TWO); - setDirectionPos( getChild("w_label"), rotation + F_PI); - setDirectionPos( getChild("s_label"), rotation + F_PI + F_PI_BY_TWO); - - setDirectionPos( getChild("ne_label"), rotation + F_PI_BY_TWO / 2); - setDirectionPos( getChild("nw_label"), rotation + F_PI_BY_TWO + F_PI_BY_TWO / 2); - setDirectionPos( getChild("sw_label"), rotation + F_PI + F_PI_BY_TWO / 2); - setDirectionPos( getChild("se_label"), rotation + F_PI + F_PI_BY_TWO + F_PI_BY_TWO / 2); - - LLView::draw(); + LLUICtrl::draw(); } -void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent) +LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos ) { - LLPanel::reshape(width, height, called_from_parent); - updateMinorDirections(); -} - -LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos, BOOL rotated ){ LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal(); LLVector3 pos_local; pos_local.setVec(relative_pos_global); // convert to floats from doubles @@ -447,7 +426,7 @@ LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos, BOOL rotated pos_local.mV[VY] *= mPixelsPerMeter; // leave Z component in meters - if( rotated ) + if( mRotateMap ) { F32 radians = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); @@ -460,10 +439,10 @@ LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos, BOOL rotated return pos_local; } -void LLNetMap::drawTracking(const LLVector3d& pos_global, BOOL rotated, - const LLColor4& color, BOOL draw_arrow ) +void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color, + BOOL draw_arrow ) { - LLVector3 pos_local = globalPosToView( pos_global, rotated ); + LLVector3 pos_local = globalPosToView( pos_global ); if( (pos_local.mV[VX] < 0) || (pos_local.mV[VY] < 0) || (pos_local.mV[VX] >= getRect().getWidth()) || @@ -486,16 +465,16 @@ void LLNetMap::drawTracking(const LLVector3d& pos_global, BOOL rotated, } } -LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y, BOOL rotated ) +LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y ) { x -= llround(getRect().getWidth() / 2 + mCurPanX); y -= llround(getRect().getHeight() / 2 + mCurPanY); - LLVector3 pos_local( (F32)x, (F32)y, 0.f ); + LLVector3 pos_local( (F32)x, (F32)y, 0 ); F32 radians = - atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ); - if( rotated ) + if( mRotateMap ) { LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f)); pos_local.rotVec( rot ); @@ -524,87 +503,55 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rec { return FALSE; } - LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y , gSavedSettings.getBOOL( "MiniMapRotate" )) ); + + // mToolTipMsg = "[AGENT][REGION](Double-click to open Map)" + + LLStringUtil::format_map_t args; + std::string fullname; + if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, fullname)) + { + args["[AGENT]"] = fullname + "\n"; + } + else + { + args["[AGENT]"] = ""; + } + + LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) ); if( region ) { - msg.assign(""); - std::string fullname; - if(mClosestAgentToCursor.notNull() && gCacheName->getFullName(mClosestAgentToCursor, fullname)) - { - msg.append(fullname); - msg.append("\n"); - } - msg.append( region->getName() ); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - std::string buffer; - msg.append("\n"); - buffer = region->getHost().getHostName(); - msg.append(buffer); - msg.append("\n"); - buffer = region->getHost().getString(); - msg.append(buffer); -#endif - msg.append("\n"); - msg.append(getToolTip()); - + args["[REGION]"] = region->getName() + "\n"; + } + else + { + args["[REGION]"] = ""; + } + + msg = mToolTipMsg; + LLStringUtil::format(msg, args); + + // set sticky_rect + if (region) + { S32 SLOP = 4; localPointToScreen( x - SLOP, y - SLOP, &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; - handled = TRUE; - } - if(!handled) - { - return LLPanel::handleToolTip(x, y, msg, sticky_rect_screen); } + + handled = TRUE; return handled; } -void LLNetMap::setDirectionPos( LLTextBox* text_box, F32 rotation ) -{ - // Rotation is in radians. - // Rotation of 0 means x = 1, y = 0 on the unit circle. - - F32 half_height = (F32)( (getRect().getHeight() - text_box->getRect().getHeight()) / 2); - F32 half_width = (F32)( (getRect().getWidth() - text_box->getRect().getWidth()) / 2); - F32 radius = llmin( half_height, half_width ); - - // Inset by a little to account for position display. - radius -= 8.f; - - text_box->setOrigin(llround(half_width + radius * cos( rotation )), - llround(half_height + radius * sin( rotation ))); -} - -void LLNetMap::updateMinorDirections() -{ - if (getChild("ne_label") == NULL) - { - return; - } - - // Hide minor directions if they cover too much of the map - bool show_minors = getChild("ne_label")->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD * - llmin(getRect().getWidth(), getRect().getHeight()); - - getChild("ne_label")->setVisible(show_minors); - getChild("nw_label")->setVisible(show_minors); - getChild("sw_label")->setVisible(show_minors); - getChild("se_label")->setVisible(show_minors); -} - void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters ) { LLVector3 local_pos; local_pos.setVec( pos - mObjectImageCenterGlobal ); - // DEV-17370 - megaprims of size > 4096 cause lag. (go figger.) - const F32 MAX_RADIUS = 256.0f; - F32 radius_clamped = llmin(radius_meters, MAX_RADIUS); + F32 radius_clamped = llmin(radius_meters, MAX_PRIM_RADIUS); S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM); renderPoint( local_pos, color, diameter_pixels ); @@ -699,10 +646,10 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color, void LLNetMap::createObjectImage() { // Find the size of the side of a square that surrounds the circle that surrounds getRect(). - // ... which is, the diagonal of the rect. - F32 width = getRect().getWidth(); - F32 height = getRect().getHeight(); - S32 square_size = llround( sqrt(width*width + height*height) ); + F32 half_width = (F32)(getRect().getWidth() / 2); + F32 half_height = (F32)(getRect().getHeight() / 2); + F32 radius = sqrt( half_width * half_width + half_height * half_height ); + S32 square_size = S32( 2 * radius ); // Find the least power of two >= the minimum size. const S32 MIN_SIZE = 32; @@ -720,80 +667,8 @@ void LLNetMap::createObjectImage() mObjectRawImagep = new LLImageRaw(img_size, img_size, 4); U8* data = mObjectRawImagep->getData(); memset( data, 0, img_size * img_size * 4 ); - mObjectImagep = new LLImageGL( mObjectRawImagep, FALSE); + mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE); setScale(mScale); } mUpdateNow = TRUE; } - -BOOL LLNetMap::handleDoubleClick( S32 x, S32 y, MASK mask ) -{ - LLFloaterWorldMap::show(NULL, FALSE); - return TRUE; -} - -BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask) -{ - mClosestAgentAtLastRightClick = mClosestAgentToCursor; - LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); - if (menu) - { - menu->buildDrawLabels(); - menu->updateParent(LLMenuGL::sMenuContainer); - LLMenuGL::showPopup(this, menu, x, y); - } - return TRUE; -} - - -// static -bool LLNetMap::LLScaleMap::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - - S32 level = userdata.asInteger(); - - switch(level) - { - case 0: - self->setScale(MAP_SCALE_MIN); - break; - case 1: - self->setScale(MAP_SCALE_MID); - break; - case 2: - self->setScale(MAP_SCALE_MAX); - break; - default: - break; - } - - return true; -} - -bool LLNetMap::LLStopTracking::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLTracker::stopTracking(NULL); - return true; -} - -bool LLNetMap::LLEnableTracking::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - self->findControl(userdata["control"].asString())->setValue(LLTracker::isTracking(NULL)); - return true; -} - -bool LLNetMap::LLShowAgentProfile::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - LLFloaterAvatarInfo::show(self->mClosestAgentAtLastRightClick); - return true; -} - -bool LLNetMap::LLEnableProfile::handleEvent(LLPointer event, const LLSD& userdata) -{ - LLNetMap *self = mPtr; - self->findControl(userdata["control"].asString())->setValue(self->isAgentUnderCursor()); - return true; -} diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h index 9fbd5097fd..a673ea3f57 100644 --- a/indra/newview/llnetmap.h +++ b/indra/newview/llnetmap.h @@ -33,55 +33,67 @@ #ifndef LL_LLNETMAP_H #define LL_LLNETMAP_H -#include "llpanel.h" -#include "llmemberlistener.h" +#include "llmath.h" +#include "lluictrl.h" #include "v3math.h" #include "v3dmath.h" #include "v4color.h" #include "llimage.h" -#include "llimagegl.h" - +class LLColor4U; +class LLCoordGL; class LLTextBox; +class LLViewerTexture ; -class LLNetMap : public LLPanel +class LLNetMap : public LLUICtrl { public: - LLNetMap(const std::string& name); + struct Params + : public LLInitParam::Block + { + Optional bg_color; + + Params() + : bg_color("bg_color") + {} + }; + +protected: + LLNetMap (const Params & p); + friend class LLUICtrlFactory; + +public: virtual ~LLNetMap(); - virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); - virtual BOOL handleDoubleClick( S32 x, S32 y, MASK mask ); - virtual BOOL handleRightMouseDown( S32 x, S32 y, MASK mask ); - virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); - virtual BOOL handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ); - - void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); - -private: - + /*virtual*/ void draw(); + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + /*virtual*/ BOOL handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ); + void setScale( F32 scale ); - - // *TODO: Enable panning of the mini-map + void setRotateMap( BOOL b ) { mRotateMap = b; } + void setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; } + BOOL getRotateMap( ) { return mRotateMap; } + void renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius ); + +private: void translatePan( F32 delta_x, F32 delta_y ); void setPan( F32 x, F32 y ) { mTargetPanX = x; mTargetPanY = y; } - void renderPoint(const LLVector3 &pos, const LLColor4U &color, - S32 diameter, S32 relative_height = 0); - LLVector3 globalPosToView(const LLVector3d& global_pos, BOOL rotated); - LLVector3d viewPosToGlobal(S32 x,S32 y, BOOL rotated); + const LLVector3d& getObjectImageCenterGlobal() { return mObjectImageCenterGlobal; } + void renderPoint(const LLVector3 &pos, const LLColor4U &color, + S32 diameter, S32 relative_height = 0); - void drawTracking( const LLVector3d& pos_global, - BOOL rotated, - const LLColor4& color, - BOOL draw_arrow = TRUE); + LLVector3 globalPosToView(const LLVector3d& global_pos); + LLVector3d viewPosToGlobal(S32 x,S32 y); + + void drawTracking( const LLVector3d& pos_global, + const LLColor4& color, + BOOL draw_arrow = TRUE); - void setDirectionPos( LLTextBox* text_box, F32 rotation ); - void updateMinorDirections(); void createObjectImage(); - - LLHandle mPopupMenuHandle; + +private: + LLUIColor mBackgroundColor; F32 mScale; // Size of a region in pixels F32 mPixelsPerMeter; // world meters to map pixels @@ -94,47 +106,13 @@ private: BOOL mUpdateNow; LLVector3d mObjectImageCenterGlobal; LLPointer mObjectRawImagep; - LLPointer mObjectImagep; + LLPointer mObjectImagep; -private: LLUUID mClosestAgentToCursor; LLUUID mClosestAgentAtLastRightClick; - static BOOL sRotateMap; - static LLNetMap* sInstance; - static BOOL isAgentUnderCursor(void*) { return sInstance && sInstance->mClosestAgentToCursor.notNull(); } - static void showAgentProfile(void*); - BOOL isAgentUnderCursor() { return mClosestAgentToCursor.notNull(); } - - class LLScaleMap : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLStopTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLEnableTracking : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLShowAgentProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; - - class LLEnableProfile : public LLMemberListener - { - public: - /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); - }; + BOOL mRotateMap; + std::string mToolTipMsg; }; diff --git a/indra/newview/llnotificationalerthandler.cpp b/indra/newview/llnotificationalerthandler.cpp new file mode 100644 index 0000000000..bd6c6b2308 --- /dev/null +++ b/indra/newview/llnotificationalerthandler.cpp @@ -0,0 +1,117 @@ +/** + * @file llnotificationalerthandler.cpp + * @brief Notification Handler Class for Alert Notifications + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llnotificationhandler.h" +#include "lltoastnotifypanel.h" +#include "llbottomtray.h" +#include "llviewercontrol.h" + +#include "lltoastalertpanel.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLAlertHandler::LLAlertHandler(e_notification_type type, const LLSD& id) : mIsModal(false) +{ + mType = type; + + LLBottomTray* tray = LLBottomTray::getInstance(); + LLChannelManager::Params p; + p.id = LLUUID(gSavedSettings.getString("AlertChannelUUID")); + p.channel_right_bound = tray->getRect().getWidth() / 2; + p.channel_width = 0; + p.display_toasts_always = true; + p.align = NA_CENTRE; + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); + mChannel->setFollows(FOLLOWS_BOTTOM | FOLLOWS_TOP); + mChannel->setShowToasts(true); +} + +//-------------------------------------------------------------------------- +LLAlertHandler::~LLAlertHandler() +{ +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::processNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "load") + { + LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); + LLToast::Params p; + p.id = notification->getID(); + p.notification = notification; + p.panel = dynamic_cast(alert_dialog); + p.enable_hide_btn = false; + p.can_fade = false; + p.is_modal = mIsModal; + p.on_toast_destroy = boost::bind(&LLAlertHandler::onToastDestroy, this, _1); + mChannel->addToast(p); + } + else if (notify["sigtype"].asString() == "change") + { + LLToastAlertPanel* alert_dialog = new LLToastAlertPanel(notification, mIsModal); + mChannel->modifyToastByNotificationID(notification->getID(), (LLToastPanel*)alert_dialog); + } + else + { + mChannel->killToastByNotificationID(notification->getID()); + } +} + +//-------------------------------------------------------------------------- + +void LLAlertHandler::onToastDestroy(LLToast* toast) +{ + toast->closeFloater(); +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::onChicletClick(void) +{ +} + +//-------------------------------------------------------------------------- +void LLAlertHandler::onChicletClose(void) +{ +} + +//-------------------------------------------------------------------------- + + diff --git a/indra/newview/llnotificationgrouphandler.cpp b/indra/newview/llnotificationgrouphandler.cpp new file mode 100644 index 0000000000..31753efec9 --- /dev/null +++ b/indra/newview/llnotificationgrouphandler.cpp @@ -0,0 +1,118 @@ +/** + * @file llnotificationgrouphandler.cpp + * @brief Notification Handler Class for Group Notifications + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llnotificationhandler.h" +#include "lltoastgroupnotifypanel.h" +#include "llbottomtray.h" +#include "llgroupactions.h" +#include "llviewercontrol.h" +#include "llfloaterreg.h" +#include "llsyswellwindow.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLGroupHandler::LLGroupHandler(e_notification_type type, const LLSD& id) +{ + mType = type; + + // getting a Chiclet and creating params for a channel + LLBottomTray* tray = LLBottomTray::getInstance(); + mChiclet = tray->getSysWell(); + LLChannelManager::Params p; + p.id = LLUUID(gSavedSettings.getString("NotificationChannelUUID")); + p.channel_right_bound = tray->getRect().mRight - gSavedSettings.getS32("NotificationChannelRightMargin"); + p.channel_width = gSavedSettings.getS32("NotifyBoxWidth"); + + // Getting a Channel for our notifications + mChannel = LLChannelManager::getInstance()->createChannel(p); +} + +//-------------------------------------------------------------------------- +LLGroupHandler::~LLGroupHandler() +{ +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::processNotification(const LLSD& notify) +{ + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change") + { + LLPanel* notify_box = new LLToastGroupNotifyPanel(notification); + LLToast::Params p; + p.id = notification->getID(); + p.notification = notification; + p.panel = notify_box; + p.on_toast_destroy = boost::bind(&LLGroupHandler::onToastDestroy, this, _1); + mChannel->addToast(p); + static_cast(mChiclet)->incUreadSystemNotifications(); + + LLGroupActions::refresh_notices(); + + } + else if (notify["sigtype"].asString() == "delete") + { + mChannel->killToastByNotificationID(notification->getID()); + } +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onToastDestroy(LLToast* toast) +{ + static_cast(mChiclet)->decUreadSystemNotifications(); + + LLToastPanel* panel = dynamic_cast(toast->getPanel()); + LLFloaterReg::getTypedInstance("syswell_window")->removeItemByID(panel->getID()); + + // turning hovering off mannualy because onMouseLeave won't happen if a toast was closed using a keyboard + if(toast->hasFocus()) + mChannel->setHovering(false); + + toast->closeFloater(); +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onChicletClick(void) +{ +} + +//-------------------------------------------------------------------------- +void LLGroupHandler::onChicletClose(void) +{ +} + +//-------------------------------------------------------------------------- + + diff --git a/indra/newview/llnotificationhandler.h b/indra/newview/llnotificationhandler.h new file mode 100644 index 0000000000..6982ab7096 --- /dev/null +++ b/indra/newview/llnotificationhandler.h @@ -0,0 +1,199 @@ +/** + * @file llnotificationhandler.h + * @brief Here are implemented Notification Handling Classes. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNOTIFICATIONHANDLER_H +#define LL_LLNOTIFICATIONHANDLER_H + + +#include "llwindow.h" + +#include "llnotifications.h" +#include "llchannelmanager.h" +#include "llchat.h" + +namespace LLNotificationsUI +{ +// ENotificationType enumerates all possible types of notifications that could be met +// +typedef enum e_notification_type +{ + NT_NOTIFY, + NT_NOTIFYTIP, + NT_GROUPNOTIFY, + NT_IMCHAT, + NT_GROUPCHAT, + NT_NEARBYCHAT, + NT_ALERT, + NT_ALERTMODAL +} ENotificationType; + +/** + * Handler of notification events. + * This handler manages events related to toasts and chicklets. This is base class + * for chat and system notification handlers. + */ + +// LLEventHandler is a base class that specifies a common interface for all +// notification handlers. It states, that every handler must react on the follofing +// events: +// - destroying of a toast; +// - clicking on a correspondet chiclet; +// - closing of a correspondent chiclet. +// Also every handler must have the following attributes: +// - type of the notification that this handler is responsible to; +// - pointer to a correspondent chiclet; +// - pointer to a correspondent screen channel, in which all toasts of the handled notification's +// type should be displayed +// +class LLEventHandler +{ +public: + virtual ~LLEventHandler() {}; + + virtual void onToastDestroy(LLToast* toast)=0; + virtual void onChicletClick(void)=0; + virtual void onChicletClose(void)=0; + + LLScreenChannel* mChannel; + LLChiclet* mChiclet; + e_notification_type mType; +}; + +// LLSysHandler and LLChatHandler are more specific base classes +// that divide all notification handlers on to groups: +// - handlers for different system notifications (script dialogs, tips, group notices and alerts); +// - handlers for different messaging notifications (nearby chat, IM chat, group chat etc.) +/** + * Handler for system notifications. + */ +class LLSysHandler : public LLEventHandler +{ +public: + virtual ~LLSysHandler() {}; + + virtual void processNotification(const LLSD& notify)=0; +}; + +/** + * Handler for chat message notifications. + */ +class LLChatHandler : public LLEventHandler +{ +public: + virtual ~LLChatHandler() {}; + + virtual void processChat(const LLChat& chat_msg)=0; +}; + +/** + * Handler for IM notifications. + * It manages life time of tip and script notices. + */ +class LLIMHandler : public LLSysHandler +{ +public: + LLIMHandler(); + virtual ~LLIMHandler(); + + // base interface functions + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: +}; + +/** + * Handler for system informational notices. + * It manages life time of tip and script notices. + */ +class LLInfoHandler : public LLSysHandler +{ +public: + LLInfoHandler(e_notification_type type, const LLSD& id); + virtual ~LLInfoHandler(); + + // base interface functions + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + + // own handlers + void onStoreToast(LLPanel* info_panel, LLUUID id); + void onRejectToast(LLToast::Params p); +protected: +}; + + +/** + * Handler for group system notices. + */ +class LLGroupHandler : public LLSysHandler +{ +public: + LLGroupHandler(e_notification_type type, const LLSD& id); + virtual ~LLGroupHandler(); + + + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: +}; + +/** + * Handler for alert system notices. + */ +class LLAlertHandler : public LLSysHandler +{ +public: + LLAlertHandler(e_notification_type type, const LLSD& id); + virtual ~LLAlertHandler(); + + void setAlertMode(bool is_modal) { mIsModal = is_modal; } + + virtual void processNotification(const LLSD& notify); + virtual void onToastDestroy(LLToast* toast); + virtual void onChicletClick(void); + virtual void onChicletClose(void); + +protected: + bool mIsModal; +}; + +} +#endif + diff --git a/indra/newview/llnotificationmanager.cpp b/indra/newview/llnotificationmanager.cpp new file mode 100644 index 0000000000..31266fdecf --- /dev/null +++ b/indra/newview/llnotificationmanager.cpp @@ -0,0 +1,130 @@ +/** + * @file llnotificationmanager.cpp + * @brief Class implements a brige between the old and a new notification sistems + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + + +#include "llviewerprecompiledheaders.h" // must be first include + + +#include "llnotificationmanager.h" +#include "llnearbychathandler.h" + +#include "boost/bind.hpp" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLNotificationManager::LLNotificationManager() +{ + mNotifyHandlers.clear(); + init(); +} + +//-------------------------------------------------------------------------- +LLNotificationManager::~LLNotificationManager() +{ +} + +//-------------------------------------------------------------------------- +void LLNotificationManager::init() +{ + LLNotificationChannel::buildChannel("Notifications", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "notify")); + LLNotificationChannel::buildChannel("NotificationTips", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "notifytip")); + LLNotificationChannel::buildChannel("Group Notifications", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "groupnotify")); + LLNotificationChannel::buildChannel("Alerts", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alert")); + LLNotificationChannel::buildChannel("AlertModal", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alertmodal")); + LLNotificationChannel::buildChannel("IM Notifications", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "notifytoast")); + + LLNotifications::instance().getChannel("Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("NotificationTips")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("Group Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("Alerts")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("AlertModal")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + LLNotifications::instance().getChannel("IM Notifications")->connectChanged(boost::bind(&LLNotificationManager::onNotification, this, _1)); + + mNotifyHandlers["notify"] = boost::shared_ptr(new LLInfoHandler(NT_NOTIFY, LLSD())); + mNotifyHandlers["notifytip"] = mNotifyHandlers["notify"]; + mNotifyHandlers["groupnotify"] = boost::shared_ptr(new LLGroupHandler(NT_GROUPNOTIFY, LLSD())); + mNotifyHandlers["alert"] = boost::shared_ptr(new LLAlertHandler(NT_ALERT, LLSD())); + mNotifyHandlers["alertmodal"] = mNotifyHandlers["alert"]; + mNotifyHandlers["notifytoast"] = boost::shared_ptr(new LLIMHandler()); + + mNotifyHandlers["nearbychat"] = boost::shared_ptr(new LLNearbyChatHandler(NT_NEARBYCHAT, LLSD())); +} + +//-------------------------------------------------------------------------- +bool LLNotificationManager::onNotification(const LLSD& notify) +{ + LLSysHandler* handle = NULL; + + LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID()); + + if (!notification) + return false; + + std::string notification_type = notification->getType(); + handle = dynamic_cast(mNotifyHandlers[notification_type].get()); + + if(!handle) + return false; + + if( notification_type == "alertmodal" ) + dynamic_cast(handle)->setAlertMode(true); + + handle->processNotification(notify); + + return true; +} + +//-------------------------------------------------------------------------- +void LLNotificationManager::onChat(const LLChat& msg,ENotificationType type) +{ + switch(type) + { + case NT_NEARBYCHAT: + { + LLNearbyChatHandler* handle = dynamic_cast(mNotifyHandlers["nearbychat"].get()); + + if(handle) + handle->processChat(msg); + } + break; + default: //no need to handle all enum types + break; + } +} + +//-------------------------------------------------------------------------- + + + + diff --git a/indra/newview/llnotificationmanager.h b/indra/newview/llnotificationmanager.h new file mode 100644 index 0000000000..838a00ee11 --- /dev/null +++ b/indra/newview/llnotificationmanager.h @@ -0,0 +1,79 @@ +// Notification Manager Class +/** + * @file llnotificationmanager.h + * @brief Class implements a brige between the old and a new notification sistems + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLNOTIFICATIONMANAGER_H +#define LL_LLNOTIFICATIONMANAGER_H + +#include "lluictrl.h" +#include "llnotificationhandler.h" + + +#include +#include + +#include + +namespace LLNotificationsUI { + +class LLToast; + +/** + * Responsible for registering notification handlers. + */ +class LLNotificationManager : public LLUICtrl, public LLSingleton +{ + typedef std::pair eventhandlers; +public: + LLNotificationManager(); + virtual ~LLNotificationManager(); + + //TODO: make private + // this method initialize handlers' map for different types of notifications + void init(void); + //TODO: combine processing and storage (*) + + // this method reacts on system notifications and calls an appropriate handler + bool onNotification(const LLSD& notification); + + // this method reacts on chat notifications and calls an appropriate handler + void onChat(const LLChat& msg,ENotificationType type); + +private: + //TODO (*) + std::map > mNotifyHandlers; + std::map mChatHandlers; +}; + +} +#endif + diff --git a/indra/newview/lloutputmonitorctrl.cpp b/indra/newview/lloutputmonitorctrl.cpp new file mode 100644 index 0000000000..d088c45710 --- /dev/null +++ b/indra/newview/lloutputmonitorctrl.cpp @@ -0,0 +1,207 @@ +/** + * @file lloutputmonitorctrl.cpp + * @brief LLOutputMonitorCtrl base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lloutputmonitorctrl.h" + +// library includes +#include "llui.h" + +// viewer includes +#include "llvoiceclient.h" + +// default options set in output_monitor.xml +static LLDefaultChildRegistry::Register r("output_monitor"); + +// The defaults will be initialized in the constructor. +//LLColor4 LLOutputMonitorCtrl::sColorMuted; +//LLColor4 LLOutputMonitorCtrl::sColorOverdriven; +//LLColor4 LLOutputMonitorCtrl::sColorNormal; +LLColor4 LLOutputMonitorCtrl::sColorBound; +//S32 LLOutputMonitorCtrl::sRectsNumber = 0; +//F32 LLOutputMonitorCtrl::sRectWidthRatio = 0.f; +//F32 LLOutputMonitorCtrl::sRectHeightRatio = 0.f; + +LLOutputMonitorCtrl::Params::Params() +: draw_border("draw_border"), + image_mute("image_mute"), + image_off("image_off"), + image_on("image_on"), + image_level_1("image_level_1"), + image_level_2("image_level_2"), + image_level_3("image_level_3") +{ + draw_border = true; + name = "output_monitor"; + follows.flags(FOLLOWS_LEFT|FOLLOWS_TOP); + mouse_opaque = false; +}; + +LLOutputMonitorCtrl::LLOutputMonitorCtrl(const LLOutputMonitorCtrl::Params& p) +: LLView(p), + mPower(0), + mIsMuted(true), + mIsTalking(false), + mImageMute(p.image_mute), + mImageOff(p.image_off), + mImageOn(p.image_on), + mImageLevel1(p.image_level_1), + mImageLevel2(p.image_level_2), + mImageLevel3(p.image_level_3) +{ + //static LLUIColor output_monitor_muted_color = LLUIColorTable::instance().getColor("OutputMonitorMutedColor", LLColor4::orange); + //static LLUIColor output_monitor_overdriven_color = LLUIColorTable::instance().getColor("OutputMonitorOverdrivenColor", LLColor4::red); + //static LLUIColor output_monitor_normal_color = LLUIColorTable::instance().getColor("OutputMonitorNotmalColor", LLColor4::green); + static LLUIColor output_monitor_bound_color = LLUIColorTable::instance().getColor("OutputMonitorBoundColor", LLColor4::white); + //static LLUICachedControl output_monitor_rects_number("OutputMonitorRectanglesNumber", 20); + //static LLUICachedControl output_monitor_rect_width_ratio("OutputMonitorRectangleWidthRatio", 0.5f); + //static LLUICachedControl output_monitor_rect_height_ratio("OutputMonitorRectangleHeightRatio", 0.8f); + + // IAN BUG compare to existing pattern where these are members - some will change per-widget and need to be anyway + // sent feedback to PE + + // *TODO: it looks suboptimal to load the defaults every time an output monitor is constructed. + //sColorMuted = output_monitor_muted_color; + //sColorOverdriven = output_monitor_overdriven_color; + //sColorNormal = output_monitor_normal_color; + sColorBound = output_monitor_bound_color; + //sRectsNumber = output_monitor_rects_number; + //sRectWidthRatio = output_monitor_rect_width_ratio; + //sRectHeightRatio = output_monitor_rect_height_ratio; + + mBorder = p.draw_border; +} + +LLOutputMonitorCtrl::~LLOutputMonitorCtrl() +{ +} + +void LLOutputMonitorCtrl::setPower(F32 val) +{ + mPower = llmax(0.f, llmin(1.f, val)); +} + +void LLOutputMonitorCtrl::draw() +{ + // Copied from llmediaremotectrl.cpp + // *TODO: Give the LLOutputMonitorCtrl an agent-id to monitor, then + // call directly into gVoiceClient to ask if that agent-id is muted, is + // speaking, and what power. This avoids duplicating data, which can get + // out of sync. + const F32 LEVEL_0 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL / 3.f; + const F32 LEVEL_1 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL * 2.f / 3.f; + const F32 LEVEL_2 = LLVoiceClient::OVERDRIVEN_POWER_LEVEL; + + LLPointer icon; + if (mIsMuted) + { + icon = mImageMute; + } + else if (mPower == 0.f && !mIsTalking) + { + // only show off if PTT is not engaged + icon = mImageOff; + } + else if (mPower < LEVEL_0) + { + // PTT is on, possibly with quiet background noise + icon = mImageOn; + } + else if (mPower < LEVEL_1) + { + icon = mImageLevel1; + } + else if (mPower < LEVEL_2) + { + icon = mImageLevel2; + } + else + { + // overdriven + icon = mImageLevel3; + } + + if (icon) + { + icon->draw(0, 0); + } + + // + // Fill the monitor with a bunch of small rectangles. + // The rectangles will be filled with gradient color, + // beginning with sColorNormal and ending with sColorOverdriven. + // + // *TODO: would using a (partially drawn) pixmap instead be faster? + // + const int monh = getRect().getHeight(); + const int monw = getRect().getWidth(); + //int maxrects = sRectsNumber; + //const int period = llmax(1, monw / maxrects, 0, 0); // "1" - min value for the period + //const int rectw = llmax(1, llfloor(period * sRectWidthRatio), 0, 0); // "1" - min value for the rect's width + //const int recth = llfloor(monh * sRectHeightRatio); + + //if(period == 1 && rectw == 1) //if we have so small control, then "maxrects = monitor's_width - 2*monitor_border's_width + // maxrects = monw-2; + + //const int nrects = mIsMuted ? maxrects : llfloor(mPower * maxrects); // how many rects to draw? + //const int rectbtm = (monh - recth) / 2; + //const int recttop = rectbtm + recth; + // + //LLColor4 rect_color; + // + //for (int i=1, xpos = 0; i <= nrects; i++) + //{ + // // Calculate color to use for the current rectangle. + // if (mIsMuted) + // { + // rect_color = sColorMuted; + // } + // else + // { + // F32 frac = (mPower * i/nrects) / LLVoiceClient::OVERDRIVEN_POWER_LEVEL; + // // Use overdriven color if the power exceeds overdriven level. + // if (frac > 1.0f) + // frac = 1.0f; + // rect_color = lerp(sColorNormal, sColorOverdriven, frac); + // } + + // // Draw rectangle filled with the color. + // gl_rect_2d(xpos, recttop, xpos+rectw, rectbtm, rect_color, TRUE); + // xpos += period; + //} + + // + // Draw bounding box. + // + if(mBorder) + gl_rect_2d(0, monh, monw, 0, sColorBound, FALSE); +} diff --git a/indra/newview/lloutputmonitorctrl.h b/indra/newview/lloutputmonitorctrl.h new file mode 100644 index 0000000000..98b2fe9dc6 --- /dev/null +++ b/indra/newview/lloutputmonitorctrl.h @@ -0,0 +1,103 @@ +/** + * @file lloutputmonitorctrl.h + * @brief LLOutputMonitorCtrl base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLOUTPUTMONITORCTRL_H +#define LL_LLOUTPUTMONITORCTRL_H + +#include "v4color.h" +#include "llview.h" + +class LLTextBox; +class LLUICtrlFactory; + +// +// Classes +// + +class LLOutputMonitorCtrl +: public LLView +{ +public: + struct Params : public LLInitParam::Block + { + Optional draw_border; + Mandatory image_mute, + image_off, + image_on, + image_level_1, + image_level_2, + image_level_3; + + Params(); + }; +protected: + bool mBorder; + LLOutputMonitorCtrl(const Params&); + friend class LLUICtrlFactory; + +public: + virtual ~LLOutputMonitorCtrl(); + + // llview overrides + virtual void draw(); + + void setPower(F32 val); + F32 getPower(F32 val) const { return mPower; } + + bool getIsMuted() const { return mIsMuted; } + void setIsMuted(bool val) { mIsMuted = val; } + + // For the current user, need to know the PTT state to show + // correct button image. + void setIsTalking(bool val) { mIsTalking = val; } + +private: + //static LLColor4 sColorMuted; + //static LLColor4 sColorNormal; + //static LLColor4 sColorOverdriven; + static LLColor4 sColorBound; + //static S32 sRectsNumber; + //static F32 sRectWidthRatio; + //static F32 sRectHeightRatio; + + F32 mPower; + bool mIsMuted; + bool mIsTalking; + LLPointer mImageMute; + LLPointer mImageOff; + LLPointer mImageOn; + LLPointer mImageLevel1; + LLPointer mImageLevel2; + LLPointer mImageLevel3; +}; + +#endif diff --git a/indra/newview/lloverlaybar.cpp b/indra/newview/lloverlaybar.cpp index b16f56d0d8..ea24638b6d 100644 --- a/indra/newview/lloverlaybar.cpp +++ b/indra/newview/lloverlaybar.cpp @@ -37,20 +37,18 @@ #include "lloverlaybar.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llrender.h" #include "llagent.h" #include "llbutton.h" -#include "llchatbar.h" #include "llfocusmgr.h" #include "llimview.h" #include "llmediaremotectrl.h" -#include "llpanelaudiovolume.h" #include "llparcel.h" #include "lltextbox.h" #include "llui.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerjoystick.h" #include "llviewermedia.h" #include "llviewermenu.h" // handle_reset_view() @@ -60,9 +58,9 @@ #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "llvoiceclient.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvoiceremotectrl.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "llselectmgr.h" // @@ -89,16 +87,10 @@ void* LLOverlayBar::createMediaRemote(void* userdata) void* LLOverlayBar::createVoiceRemote(void* userdata) { LLOverlayBar *self = (LLOverlayBar*)userdata; - self->mVoiceRemote = new LLVoiceRemoteCtrl(std::string("voice_remote")); + self->mVoiceRemote = new LLVoiceRemoteCtrl(); return self->mVoiceRemote; } -void* LLOverlayBar::createChatBar(void* userdata) -{ - gChatBar = new LLChatBar(); - return gChatBar; -} - LLOverlayBar::LLOverlayBar() : LLPanel(), mMediaRemote(NULL), @@ -110,23 +102,23 @@ LLOverlayBar::LLOverlayBar() mBuilt = false; - LLCallbackMap::map_t factory_map; - factory_map["media_remote"] = LLCallbackMap(LLOverlayBar::createMediaRemote, this); - factory_map["voice_remote"] = LLCallbackMap(LLOverlayBar::createVoiceRemote, this); - factory_map["chat_bar"] = LLCallbackMap(LLOverlayBar::createChatBar, this); + mFactoryMap["media_remote"] = LLCallbackMap(LLOverlayBar::createMediaRemote, this); + mFactoryMap["voice_remote"] = LLCallbackMap(LLOverlayBar::createVoiceRemote, this); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_overlaybar.xml", &factory_map); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_overlaybar.xml"); } BOOL LLOverlayBar::postBuild() { - childSetAction("IM Received",onClickIMReceived,this); childSetAction("Set Not Busy",onClickSetNotBusy,this); childSetAction("Mouselook",onClickMouselook,this); childSetAction("Stand Up",onClickStandUp,this); childSetAction("Flycam",onClickFlycam,this); childSetVisible("chat_bar", gSavedSettings.getBOOL("ChatVisible")); + mVoiceRemote->expandOrCollapse(); + mMediaRemote->expandOrCollapse(); + setFocusRoot(TRUE); mBuilt = true; @@ -168,8 +160,9 @@ void LLOverlayBar::layoutButtons() // calculate button widths const S32 MAX_BUTTON_WIDTH = 150; + const S32 STATUS_BAR_PAD = 10; S32 segment_width = llclamp(lltrunc((F32)(bar_width) / (F32)button_list.size()), 0, MAX_BUTTON_WIDTH); - S32 btn_width = segment_width - gSavedSettings.getS32("StatusBarPad"); + S32 btn_width = segment_width - STATUS_BAR_PAD; // Evenly space all buttons, starting from left S32 left = 0; @@ -238,7 +231,7 @@ void LLOverlayBar::refresh() BOOL sitting = FALSE; if (gAgent.getAvatarObject()) { - sitting = gAgent.getAvatarObject()->mIsSitting; + sitting = gAgent.getAvatarObject()->isSitting(); } button = getChild("Stand Up"); @@ -282,13 +275,6 @@ void LLOverlayBar::refresh() // Static functions //----------------------------------------------------------------------- -// static -void LLOverlayBar::onClickIMReceived(void*) -{ - gIMMgr->setFloaterOpen(TRUE); -} - - // static void LLOverlayBar::onClickSetNotBusy(void*) { @@ -329,7 +315,7 @@ void LLOverlayBar::mediaStop(void*) { if (!gOverlayBar) { - return; + // return; } LLViewerParcelMedia::stop(); } @@ -338,15 +324,15 @@ void LLOverlayBar::toggleMediaPlay(void*) { if (!gOverlayBar) { - return; + // return; } - if (LLViewerMedia::isMediaPaused()) + if (LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PAUSED) { LLViewerParcelMedia::start(); } - else if(LLViewerMedia::isMediaPlaying()) + else if(LLViewerParcelMedia::getStatus() == LLViewerMediaImpl::MEDIA_PLAYING) { LLViewerParcelMedia::pause(); } diff --git a/indra/newview/lloverlaybar.h b/indra/newview/lloverlaybar.h index 852d033a10..ffdbd96f60 100644 --- a/indra/newview/lloverlaybar.h +++ b/indra/newview/lloverlaybar.h @@ -67,7 +67,6 @@ public: // helpers for returning desired state BOOL musicPlaying() { return mMusicState == PLAYING; } - static void onClickIMReceived(void* data); static void onClickSetNotBusy(void* data); static void onClickMouselook(void* data); static void onClickStandUp(void* data); @@ -86,7 +85,6 @@ public: protected: static void* createMediaRemote(void* userdata); static void* createVoiceRemote(void* userdata); - static void* createChatBar(void* userdata); void enableMediaButtons(); diff --git a/indra/newview/llpanelappearancetab.h b/indra/newview/llpanelappearancetab.h new file mode 100644 index 0000000000..8a9ba66ec0 --- /dev/null +++ b/indra/newview/llpanelappearancetab.h @@ -0,0 +1,65 @@ +/** + * @file llpanelplacestab.h + * @brief Tabs interface for Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELAPPEARANCETAB_H +#define LL_LLPANELAPPEARANCETAB_H + +#include "llpanel.h" + +#include "llpanelappearance.h" + +class LLPanelAppearanceTab : public LLPanel +{ +public: + LLPanelAppearanceTab(LLPanelAppearance *parent) : + LLPanel(), + mParent(parent) + {} + virtual ~LLPanelAppearanceTab() {} + + virtual void onSearchEdit(const std::string& string) = 0; + virtual void updateVerbs() = 0; // Updates buttons at the bottom of Appearance panel + virtual void onWear() = 0; + virtual void onEdit() = 0; + virtual void onNew() = 0; + + bool isTabVisible(); // Check if parent TabContainer is visible. + + void setPanelAppearanceButtons(LLPanelAppearance* panel); + + +protected: + LLButton* mWearBtn; + LLButton* mEditBtn; + LLPanelAppearance* mParent; +}; + +#endif //LL_LLPANELAPPEARANCETAB_H diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp index 9d5a4ad01c..6e94b087a6 100644 --- a/indra/newview/llpanelavatar.cpp +++ b/indra/newview/llpanelavatar.cpp @@ -31,61 +31,19 @@ */ #include "llviewerprecompiledheaders.h" - #include "llpanelavatar.h" -#include "llclassifiedflags.h" -#include "llfontgl.h" -#include "llcachename.h" - -#include "llavatarconstants.h" -#include "lluiconstants.h" -#include "lltextbox.h" -#include "llviewertexteditor.h" -#include "lltexturectrl.h" #include "llagent.h" -#include "llviewerwindow.h" -#include "llbutton.h" +#include "llavataractions.h" +#include "llavatarconstants.h" #include "llcallingcard.h" -#include "llcheckboxctrl.h" -#include "llfloater.h" - -#include "llfloaterfriends.h" -#include "llfloatergroupinfo.h" -#include "llfloaterworldmap.h" -#include "llfloatermute.h" -#include "llfloateravatarinfo.h" -#include "lliconctrl.h" -#include "llinventoryview.h" -#include "lllineeditor.h" -#include "llnameeditor.h" -#include "llmutelist.h" -#include "llpanelclassified.h" -#include "llpanelpick.h" -#include "llscrolllistctrl.h" -#include "llstatusbar.h" -#include "lltabcontainer.h" -#include "lltabcontainervertical.h" +#include "llcombobox.h" #include "llimview.h" +#include "lltexteditor.h" +#include "lltexturectrl.h" #include "lltooldraganddrop.h" -#include "lluiconstants.h" -#include "llvoavatar.h" -#include "llviewercontrol.h" -#include "llviewermenu.h" // *FIX: for is_agent_friend() -#include "llviewergenericmessage.h" // send_generic_message -#include "llviewerobjectlist.h" -#include "llviewerregion.h" +#include "llscrollcontainer.h" #include "llweb.h" -#include "llinventorymodel.h" -#include "roles_constants.h" -#include "lluictrlfactory.h" - -// Statics -std::list LLPanelAvatar::sAllPanels; -BOOL LLPanelAvatar::sAllowFirstLife = FALSE; - -extern void handle_lure(const LLUUID& invitee); -extern void handle_pay_by_id(const LLUUID& payee); //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLDropTarget @@ -98,7 +56,18 @@ extern void handle_pay_by_id(const LLUUID& payee); class LLDropTarget : public LLView { public: - LLDropTarget(const std::string& name, const LLRect& rect, const LLUUID& agent_id); + struct Params : public LLInitParam::Block + { + Optional agent_id; + Params() + : agent_id("agent_id") + { + mouse_opaque(false); + follows.flags(FOLLOWS_ALL); + } + }; + + LLDropTarget(const Params&); ~LLDropTarget(); void doDrop(EDragAndDropType cargo_type, void* cargo_data); @@ -115,17 +84,13 @@ protected: LLUUID mAgentID; }; - -LLDropTarget::LLDropTarget(const std::string& name, const LLRect& rect, - const LLUUID& agent_id) : - LLView(name, rect, NOT_MOUSE_OPAQUE, FOLLOWS_ALL), - mAgentID(agent_id) -{ -} +LLDropTarget::LLDropTarget(const LLDropTarget::Params& p) +: LLView(p), + mAgentID(p.agent_id) +{} LLDropTarget::~LLDropTarget() -{ -} +{} void LLDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { @@ -149,2156 +114,580 @@ BOOL LLDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, return FALSE; } +static LLDefaultChildRegistry::Register r("drop_target"); -//----------------------------------------------------------------------------- -// LLPanelAvatarTab() -//----------------------------------------------------------------------------- -LLPanelAvatarTab::LLPanelAvatarTab(const std::string& name, const LLRect &rect, - LLPanelAvatar* panel_avatar) -: LLPanel(name, rect), - mPanelAvatar(panel_avatar), - mDataRequested(false) -{ } - -// virtual -void LLPanelAvatarTab::draw() -{ - refresh(); - - LLPanel::draw(); -} - -void LLPanelAvatarTab::sendAvatarProfileRequestIfNeeded(const std::string& method) -{ - if (!mDataRequested) - { - std::vector strings; - strings.push_back( mPanelAvatar->getAvatarID().asString() ); - send_generic_message(method, strings); - mDataRequested = true; - } -} - -//----------------------------------------------------------------------------- -// LLPanelAvatarSecondLife() -//----------------------------------------------------------------------------- -LLPanelAvatarSecondLife::LLPanelAvatarSecondLife(const std::string& name, - const LLRect &rect, - LLPanelAvatar* panel_avatar ) -: LLPanelAvatarTab(name, rect, panel_avatar), - mPartnerID() -{ -} - -void LLPanelAvatarSecondLife::refresh() -{ - updatePartnerName(); -} - -void LLPanelAvatarSecondLife::updatePartnerName() -{ - if (mPartnerID.notNull()) - { - std::string first, last; - BOOL found = gCacheName->getName(mPartnerID, first, last); - if (found) - { - childSetTextArg("partner_edit", "[FIRST]", first); - childSetTextArg("partner_edit", "[LAST]", last); - } - childSetEnabled("partner_info", TRUE); - } -} - -//----------------------------------------------------------------------------- -// clearControls() -// Empty the data out of the controls, since we have to wait for new -// data off the network. -//----------------------------------------------------------------------------- -void LLPanelAvatarSecondLife::clearControls() -{ - LLTextureCtrl* image_ctrl = getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(LLUUID::null); - } - childSetValue("about", ""); - childSetValue("born", ""); - childSetValue("acct", ""); - - childSetTextArg("partner_edit", "[FIRST]", LLStringUtil::null); - childSetTextArg("partner_edit", "[LAST]", LLStringUtil::null); - - mPartnerID = LLUUID::null; - - LLScrollListCtrl* group_list = getChild("groups"); - if(group_list) - { - group_list->deleteAllItems(); - } - LLScrollListCtrl* ratings_list = getChild("ratings"); - if(ratings_list) - { - ratings_list->deleteAllItems(); - } - -} - - -//----------------------------------------------------------------------------- -// enableControls() -//----------------------------------------------------------------------------- -void LLPanelAvatarSecondLife::enableControls(BOOL self) -{ - childSetEnabled("img", self); - childSetEnabled("about", self); - childSetVisible("allow_publish", self); - childSetEnabled("allow_publish", self); - childSetVisible("?", self); - childSetEnabled("?", self); -} - - -// static -void LLPanelAvatarSecondLife::onClickImage(void *) -{ } - -// static -void LLPanelAvatarSecondLife::onDoubleClickGroup(void* data) -{ - LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*)data; - - - LLScrollListCtrl* group_list = self->getChild("groups"); - if(group_list) - { - LLScrollListItem* item = group_list->getFirstSelected(); - - if(item && item->getUUID().notNull()) - { - llinfos << "Show group info " << item->getUUID() << llendl; - - LLFloaterGroupInfo::showFromUUID(item->getUUID()); - } - } -} - -// static -void LLPanelAvatarSecondLife::onClickPublishHelp(void *) -{ - LLNotifications::instance().add("ClickPublishHelpAvatar"); -} - -// static -void LLPanelAvatarSecondLife::onClickPartnerHelp(void *) -{ - LLNotifications::instance().add("ClickPartnerHelpAvatar", LLSD(), LLSD(), onClickPartnerHelpLoadURL); -} - -// static -bool LLPanelAvatarSecondLife::onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (option == 0) - { - LLWeb::loadURL("http://secondlife.com/partner"); - } - return false; -} - -// static -void LLPanelAvatarSecondLife::onClickPartnerInfo(void *data) -{ - LLPanelAvatarSecondLife* self = (LLPanelAvatarSecondLife*) data; - if (self->mPartnerID.notNull()) - { - LLFloaterAvatarInfo::showFromProfile(self->mPartnerID, - self->getScreenRect()); - } -} - -//----------------------------------------------------------------------------- -// LLPanelAvatarFirstLife() -//----------------------------------------------------------------------------- -LLPanelAvatarFirstLife::LLPanelAvatarFirstLife(const std::string& name, - const LLRect &rect, - LLPanelAvatar* panel_avatar ) -: LLPanelAvatarTab(name, rect, panel_avatar) -{ -} - -void LLPanelAvatarFirstLife::enableControls(BOOL self) -{ - childSetEnabled("img", self); - childSetEnabled("about", self); -} - -//----------------------------------------------------------------------------- -// postBuild -//----------------------------------------------------------------------------- - -BOOL LLPanelAvatarSecondLife::postBuild(void) -{ - childSetEnabled("born", FALSE); - childSetEnabled("partner_edit", FALSE); - childSetAction("partner_help",onClickPartnerHelp,this); - childSetAction("partner_info", onClickPartnerInfo, this); - childSetEnabled("partner_info", mPartnerID.notNull()); - - childSetAction("?",onClickPublishHelp,this); - BOOL own_avatar = (getPanelAvatar()->getAvatarID() == gAgent.getID() ); - enableControls(own_avatar); - - childSetVisible("About:",LLPanelAvatar::sAllowFirstLife); - childSetVisible("(500 chars)",LLPanelAvatar::sAllowFirstLife); - childSetVisible("about",LLPanelAvatar::sAllowFirstLife); - - childSetVisible("allow_publish",LLPanelAvatar::sAllowFirstLife); - childSetVisible("?",LLPanelAvatar::sAllowFirstLife); - - childSetVisible("online_yes",FALSE); - - // These are cruft but may still exist in some xml files - // TODO: remove the following 2 lines once translators grab these changes - childSetVisible("online_unknown",FALSE); - childSetVisible("online_no",FALSE); - - childSetAction("Find on Map", LLPanelAvatar::onClickTrack, getPanelAvatar()); - childSetAction("Instant Message...", LLPanelAvatar::onClickIM, getPanelAvatar()); - - childSetAction("Add Friend...", LLPanelAvatar::onClickAddFriend, getPanelAvatar()); - childSetAction("Pay...", LLPanelAvatar::onClickPay, getPanelAvatar()); - childSetAction("Mute", LLPanelAvatar::onClickMute, getPanelAvatar() ); - - childSetAction("Offer Teleport...", LLPanelAvatar::onClickOfferTeleport, - getPanelAvatar() ); - - childSetDoubleClickCallback("groups", onDoubleClickGroup, this ); - - getChild("img")->setFallbackImageName("default_profile_picture.j2c"); - - return TRUE; -} - -BOOL LLPanelAvatarFirstLife::postBuild(void) -{ - BOOL own_avatar = (getPanelAvatar()->getAvatarID() == gAgent.getID() ); - enableControls(own_avatar); - - getChild("img")->setFallbackImageName("default_profile_picture.j2c"); - - return TRUE; -} - -BOOL LLPanelAvatarNotes::postBuild(void) -{ - childSetCommitCallback("notes edit",onCommitNotes,this); - - LLTextEditor* te = getChild("notes edit"); - if(te) te->setCommitOnFocusLost(TRUE); - return TRUE; -} - -BOOL LLPanelAvatarWeb::postBuild(void) -{ - childSetKeystrokeCallback("url_edit", onURLKeystroke, this); - childSetCommitCallback("load", onCommitLoad, this); - - childSetAction("web_profile_help",onClickWebProfileHelp,this); - - childSetCommitCallback("url_edit",onCommitURL,this); - - childSetControlName("auto_load","AutoLoadWebProfiles"); - - mWebBrowser = getChild("profile_html"); - - // links open in internally - mWebBrowser->setOpenInExternalBrowser( false ); - - // observe browser events - mWebBrowser->addObserver( this ); - - return TRUE; -} - -BOOL LLPanelAvatarClassified::postBuild(void) -{ - childSetAction("New...",onClickNew,NULL); - childSetAction("Delete...",onClickDelete,NULL); - return TRUE; -} - -BOOL LLPanelAvatarPicks::postBuild(void) -{ - childSetAction("New...",onClickNew,NULL); - childSetAction("Delete...",onClickDelete,NULL); - return TRUE; -} - -BOOL LLPanelAvatarAdvanced::postBuild() -{ - for(size_t ii = 0; ii < LL_ARRAY_SIZE(mWantToCheck); ++ii) - mWantToCheck[ii] = NULL; - for(size_t ii = 0; ii < LL_ARRAY_SIZE(mSkillsCheck); ++ii) - mSkillsCheck[ii] = NULL; - mWantToCount = (8>LL_ARRAY_SIZE(mWantToCheck))?LL_ARRAY_SIZE(mWantToCheck):8; - for(S32 tt=0; tt < mWantToCount; ++tt) - { - std::string ctlname = llformat("chk%d", tt); - mWantToCheck[tt] = getChild(ctlname); - } - mSkillsCount = (6>LL_ARRAY_SIZE(mSkillsCheck))?LL_ARRAY_SIZE(mSkillsCheck):6; - - for(S32 tt=0; tt < mSkillsCount; ++tt) - { - //Find the Skills checkboxes and save off thier controls - std::string ctlname = llformat("schk%d",tt); - mSkillsCheck[tt] = getChild(ctlname); - } - - mWantToEdit = getChild("want_to_edit"); - mSkillsEdit = getChild("skills_edit"); - childSetVisible("skills_edit",LLPanelAvatar::sAllowFirstLife); - childSetVisible("want_to_edit",LLPanelAvatar::sAllowFirstLife); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLPanelAvatarWeb -//----------------------------------------------------------------------------- -LLPanelAvatarWeb::LLPanelAvatarWeb(const std::string& name, const LLRect& rect, - LLPanelAvatar* panel_avatar) -: LLPanelAvatarTab(name, rect, panel_avatar), - mWebBrowser(NULL) -{ -} - -LLPanelAvatarWeb::~LLPanelAvatarWeb() -{ - // stop observing browser events - if ( mWebBrowser ) - { - mWebBrowser->remObserver( this ); - }; -} - -void LLPanelAvatarWeb::refresh() -{ - if (mNavigateTo != "") - { - llinfos << "Loading " << mNavigateTo << llendl; - mWebBrowser->navigateTo( mNavigateTo ); - mNavigateTo = ""; - } -} - - -void LLPanelAvatarWeb::enableControls(BOOL self) -{ - childSetEnabled("url_edit",self); -} - -void LLPanelAvatarWeb::setWebURL(std::string url) -{ - bool changed_url = (mHome != url); - - mHome = url; - bool have_url = !mHome.empty(); - - childSetText("url_edit", mHome); - childSetEnabled("load", mHome.length() > 0); - - if (have_url - && gSavedSettings.getBOOL("AutoLoadWebProfiles")) - { - if (changed_url) - { - load(mHome); - } - } - else - { - childSetVisible("profile_html",false); - childSetVisible("status_text", false); - } -} - -// static -void LLPanelAvatarWeb::onCommitURL(LLUICtrl* ctrl, void* data) -{ - LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data; - - if (!self) return; - - self->load( self->childGetText("url_edit") ); -} - -// static -void LLPanelAvatarWeb::onClickWebProfileHelp(void *) -{ - LLNotifications::instance().add("ClickWebProfileHelpAvatar"); -} - -void LLPanelAvatarWeb::load(std::string url) -{ - bool have_url = (!url.empty()); - - - childSetVisible("profile_html", have_url); - childSetVisible("status_text", have_url); - childSetText("status_text", LLStringUtil::null); - - if (have_url) - { - mNavigateTo = url; - } -} - -//static -void LLPanelAvatarWeb::onURLKeystroke(LLLineEditor* editor, void* data) -{ - LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data; - if (!self) return; - LLSD::String url = editor->getText(); - self->childSetEnabled("load", url.length() > 0); - return; -} - -// static -void LLPanelAvatarWeb::onCommitLoad(LLUICtrl* ctrl, void* data) -{ - LLPanelAvatarWeb* self = (LLPanelAvatarWeb*)data; - - if (!self) return; - - LLSD::String valstr = ctrl->getValue().asString(); - LLSD::String urlstr = self->childGetText("url_edit"); - if (valstr == "") // load url string into browser panel - { - self->load(urlstr); - } - else if (valstr == "open") // open in user's external browser - { - if (!urlstr.empty()) - { - LLWeb::loadURLExternal(urlstr); - } - } - else if (valstr == "home") // reload profile owner's home page - { - if (!self->mHome.empty()) - { - self->load(self->mHome); - } - } -} - -void LLPanelAvatarWeb::onStatusTextChange( const EventType& eventIn ) -{ - childSetText("status_text", eventIn.getStringValue() ); -} - -void LLPanelAvatarWeb::onLocationChange( const EventType& eventIn ) -{ - childSetText("url_edit", eventIn.getStringValue() ); -} - - -//----------------------------------------------------------------------------- -// LLPanelAvatarAdvanced -//----------------------------------------------------------------------------- -LLPanelAvatarAdvanced::LLPanelAvatarAdvanced(const std::string& name, - const LLRect& rect, - LLPanelAvatar* panel_avatar) -: LLPanelAvatarTab(name, rect, panel_avatar), - mWantToCount(0), - mSkillsCount(0), - mWantToEdit( NULL ), - mSkillsEdit( NULL ) -{ -} - -void LLPanelAvatarAdvanced::enableControls(BOOL self) -{ - S32 t; - for(t=0;tsetEnabled(self); - } - for(t=0;tsetEnabled(self); - } - - if (mWantToEdit) mWantToEdit->setEnabled(self); - if (mSkillsEdit) mSkillsEdit->setEnabled(self); - childSetEnabled("languages_edit",self); -} - -void LLPanelAvatarAdvanced::setWantSkills(U32 want_to_mask, const std::string& want_to_text, - U32 skills_mask, const std::string& skills_text, - const std::string& languages_text) -{ - for(int id =0;idset( want_to_mask & 1<set( skills_mask & 1<setText( want_to_text ); - mSkillsEdit->setText( skills_text ); - } - - childSetText("languages_edit",languages_text); -} - -void LLPanelAvatarAdvanced::getWantSkills(U32* want_to_mask, std::string& want_to_text, - U32* skills_mask, std::string& skills_text, - std::string& languages_text) -{ - if (want_to_mask) - { - *want_to_mask = 0; - for(int t=0;tget()) - *want_to_mask |= 1<get()) - *skills_mask |= 1<getText(); - } - - if (mSkillsEdit) - { - skills_text = mSkillsEdit->getText(); - } - - languages_text = childGetText("languages_edit"); -} +static LLRegisterPanelClassWrapper t_panel_profile("panel_profile"); +static LLRegisterPanelClassWrapper t_panel_me_profile("panel_me_profile"); +static LLRegisterPanelClassWrapper t_panel_notes("panel_notes"); //----------------------------------------------------------------------------- // LLPanelAvatarNotes() //----------------------------------------------------------------------------- -LLPanelAvatarNotes::LLPanelAvatarNotes(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar) -: LLPanelAvatarTab(name, rect, panel_avatar) +LLPanelAvatarNotes::LLPanelAvatarNotes() +: LLPanelProfileTab() { + } -void LLPanelAvatarNotes::refresh() +void LLPanelAvatarNotes::updateData() { - sendAvatarProfileRequestIfNeeded("avatarnotesrequest"); + LLAvatarPropertiesProcessor::getInstance()->sendDataRequest(getAvatarId(),APT_NOTES); } -void LLPanelAvatarNotes::clearControls() +BOOL LLPanelAvatarNotes::postBuild() { - childSetText("notes edit", getString("Loading")); - childSetEnabled("notes edit", false); -} + childSetCommitCallback("status_check", boost::bind(&LLPanelAvatarNotes::onCommitRights, this), NULL); + childSetCommitCallback("map_check", boost::bind(&LLPanelAvatarNotes::onCommitRights, this), NULL); + childSetCommitCallback("objects_check", boost::bind(&LLPanelAvatarNotes::onCommitRights, this), NULL); -// static -void LLPanelAvatarNotes::onCommitNotes(LLUICtrl*, void* userdata) -{ - LLPanelAvatarNotes* self = (LLPanelAvatarNotes*)userdata; + childSetCommitCallback("add_friend", boost::bind(&LLPanelAvatarNotes::onAddFriendButtonClick, this),NULL); + childSetCommitCallback("im", boost::bind(&LLPanelAvatarNotes::onIMButtonClick, this), NULL); + childSetCommitCallback("call", boost::bind(&LLPanelAvatarNotes::onCallButtonClick, this), NULL); + childSetCommitCallback("teleport", boost::bind(&LLPanelAvatarNotes::onTeleportButtonClick, this), NULL); + childSetCommitCallback("share", boost::bind(&LLPanelAvatarNotes::onShareButtonClick, this), NULL); - self->getPanelAvatar()->sendAvatarNotesUpdate(); -} + LLTextEditor* te = getChild("notes_edit"); + te->setCommitCallback(boost::bind(&LLPanelAvatarNotes::onCommitNotes,this)); + te->setCommitOnFocusLost(TRUE); + resetControls(); + resetData(); -//----------------------------------------------------------------------------- -// LLPanelAvatarClassified() -//----------------------------------------------------------------------------- -LLPanelAvatarClassified::LLPanelAvatarClassified(const std::string& name, const LLRect& rect, - LLPanelAvatar* panel_avatar) -: LLPanelAvatarTab(name, rect, panel_avatar) -{ -} - - -void LLPanelAvatarClassified::refresh() -{ - BOOL self = (gAgent.getID() == getPanelAvatar()->getAvatarID()); - - LLTabContainer* tabs = getChild("classified tab"); - - S32 tab_count = tabs ? tabs->getTabCount() : 0; - - bool allow_new = tab_count < MAX_CLASSIFIEDS; - bool allow_delete = (tab_count > 0); - bool show_help = (tab_count == 0); - - // *HACK: Don't allow making new classifieds from inside the directory. - // The logic for save/don't save when closing is too hairy, and the - // directory is conceptually read-only. JC - bool in_directory = false; - LLView* view = this; - while (view) - { - if (view->getName() == "directory") - { - in_directory = true; - break; - } - view = view->getParent(); - } - childSetEnabled("New...", self && !in_directory && allow_new); - childSetVisible("New...", !in_directory); - childSetEnabled("Delete...", self && !in_directory && allow_delete); - childSetVisible("Delete...", !in_directory); - childSetVisible("classified tab",!show_help); - - sendAvatarProfileRequestIfNeeded("avatarclassifiedsrequest"); -} - - -BOOL LLPanelAvatarClassified::canClose() -{ - LLTabContainer* tabs = getChild("classified tab"); - for (S32 i = 0; i < tabs->getTabCount(); i++) - { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getPanelByIndex(i); - if (!panel->canClose()) - { - return FALSE; - } - } return TRUE; } -BOOL LLPanelAvatarClassified::titleIsValid() +void LLPanelAvatarNotes::onOpen(const LLSD& key) { - LLTabContainer* tabs = getChild("classified tab"); - if ( tabs ) + LLPanelProfileTab::onOpen(key); + + fillRightsData(); + + //Disable "Add Friend" button for friends. + childSetEnabled("add_friend", !LLAvatarActions::isFriend(getAvatarId())); +} + +void LLPanelAvatarNotes::fillRightsData() +{ + const LLRelationship* relation = LLAvatarTracker::instance().getBuddyInfo(getAvatarId()); + // If true - we are viewing friend's profile, enable check boxes and set values. + if(relation) { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getCurrentPanel(); - if ( panel ) + S32 rights = relation->getRightsGrantedTo(); + + childSetValue("status_check",LLRelationship::GRANT_ONLINE_STATUS & rights ? TRUE : FALSE); + childSetValue("map_check",LLRelationship::GRANT_MAP_LOCATION & rights ? TRUE : FALSE); + childSetValue("objects_check",LLRelationship::GRANT_MODIFY_OBJECTS & rights ? TRUE : FALSE); + + childSetEnabled("status_check",TRUE); + childSetEnabled("map_check",TRUE); + childSetEnabled("objects_check",TRUE); + } +} + +void LLPanelAvatarNotes::onCommitNotes() +{ + std::string notes = childGetValue("notes_edit").asString(); + LLAvatarPropertiesProcessor::getInstance()-> sendNotes(getAvatarId(),notes); +} + +void LLPanelAvatarNotes::onCommitRights() +{ + S32 rights = 0; + + if(childGetValue("status_check").asBoolean()) + rights |= LLRelationship::GRANT_ONLINE_STATUS; + if(childGetValue("map_check").asBoolean()) + rights |= LLRelationship::GRANT_MAP_LOCATION; + if(childGetValue("objects_check").asBoolean()) + rights |= LLRelationship::GRANT_MODIFY_OBJECTS; + + LLAvatarPropertiesProcessor::getInstance()->sendFriendRights(getAvatarId(),rights); +} + +void LLPanelAvatarNotes::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_NOTES == type) + { + LLAvatarNotes* avatar_notes = static_cast(data); + if(avatar_notes && getAvatarId() == avatar_notes->target_id) { - if ( ! panel->titleIsValid() ) - { - return FALSE; - }; + childSetValue("notes_edit",avatar_notes->notes); + childSetEnabled("notes edit", true); + + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } + } +} + +void LLPanelAvatarNotes::resetData() +{ + childSetValue("notes_edit",LLStringUtil::null); + // Default value is TRUE + childSetValue("status_check", TRUE); +} + +void LLPanelAvatarNotes::resetControls() +{ + //Disable "Add Friend" button for friends. + childSetEnabled("add_friend", TRUE); + + childSetEnabled("status_check",FALSE); + childSetEnabled("map_check",FALSE); + childSetEnabled("objects_check",FALSE); +} + +void LLPanelAvatarNotes::onAddFriendButtonClick() +{ + LLAvatarActions::requestFriendshipDialog(getAvatarId()); +} + +void LLPanelAvatarNotes::onIMButtonClick() +{ + LLAvatarActions::startIM(getAvatarId()); +} + +void LLPanelAvatarNotes::onTeleportButtonClick() +{ + LLAvatarActions::offerTeleport(getAvatarId()); +} + +void LLPanelAvatarNotes::onCallButtonClick() +{ + //*TODO not implemented. +} + +void LLPanelAvatarNotes::onShareButtonClick() +{ + //*TODO not implemented. +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelProfileTab::LLPanelProfileTab() +: LLPanel() +, mAvatarId(LLUUID::null) +{ +} + +LLPanelProfileTab::~LLPanelProfileTab() +{ + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } +} + +void LLPanelProfileTab::setAvatarId(const LLUUID& id) +{ + if(id.notNull()) + { + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(mAvatarId,this); + } + mAvatarId = id; + LLAvatarPropertiesProcessor::getInstance()->addObserver(getAvatarId(),this); + } +} + +void LLPanelProfileTab::onOpen(const LLSD& key) +{ + // Don't reset panel if we are opening it for same avatar. + if(getAvatarId() != key.asUUID()) + { + resetControls(); + resetData(); + + scrollToTop(); + } + + // Update data even if we are viewing same avatar profile as some data might been changed. + setAvatarId(key.asUUID()); + updateData(); +} + +void LLPanelProfileTab::scrollToTop() +{ + LLScrollContainer* scrollContainer = getChild("profile_scroll"); + scrollContainer->goToTop(); +} + +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelAvatarProfile::LLPanelAvatarProfile() +: LLPanelProfileTab() +{ +} + +BOOL LLPanelAvatarProfile::postBuild() +{ + childSetActionTextbox("homepage_edit", boost::bind(&LLPanelAvatarProfile::onHomepageTextboxClicked, this)); + childSetCommitCallback("add_friend",(boost::bind(&LLPanelAvatarProfile::onAddFriendButtonClick,this)),NULL); + childSetCommitCallback("im",(boost::bind(&LLPanelAvatarProfile::onIMButtonClick,this)),NULL); + childSetCommitCallback("call",(boost::bind(&LLPanelAvatarProfile::onCallButtonClick,this)),NULL); + childSetCommitCallback("teleport",(boost::bind(&LLPanelAvatarProfile::onTeleportButtonClick,this)),NULL); + childSetCommitCallback("share",(boost::bind(&LLPanelAvatarProfile::onShareButtonClick,this)),NULL); + + LLTextureCtrl* pic = getChild("2nd_life_pic"); + pic->setFallbackImageName("default_land_picture.j2c"); + + pic = getChild("real_world_pic"); + pic->setFallbackImageName("default_land_picture.j2c"); + + resetControls(); + resetData(); + + return TRUE; +} + +void LLPanelAvatarProfile::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); + + //Disable "Add Friend" button for friends. + childSetEnabled("add_friend", !LLAvatarActions::isFriend(getAvatarId())); +} + +void LLPanelAvatarProfile::updateData() +{ + if (getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->sendDataRequest(getAvatarId(),APT_PROPERTIES); + LLAvatarPropertiesProcessor::getInstance()->sendDataRequest(getAvatarId(),APT_GROUPS); + } +} + +void LLPanelAvatarProfile::resetControls() +{ + childSetVisible("status_panel", true); + childSetVisible("profile_buttons_panel", true); + childSetVisible("title_groups_text", true); + childSetVisible("sl_groups", true); + childSetEnabled("add_friend", true); + + childSetVisible("status_me_panel", false); + childSetVisible("profile_me_buttons_panel", false); + childSetVisible("account_actions_panel", false); + childSetVisible("partner_edit_link", false); +} + +void LLPanelAvatarProfile::resetData() +{ + childSetValue("2nd_life_pic",LLUUID::null); + childSetValue("real_world_pic",LLUUID::null); + childSetValue("online_status",LLStringUtil::null); + childSetValue("status_message",LLStringUtil::null); + childSetValue("sl_description_edit",LLStringUtil::null); + childSetValue("fl_description_edit",LLStringUtil::null); + childSetValue("sl_groups",LLStringUtil::null); + childSetValue("homepage_edit",LLStringUtil::null); + childSetValue("register_date",LLStringUtil::null); + childSetValue("acc_status_text",LLStringUtil::null); + childSetTextArg("partner_text", "[FIRST]", LLStringUtil::null); + childSetTextArg("partner_text", "[LAST]", LLStringUtil::null); +} + +void LLPanelAvatarProfile::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_PROPERTIES == type) + { + const LLAvatarData* avatar_data = static_cast(data); + if(avatar_data && getAvatarId() == avatar_data->avatar_id) + { + processProfileProperties(avatar_data); + } + } + else if(APT_GROUPS == type) + { + LLAvatarGroups* avatar_groups = static_cast(data); + if(avatar_groups && getAvatarId() == avatar_groups->avatar_id) + { + processGroupProperties(avatar_groups); + } + } +} + +void LLPanelAvatarProfile::processProfileProperties(const LLAvatarData* avatar_data) +{ + fillCommonData(avatar_data); + + fillPartnerData(avatar_data); + + fillOnlineStatus(avatar_data); + + fillAccountStatus(avatar_data); +} + +void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_groups) +{ + std::string groups; + LLAvatarGroups::group_list_t::const_iterator it = avatar_groups->group_list.begin(); + const LLAvatarGroups::group_list_t::const_iterator it_end = avatar_groups->group_list.end(); + + if(it_end != it) + { + groups = (*it).group_name; + ++it; + } + for(; it_end != it; ++it) + { + LLAvatarGroups::LLGroupData group_data = *it; + groups += ", "; + groups += group_data.group_name; + } + childSetValue("sl_groups",groups); +} + +void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data) +{ + childSetValue("register_date", avatar_data->born_on); + childSetValue("sl_description_edit", avatar_data->about_text); + childSetValue("fl_description_edit",avatar_data->fl_about_text); + childSetValue("2nd_life_pic", avatar_data->image_id); + childSetValue("real_world_pic", avatar_data->fl_image_id); + childSetValue("homepage_edit", avatar_data->profile_url); +} + +void LLPanelAvatarProfile::fillPartnerData(const LLAvatarData* avatar_data) +{ + if (avatar_data->partner_id.notNull()) + { + std::string first, last; + BOOL found = gCacheName->getName(avatar_data->partner_id, first, last); + if (found) + { + childSetTextArg("partner_text", "[FIRST]", first); + childSetTextArg("partner_text", "[LAST]", last); + } + } + else + { + childSetTextArg("partner_text", "[FIRST]", getString("no_partner_text")); + } +} + +void LLPanelAvatarProfile::fillOnlineStatus(const LLAvatarData* avatar_data) +{ + bool online = avatar_data->flags & AVATAR_ONLINE; + if(LLAvatarActions::isFriend(avatar_data->avatar_id)) + { + // Online status NO could be because they are hidden + // If they are a friend, we may know the truth! + online = LLAvatarTracker::instance().isBuddyOnline(avatar_data->avatar_id); + } + childSetValue("online_status", online ? + "Online" : "Offline"); + childSetColor("online_status", online ? + LLColor4::green : LLColor4::red); +} + +void LLPanelAvatarProfile::fillAccountStatus(const LLAvatarData* avatar_data) +{ + std::string caption_text = avatar_data->caption_text; + if(caption_text.empty()) + { + LLStringUtil::format_map_t args; + caption_text = getString("CaptionTextAcctInfo"); + BOOL transacted = (avatar_data->flags & AVATAR_TRANSACTED); + BOOL identified = (avatar_data->flags & AVATAR_IDENTIFIED); + BOOL age_verified = (avatar_data->flags & AVATAR_AGEVERIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations + + const char* ACCT_TYPE[] = { + "AcctTypeResident", + "AcctTypeTrial", + "AcctTypeCharterMember", + "AcctTypeEmployee" }; - }; - - return TRUE; -} - -void LLPanelAvatarClassified::apply() -{ - LLTabContainer* tabs = getChild("classified tab"); - for (S32 i = 0; i < tabs->getTabCount(); i++) - { - LLPanelClassified* panel = (LLPanelClassified*)tabs->getPanelByIndex(i); - panel->apply(); - } -} - - -void LLPanelAvatarClassified::deleteClassifiedPanels() -{ - LLTabContainer* tabs = getChild("classified tab"); - if (tabs) - { - tabs->deleteAllTabs(); - } - - childSetVisible("New...", false); - childSetVisible("Delete...", false); - childSetVisible("loading_text", true); -} - - -void LLPanelAvatarClassified::processAvatarClassifiedReply(LLMessageSystem* msg, void**) -{ - S32 block = 0; - S32 block_count = 0; - LLUUID classified_id; - std::string classified_name; - LLPanelClassified* panel_classified = NULL; - - LLTabContainer* tabs = getChild("classified tab"); - - // Don't remove old panels. We need to be able to process multiple - // packets for people who have lots of classifieds. JC - - block_count = msg->getNumberOfBlocksFast(_PREHASH_Data); - for (block = 0; block < block_count; block++) - { - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ClassifiedID, classified_id, block); - msg->getStringFast(_PREHASH_Data, _PREHASH_Name, classified_name, block); - - panel_classified = new LLPanelClassified(false, false); - - panel_classified->setClassifiedID(classified_id); - - // This will request data from the server when the pick is first drawn. - panel_classified->markForServerRequest(); - - // The button should automatically truncate long names for us - if(tabs) - { - tabs->addTabPanel(panel_classified, classified_name); - } - } - - // Make sure somebody is highlighted. This works even if there - // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } - - childSetVisible("New...", true); - childSetVisible("Delete...", true); - childSetVisible("loading_text", false); -} - - -// Create a new classified panel. It will automatically handle generating -// its own id when it's time to save. -// static -void LLPanelAvatarClassified::onClickNew(void* data) -{ - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - - LLNotifications::instance().add("AddClassified", LLSD(), LLSD(), boost::bind(&LLPanelAvatarClassified::callbackNew, self, _1, _2)); - -} - -bool LLPanelAvatarClassified::callbackNew(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - if (0 == option) - { - LLPanelClassified* panel_classified = new LLPanelClassified(false, false); - panel_classified->initNewClassified(); - LLTabContainer* tabs = getChild("classified tab"); - if(tabs) - { - tabs->addTabPanel(panel_classified, panel_classified->getClassifiedName()); - tabs->selectLastTab(); - } - } - return false; -} - - -// static -void LLPanelAvatarClassified::onClickDelete(void* data) -{ - LLPanelAvatarClassified* self = (LLPanelAvatarClassified*)data; - - LLTabContainer* tabs = self->getChild("classified tab"); - LLPanelClassified* panel_classified = NULL; - if(tabs) - { - panel_classified = (LLPanelClassified*)tabs->getCurrentPanel(); - } - if (!panel_classified) return; - - LLSD args; - args["NAME"] = panel_classified->getClassifiedName(); - LLNotifications::instance().add("DeleteClassified", args, LLSD(), boost::bind(&LLPanelAvatarClassified::callbackDelete, self, _1, _2)); - -} - - -bool LLPanelAvatarClassified::callbackDelete(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLTabContainer* tabs = getChild("classified tab"); - LLPanelClassified* panel_classified=NULL; - if(tabs) - { - panel_classified = (LLPanelClassified*)tabs->getCurrentPanel(); - } - - LLMessageSystem* msg = gMessageSystem; - - if (!panel_classified) return false; - - if (0 == option) - { - msg->newMessageFast(_PREHASH_ClassifiedDelete); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlockFast(_PREHASH_Data); - msg->addUUIDFast(_PREHASH_ClassifiedID, panel_classified->getClassifiedID()); - gAgent.sendReliableMessage(); - - if(tabs) - { - tabs->removeTabPanel(panel_classified); - } - delete panel_classified; - panel_classified = NULL; - } - return false; -} - - -//----------------------------------------------------------------------------- -// LLPanelAvatarPicks() -//----------------------------------------------------------------------------- -LLPanelAvatarPicks::LLPanelAvatarPicks(const std::string& name, - const LLRect& rect, - LLPanelAvatar* panel_avatar) -: LLPanelAvatarTab(name, rect, panel_avatar) -{ -} - - -void LLPanelAvatarPicks::refresh() -{ - BOOL self = (gAgent.getID() == getPanelAvatar()->getAvatarID()); - LLTabContainer* tabs = getChild("picks tab"); - S32 tab_count = tabs ? tabs->getTabCount() : 0; - childSetEnabled("New...", self && tab_count < MAX_AVATAR_PICKS); - childSetEnabled("Delete...", self && tab_count > 0); - childSetVisible("New...", self && getPanelAvatar()->isEditable()); - childSetVisible("Delete...", self && getPanelAvatar()->isEditable()); - - sendAvatarProfileRequestIfNeeded("avatarpicksrequest"); -} - - -void LLPanelAvatarPicks::deletePickPanels() -{ - LLTabContainer* tabs = getChild("picks tab"); - if(tabs) - { - tabs->deleteAllTabs(); - } - - childSetVisible("New...", false); - childSetVisible("Delete...", false); - childSetVisible("loading_text", true); -} - -void LLPanelAvatarPicks::processAvatarPicksReply(LLMessageSystem* msg, void**) -{ - S32 block = 0; - S32 block_count = 0; - LLUUID pick_id; - std::string pick_name; - LLPanelPick* panel_pick = NULL; - - LLTabContainer* tabs = getChild("picks tab"); - - // Clear out all the old panels. We'll replace them with the correct - // number of new panels. - deletePickPanels(); - - // The database needs to know for which user to look up picks. - LLUUID avatar_id = getPanelAvatar()->getAvatarID(); - - block_count = msg->getNumberOfBlocks("Data"); - for (block = 0; block < block_count; block++) - { - msg->getUUID("Data", "PickID", pick_id, block); - msg->getString("Data", "PickName", pick_name, block); - - panel_pick = new LLPanelPick(FALSE); - - panel_pick->setPickID(pick_id, avatar_id); - - // This will request data from the server when the pick is first - // drawn. - panel_pick->markForServerRequest(); - - // The button should automatically truncate long names for us - if(tabs) - { - tabs->addTabPanel(panel_pick, pick_name); - } - } - - // Make sure somebody is highlighted. This works even if there - // are no tabs in the container. - if(tabs) - { - tabs->selectFirstTab(); - } - - childSetVisible("New...", true); - childSetVisible("Delete...", true); - childSetVisible("loading_text", false); -} - - -// Create a new pick panel. It will automatically handle generating -// its own id when it's time to save. -// static -void LLPanelAvatarPicks::onClickNew(void* data) -{ - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLPanelPick* panel_pick = new LLPanelPick(FALSE); - LLTabContainer* tabs = self->getChild("picks tab"); - - panel_pick->initNewPick(); - if(tabs) - { - tabs->addTabPanel(panel_pick, panel_pick->getPickName()); - tabs->selectLastTab(); - } -} - - -// static -void LLPanelAvatarPicks::onClickDelete(void* data) -{ - LLPanelAvatarPicks* self = (LLPanelAvatarPicks*)data; - LLTabContainer* tabs = self->getChild("picks tab"); - LLPanelPick* panel_pick = tabs?(LLPanelPick*)tabs->getCurrentPanel():NULL; - - if (!panel_pick) return; - - LLSD args; - args["PICK"] = panel_pick->getPickName(); - - LLNotifications::instance().add("DeleteAvatarPick", args, LLSD(), - boost::bind(&LLPanelAvatarPicks::callbackDelete, self, _1, _2)); -} - - -// static -bool LLPanelAvatarPicks::callbackDelete(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - LLTabContainer* tabs = getChild("picks tab"); - LLPanelPick* panel_pick = tabs ? (LLPanelPick*)tabs->getCurrentPanel() : NULL; - LLMessageSystem* msg = gMessageSystem; - - if (!panel_pick) return false; - - if (0 == option) - { - // If the viewer has a hacked god-mode, then this call will - // fail. - if(gAgent.isGodlike()) - { - msg->newMessage("PickGodDelete"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", panel_pick->getPickID()); - // *HACK: We need to send the pick's creator id to accomplish - // the delete, and we don't use the query id for anything. JC - msg->addUUID( "QueryID", panel_pick->getPickCreatorID() ); - } - else - { - msg->newMessage("PickDelete"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", panel_pick->getPickID()); - } - gAgent.sendReliableMessage(); - - if(tabs) - { - tabs->removeTabPanel(panel_pick); - } - delete panel_pick; - panel_pick = NULL; - } - return false; -} - - -//----------------------------------------------------------------------------- -// LLPanelAvatar -//----------------------------------------------------------------------------- -LLPanelAvatar::LLPanelAvatar( - const std::string& name, - const LLRect &rect, - BOOL allow_edit) - : - LLPanel(name, rect, FALSE), - mPanelSecondLife(NULL), - mPanelAdvanced(NULL), - mPanelClassified(NULL), - mPanelPicks(NULL), - mPanelNotes(NULL), - mPanelFirstLife(NULL), - mPanelWeb(NULL), - mDropTarget(NULL), - mAvatarID( LLUUID::null ), // mAvatarID is set with 'setAvatar' or 'setAvatarID' - mHaveProperties(FALSE), - mHaveStatistics(FALSE), - mHaveNotes(false), - mLastNotes(), - mAllowEdit(allow_edit) -{ - - sAllPanels.push_back(this); - - LLCallbackMap::map_t factory_map; - - factory_map["2nd Life"] = LLCallbackMap(createPanelAvatarSecondLife, this); - factory_map["WebProfile"] = LLCallbackMap(createPanelAvatarWeb, this); - factory_map["Interests"] = LLCallbackMap(createPanelAvatarInterests, this); - factory_map["Picks"] = LLCallbackMap(createPanelAvatarPicks, this); - factory_map["Classified"] = LLCallbackMap(createPanelAvatarClassified, this); - factory_map["1st Life"] = LLCallbackMap(createPanelAvatarFirstLife, this); - factory_map["My Notes"] = LLCallbackMap(createPanelAvatarNotes, this); - - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar.xml", &factory_map); - - selectTab(0); - - -} - -BOOL LLPanelAvatar::postBuild(void) -{ - mTab = getChild("tab"); - childSetAction("Kick",onClickKick,this); - childSetAction("Freeze",onClickFreeze, this); - childSetAction("Unfreeze", onClickUnfreeze, this); - childSetAction("csr_btn", onClickCSR, this); - childSetAction("OK", onClickOK, this); - childSetAction("Cancel", onClickCancel, this); - - if(mTab && !sAllowFirstLife) - { - LLPanel* panel = mTab->getPanelByName("1st Life"); - if (panel) mTab->removeTabPanel(panel); - - panel = mTab->getPanelByName("WebProfile"); - if (panel) mTab->removeTabPanel(panel); - } - childSetVisible("Kick",FALSE); - childSetEnabled("Kick",FALSE); - childSetVisible("Freeze",FALSE); - childSetEnabled("Freeze",FALSE); - childSetVisible("Unfreeze",FALSE); - childSetEnabled("Unfreeze",FALSE); - childSetVisible("csr_btn", FALSE); - childSetEnabled("csr_btn", FALSE); - - return TRUE; -} - - -LLPanelAvatar::~LLPanelAvatar() -{ - sAllPanels.remove(this); -} - - -BOOL LLPanelAvatar::canClose() -{ - return mPanelClassified && mPanelClassified->canClose(); -} - -void LLPanelAvatar::setAvatar(LLViewerObject *avatarp) -{ - // find the avatar and grab the name - LLNameValue *firstname = avatarp->getNVPair("FirstName"); - LLNameValue *lastname = avatarp->getNVPair("LastName"); - - std::string name; - if (firstname && lastname) - { - name.assign( firstname->getString() ); - name.append(" "); - name.append( lastname->getString() ); - } - else - { - name.assign(""); - } - - // If we have an avatar pointer, they must be online. - setAvatarID(avatarp->getID(), name, ONLINE_STATUS_YES); -} - -void LLPanelAvatar::setOnlineStatus(EOnlineStatus online_status) -{ - // Online status NO could be because they are hidden - // If they are a friend, we may know the truth! - if ((ONLINE_STATUS_YES != online_status) - && mIsFriend - && (LLAvatarTracker::instance().isBuddyOnline( mAvatarID ))) - { - online_status = ONLINE_STATUS_YES; - } - - mPanelSecondLife->childSetVisible("online_yes", (online_status == ONLINE_STATUS_YES)); - - // Since setOnlineStatus gets called after setAvatarID - // need to make sure that "Offer Teleport" doesn't get set - // to TRUE again for yourself - if (mAvatarID != gAgent.getID()) - { - childSetVisible("Offer Teleport...",TRUE); - } - - BOOL in_prelude = gAgent.inPrelude(); - if(gAgent.isGodlike()) - { - childSetEnabled("Offer Teleport...", TRUE); - childSetToolTip("Offer Teleport...", childGetValue("TeleportGod").asString()); - } - else if (in_prelude) - { - childSetEnabled("Offer Teleport...",FALSE); - childSetToolTip("Offer Teleport...",childGetValue("TeleportPrelude").asString()); - } - else - { - childSetEnabled("Offer Teleport...", (online_status == ONLINE_STATUS_YES)); - childSetToolTip("Offer Teleport...", childGetValue("TeleportNormal").asString()); - } -} - -void LLPanelAvatar::setAvatarID(const LLUUID &avatar_id, const std::string &name, - EOnlineStatus online_status) -{ - if (avatar_id.isNull()) return; - - BOOL avatar_changed = FALSE; - if (avatar_id != mAvatarID) - { - avatar_changed = TRUE; - } - mAvatarID = avatar_id; - - // Determine if we have their calling card. - mIsFriend = is_agent_friend(mAvatarID); - - // setOnlineStatus uses mIsFriend - setOnlineStatus(online_status); - - BOOL own_avatar = (mAvatarID == gAgent.getID() ); - BOOL avatar_is_friend = LLAvatarTracker::instance().getBuddyInfo(mAvatarID) != NULL; - - mPanelSecondLife->enableControls(own_avatar && mAllowEdit); - mPanelWeb->enableControls(own_avatar && mAllowEdit); - mPanelAdvanced->enableControls(own_avatar && mAllowEdit); - // Teens don't have this. - if (mPanelFirstLife) mPanelFirstLife->enableControls(own_avatar && mAllowEdit); - - LLView *target_view = getChild("drop_target_rect"); - if(target_view) - { - if (mDropTarget) - { - delete mDropTarget; - } - mDropTarget = new LLDropTarget("drop target", target_view->getRect(), mAvatarID); - addChild(mDropTarget); - mDropTarget->setAgentID(mAvatarID); - } - - LLNameEditor* name_edit = getChild("name"); - if(name_edit) - { - if (name.empty()) - { - name_edit->setNameID(avatar_id, FALSE); - } - else - { - name_edit->setText(name); - } - } -// if (avatar_changed) - { - // While we're waiting for data off the network, clear out the - // old data. - mPanelSecondLife->clearControls(); - - mPanelPicks->deletePickPanels(); - mPanelPicks->setDataRequested(false); - - mPanelClassified->deleteClassifiedPanels(); - mPanelClassified->setDataRequested(false); - - mPanelNotes->clearControls(); - mPanelNotes->setDataRequested(false); - mHaveNotes = false; - mLastNotes.clear(); - - // Request just the first two pages of data. The picks, - // classifieds, and notes will be requested when that panel - // is made visible. JC - sendAvatarPropertiesRequest(); - - if (own_avatar) - { - if (mAllowEdit) + U8 caption_index = llclamp(avatar_data->caption_index, (U8)0, (U8)(LL_ARRAY_SIZE(ACCT_TYPE)-1)); + args["[ACCTTYPE]"] = getString(ACCT_TYPE[caption_index]); + + std::string payment_text = " "; + const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3; + if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX) + { + if(transacted) { - // OK button disabled until properties data arrives - childSetVisible("OK", true); - childSetEnabled("OK", false); - childSetVisible("Cancel",TRUE); - childSetEnabled("Cancel",TRUE); + payment_text = "PaymentInfoUsed"; + } + else if (identified) + { + payment_text = "PaymentInfoOnFile"; } else { - childSetVisible("OK",FALSE); - childSetEnabled("OK",FALSE); - childSetVisible("Cancel",FALSE); - childSetEnabled("Cancel",FALSE); + payment_text = "NoPaymentInfoOnFile"; } - childSetVisible("Instant Message...",FALSE); - childSetEnabled("Instant Message...",FALSE); - childSetVisible("Mute",FALSE); - childSetEnabled("Mute",FALSE); - childSetVisible("Offer Teleport...",FALSE); - childSetEnabled("Offer Teleport...",FALSE); - childSetVisible("drop target",FALSE); - childSetEnabled("drop target",FALSE); - childSetVisible("Find on Map",FALSE); - childSetEnabled("Find on Map",FALSE); - childSetVisible("Add Friend...",FALSE); - childSetEnabled("Add Friend...",FALSE); - childSetVisible("Pay...",FALSE); - childSetEnabled("Pay...",FALSE); + args["[PAYMENTINFO]"] = getString(payment_text); + + std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; + // Do not display age verification status at this time + //args["[[AGEVERIFICATION]]"] = mPanelSecondLife->getString(age_text); + args["[AGEVERIFICATION]"] = " "; } else { - childSetVisible("OK",FALSE); - childSetEnabled("OK",FALSE); - - childSetVisible("Cancel",FALSE); - childSetEnabled("Cancel",FALSE); - - childSetVisible("Instant Message...",TRUE); - childSetEnabled("Instant Message...",FALSE); - childSetVisible("Mute",TRUE); - childSetEnabled("Mute",FALSE); - - childSetVisible("drop target",TRUE); - childSetEnabled("drop target",FALSE); - - childSetVisible("Find on Map",TRUE); - // Note: we don't always know online status, so always allow gods to try to track - BOOL enable_track = gAgent.isGodlike() || is_agent_mappable(mAvatarID); - childSetEnabled("Find on Map",enable_track); - if (!mIsFriend) - { - childSetToolTip("Find on Map",childGetValue("ShowOnMapNonFriend").asString()); - } - else if (ONLINE_STATUS_YES != online_status) - { - childSetToolTip("Find on Map",childGetValue("ShowOnMapFriendOffline").asString()); - } - else - { - childSetToolTip("Find on Map",childGetValue("ShowOnMapFriendOnline").asString()); - } - childSetVisible("Add Friend...", true); - childSetEnabled("Add Friend...", !avatar_is_friend); - childSetVisible("Pay...",TRUE); - childSetEnabled("Pay...",FALSE); + args["[PAYMENTINFO]"] = " "; + args["[AGEVERIFICATION]"] = " "; } - } - - BOOL is_god = FALSE; - if (gAgent.isGodlike()) is_god = TRUE; - - childSetVisible("Kick", is_god); - childSetEnabled("Kick", is_god); - childSetVisible("Freeze", is_god); - childSetEnabled("Freeze", is_god); - childSetVisible("Unfreeze", is_god); - childSetEnabled("Unfreeze", is_god); - childSetVisible("csr_btn", is_god); - childSetEnabled("csr_btn", is_god); -} - - -void LLPanelAvatar::resetGroupList() -{ - // only get these updates asynchronously via the group floater, which works on the agent only - if (mAvatarID != gAgent.getID()) - { - return; - } - - if (mPanelSecondLife) - { - LLScrollListCtrl* group_list = mPanelSecondLife->getChild("groups"); - if (group_list) - { - group_list->deleteAllItems(); - - S32 count = gAgent.mGroups.count(); - LLUUID id; - - for(S32 i = 0; i < count; ++i) - { - LLGroupData group_data = gAgent.mGroups.get(i); - id = group_data.mID; - std::string group_string; - /* Show group title? DUMMY_POWER for Don Grep - if(group_data.mOfficer) - { - group_string = "Officer of "; - } - else - { - group_string = "Member of "; - } - */ - - group_string += group_data.mName; - - LLSD row; - - row["id"] = id ; - row["columns"][0]["value"] = group_string; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - row["columns"][0]["width"] = 0; - group_list->addElement(row); - } - group_list->sortByColumnIndex(0, TRUE); - } - } -} - -// static -//----------------------------------------------------------------------------- -// onClickIM() -//----------------------------------------------------------------------------- -void LLPanelAvatar::onClickIM(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - gIMMgr->setFloaterOpen(TRUE); - - std::string name; - LLNameEditor* nameedit = self->mPanelSecondLife->getChild("name"); - if (nameedit) name = nameedit->getText(); - gIMMgr->addSession(name, IM_NOTHING_SPECIAL, self->mAvatarID); -} - - -// static -//----------------------------------------------------------------------------- -// onClickTrack() -//----------------------------------------------------------------------------- -void LLPanelAvatar::onClickTrack(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - - if( gFloaterWorldMap ) - { - std::string name; - LLNameEditor* nameedit = self->mPanelSecondLife->getChild("name"); - if (nameedit) name = nameedit->getText(); - gFloaterWorldMap->trackAvatar(self->mAvatarID, name); - LLFloaterWorldMap::show(NULL, TRUE); - } -} - - -// static -void LLPanelAvatar::onClickAddFriend(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - LLNameEditor* name_edit = self->mPanelSecondLife->getChild("name"); - if (name_edit) - { - LLPanelFriends::requestFriendshipDialog(self->getAvatarID(), - name_edit->getText()); - } -} - -//----------------------------------------------------------------------------- -// onClickMute() -//----------------------------------------------------------------------------- -void LLPanelAvatar::onClickMute(void *userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - - LLUUID agent_id = self->getAvatarID(); - LLNameEditor* name_edit = self->mPanelSecondLife->getChild("name"); - - if (name_edit) - { - std::string agent_name = name_edit->getText(); - LLFloaterMute::showInstance(); - - if (LLMuteList::getInstance()->isMuted(agent_id)) - { - LLFloaterMute::getInstance()->selectMute(agent_id); - } - else - { - LLMute mute(agent_id, agent_name, LLMute::AGENT); - LLMuteList::getInstance()->add(mute); - } - } -} - - -// static -void LLPanelAvatar::onClickOfferTeleport(void *userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - - handle_lure(self->mAvatarID); -} - - -// static -void LLPanelAvatar::onClickPay(void *userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - handle_pay_by_id(self->mAvatarID); -} - - -// static -void LLPanelAvatar::onClickOK(void *userdata) -{ - LLPanelAvatar *self = (LLPanelAvatar *)userdata; - - // JC: Only save the data if we actually got the original - // properties. Otherwise we might save blanks into - // the database. - if (self - && self->mHaveProperties) - { - self->sendAvatarPropertiesUpdate(); - - LLTabContainer* tabs = self->getChild("tab"); - if ( tabs->getCurrentPanel() != self->mPanelClassified ) - { - self->mPanelClassified->apply(); - - LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID); - if (infop) - { - infop->close(); - } - } - else - { - if ( self->mPanelClassified->titleIsValid() ) - { - self->mPanelClassified->apply(); - - LLFloaterAvatarInfo *infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID); - if (infop) - { - infop->close(); - } - } - } - } -} - -// static -void LLPanelAvatar::onClickCancel(void *userdata) -{ - LLPanelAvatar *self = (LLPanelAvatar *)userdata; - - if (self) - { - LLFloaterAvatarInfo *infop; - if ((infop = LLFloaterAvatarInfo::getInstance(self->mAvatarID))) - { - infop->close(); - } - else - { - // We're in the Search directory and are cancelling an edit - // to our own profile, so reset. - self->sendAvatarPropertiesRequest(); - } - } -} - - -void LLPanelAvatar::sendAvatarPropertiesRequest() -{ - lldebugs << "LLPanelAvatar::sendAvatarPropertiesRequest()" << llendl; - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_AvatarPropertiesRequest); - msg->nextBlockFast( _PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addUUIDFast( _PREHASH_AvatarID, mAvatarID); - gAgent.sendReliableMessage(); -} - -void LLPanelAvatar::sendAvatarNotesUpdate() -{ - std::string notes = mPanelNotes->childGetValue("notes edit").asString(); - - if (!mHaveNotes - && (notes.empty() || notes == getString("Loading"))) - { - // no notes from server and no user updates - return; - } - if (notes == mLastNotes) - { - // Avatar notes unchanged - return; + LLStringUtil::format(caption_text, args); } - LLMessageSystem *msg = gMessageSystem; - - msg->newMessage("AvatarNotesUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("TargetID", mAvatarID); - msg->addString("Notes", notes); - - gAgent.sendReliableMessage(); + childSetValue("acc_status_text", caption_text); } - -// static -void LLPanelAvatar::processAvatarPropertiesReply(LLMessageSystem *msg, void**) +void LLPanelAvatarProfile::onUrlTextboxClicked(std::string url) { - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - LLUUID image_id; - LLUUID fl_image_id; - LLUUID partner_id; - std::string about_text; - std::string fl_about_text; - std::string born_on; - S32 charter_member_size = 0; - BOOL allow_publish = FALSE; - //BOOL mature = FALSE; - BOOL identified = FALSE; - BOOL transacted = FALSE; - BOOL age_verified = FALSE; - BOOL online = FALSE; - std::string profile_url; - - U32 flags = 0x0; - - //llinfos << "properties packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) - { - continue; - } - self->childSetEnabled("Instant Message...",TRUE); - self->childSetEnabled("Pay...",TRUE); - self->childSetEnabled("Mute",TRUE); - - self->childSetEnabled("drop target",TRUE); - - self->mHaveProperties = TRUE; - self->enableOKIfReady(); - - msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_ImageID, image_id ); - msg->getUUIDFast( _PREHASH_PropertiesData, _PREHASH_FLImageID, fl_image_id ); - msg->getUUIDFast(_PREHASH_PropertiesData, _PREHASH_PartnerID, partner_id); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_AboutText, about_text ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_FLAboutText, fl_about_text ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_BornOn, born_on); - msg->getString("PropertiesData","ProfileURL", profile_url); - msg->getU32Fast(_PREHASH_PropertiesData, _PREHASH_Flags, flags); - - identified = (flags & AVATAR_IDENTIFIED); - transacted = (flags & AVATAR_TRANSACTED); - age_verified = (flags & AVATAR_AGEVERIFIED); // Not currently getting set in dataserver/lldataavatar.cpp for privacy considerations - allow_publish = (flags & AVATAR_ALLOW_PUBLISH); - online = (flags & AVATAR_ONLINE); - - U8 caption_index = 0; - std::string caption_text; - charter_member_size = msg->getSize("PropertiesData", "CharterMember"); - if(1 == charter_member_size) - { - msg->getBinaryData("PropertiesData", "CharterMember", &caption_index, 1); - } - else if(1 < charter_member_size) - { - msg->getString("PropertiesData", "CharterMember", caption_text); - } - - - if(caption_text.empty()) - { - LLStringUtil::format_map_t args; - caption_text = self->mPanelSecondLife->getString("CaptionTextAcctInfo"); - - const char* ACCT_TYPE[] = { - "AcctTypeResident", - "AcctTypeTrial", - "AcctTypeCharterMember", - "AcctTypeEmployee" - }; - caption_index = llclamp(caption_index, (U8)0, (U8)(LL_ARRAY_SIZE(ACCT_TYPE)-1)); - args["[ACCTTYPE]"] = self->mPanelSecondLife->getString(ACCT_TYPE[caption_index]); - - std::string payment_text = " "; - const S32 DEFAULT_CAPTION_LINDEN_INDEX = 3; - if(caption_index != DEFAULT_CAPTION_LINDEN_INDEX) - { - if(transacted) - { - payment_text = "PaymentInfoUsed"; - } - else if (identified) - { - payment_text = "PaymentInfoOnFile"; - } - else - { - payment_text = "NoPaymentInfoOnFile"; - } - args["[PAYMENTINFO]"] = self->mPanelSecondLife->getString(payment_text); - std::string age_text = age_verified ? "AgeVerified" : "NotAgeVerified"; - // Do not display age verification status at this time - //args["[[AGEVERIFICATION]]"] = self->mPanelSecondLife->getString(age_text); - args["[AGEVERIFICATION]"] = " "; - } - else - { - args["[PAYMENTINFO]"] = " "; - args["[AGEVERIFICATION]"] = " "; - } - LLStringUtil::format(caption_text, args); - } - - self->mPanelSecondLife->childSetValue("acct", caption_text); - self->mPanelSecondLife->childSetValue("born", born_on); - - EOnlineStatus online_status = (online) ? ONLINE_STATUS_YES : ONLINE_STATUS_NO; - - self->setOnlineStatus(online_status); - - self->mPanelWeb->setWebURL(profile_url); - - LLTextureCtrl* image_ctrl = self->mPanelSecondLife->getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(image_id); - } - self->childSetValue("about", about_text); - - self->mPanelSecondLife->setPartnerID(partner_id); - self->mPanelSecondLife->updatePartnerName(); - - if (self->mPanelFirstLife) - { - // Teens don't get these - self->mPanelFirstLife->childSetValue("about", fl_about_text); - LLTextureCtrl* image_ctrl = self->mPanelFirstLife->getChild("img"); - if(image_ctrl) - { - image_ctrl->setImageAssetID(fl_image_id); - } - - self->mPanelSecondLife->childSetValue("allow_publish", allow_publish); - - } - } -} - -// static -void LLPanelAvatar::processAvatarInterestsReply(LLMessageSystem *msg, void**) -{ - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - - U32 want_to_mask; - std::string want_to_text; - U32 skills_mask; - std::string skills_text; - std::string languages_text; - - //llinfos << "properties packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) - { - continue; - } - - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_WantToMask, want_to_mask ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_WantToText, want_to_text ); - msg->getU32Fast( _PREHASH_PropertiesData, _PREHASH_SkillsMask, skills_mask ); - msg->getStringFast(_PREHASH_PropertiesData, _PREHASH_SkillsText, skills_text ); - msg->getString(_PREHASH_PropertiesData, "LanguagesText", languages_text ); - - self->mPanelAdvanced->setWantSkills(want_to_mask, want_to_text, skills_mask, skills_text, languages_text); - } -} - -// Separate function because the groups list can be very long, almost -// filling a packet. JC -// static -void LLPanelAvatar::processAvatarGroupsReply(LLMessageSystem *msg, void**) -{ - LLUUID agent_id; // your id - LLUUID avatar_id; // target of this panel - U64 group_powers; - std::string group_title; - LLUUID group_id; - std::string group_name; - LLUUID group_insignia_id; - - llinfos << "groups packet size " << msg->getReceiveSize() << llendl; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AvatarID, avatar_id ); - - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != avatar_id) - { - continue; - } - - LLScrollListCtrl* group_list = self->mPanelSecondLife->getChild("groups"); -// if(group_list) -// { -// group_list->deleteAllItems(); -// } - - S32 group_count = msg->getNumberOfBlocksFast(_PREHASH_GroupData); - if (0 == group_count) - { - if(group_list) group_list->addCommentText(std::string("None")); // *TODO: Translate - } - else - { - for(S32 i = 0; i < group_count; ++i) - { - msg->getU64( _PREHASH_GroupData, "GroupPowers", group_powers, i ); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupTitle, group_title, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupID, group_id, i); - msg->getStringFast(_PREHASH_GroupData, _PREHASH_GroupName, group_name, i ); - msg->getUUIDFast( _PREHASH_GroupData, _PREHASH_GroupInsigniaID, group_insignia_id, i ); - - std::string group_string; - if (group_id.notNull()) - { - group_string.assign(group_name); - } - else - { - group_string.assign(""); - } - - // Is this really necessary? Remove existing entry if it exists. - // TODO: clear the whole list when a request for data is made - if (group_list) - { - S32 index = group_list->getItemIndex(group_id); - if ( index >= 0 ) - { - group_list->deleteSingleItem(index); - } - } - - LLSD row; - row["id"] = group_id; - row["columns"][0]["value"] = group_string; - row["columns"][0]["font"] = "SANSSERIF_SMALL"; - if (group_list) - { - group_list->addElement(row); - } - } - } - if(group_list) group_list->sortByColumnIndex(0, TRUE); - } -} - -// Don't enable the OK button until you actually have the data. -// Otherwise you will write blanks back into the database. -void LLPanelAvatar::enableOKIfReady() -{ - if(mHaveProperties && childIsVisible("OK")) - { - childSetEnabled("OK", TRUE); - } - else - { - childSetEnabled("OK", FALSE); - } -} - -void LLPanelAvatar::sendAvatarPropertiesUpdate() -{ - llinfos << "Sending avatarinfo update" << llendl; - BOOL allow_publish = FALSE; - BOOL mature = FALSE; - if (LLPanelAvatar::sAllowFirstLife) - { - allow_publish = childGetValue("allow_publish"); - //A profile should never be mature. - mature = FALSE; - } - U32 want_to_mask = 0x0; - U32 skills_mask = 0x0; - std::string want_to_text; - std::string skills_text; - std::string languages_text; - mPanelAdvanced->getWantSkills(&want_to_mask, want_to_text, &skills_mask, skills_text, languages_text); - - LLUUID first_life_image_id; - std::string first_life_about_text; - if (mPanelFirstLife) - { - first_life_about_text = mPanelFirstLife->childGetValue("about").asString(); - LLTextureCtrl* image_ctrl = mPanelFirstLife->getChild("img"); - if(image_ctrl) - { - first_life_image_id = image_ctrl->getImageAssetID(); - } - } - - std::string about_text = mPanelSecondLife->childGetValue("about").asString(); - - LLMessageSystem *msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_AvatarPropertiesUpdate); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_PropertiesData); - - LLTextureCtrl* image_ctrl = mPanelSecondLife->getChild("img"); - if(image_ctrl) - { - msg->addUUIDFast( _PREHASH_ImageID, image_ctrl->getImageAssetID()); - } - else - { - msg->addUUIDFast( _PREHASH_ImageID, LLUUID::null); - } -// msg->addUUIDFast( _PREHASH_ImageID, mPanelSecondLife->mimage_ctrl->getImageAssetID() ); - msg->addUUIDFast( _PREHASH_FLImageID, first_life_image_id); - msg->addStringFast( _PREHASH_AboutText, about_text); - msg->addStringFast( _PREHASH_FLAboutText, first_life_about_text); - - msg->addBOOL("AllowPublish", allow_publish); - msg->addBOOL("MaturePublish", mature); - msg->addString("ProfileURL", mPanelWeb->childGetText("url_edit")); - gAgent.sendReliableMessage(); - - msg->newMessage("AvatarInterestsUpdate"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast( _PREHASH_AgentID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->nextBlockFast(_PREHASH_PropertiesData); - msg->addU32Fast( _PREHASH_WantToMask, want_to_mask); - msg->addStringFast( _PREHASH_WantToText, want_to_text); - msg->addU32Fast( _PREHASH_SkillsMask, skills_mask); - msg->addStringFast( _PREHASH_SkillsText, skills_text); - msg->addString( "LanguagesText", languages_text); - gAgent.sendReliableMessage(); -} - -void LLPanelAvatar::selectTab(S32 tabnum) -{ - if(mTab) - { - mTab->selectTab(tabnum); - } -} - -void LLPanelAvatar::selectTabByName(std::string tab_name) -{ - if (mTab) - { - if (tab_name.empty()) - { - mTab->selectFirstTab(); - } - else - { - mTab->selectTabByName(tab_name); - } - } -} - - -void LLPanelAvatar::processAvatarNotesReply(LLMessageSystem *msg, void**) -{ - // extract the agent id - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id); - - LLUUID target_id; - msg->getUUID("Data", "TargetID", target_id); - - // look up all panels which have this avatar - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - std::string text; - msg->getString("Data", "Notes", text); - self->childSetValue("notes edit", text); - self->childSetEnabled("notes edit", true); - self->mHaveNotes = true; - self->mLastNotes = text; - } -} - - -void LLPanelAvatar::processAvatarClassifiedReply(LLMessageSystem *msg, void** userdata) -{ - LLUUID agent_id; - LLUUID target_id; - - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id); - msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_TargetID, target_id); - - // look up all panels which have this avatar target - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - self->mPanelClassified->processAvatarClassifiedReply(msg, userdata); - } -} - -void LLPanelAvatar::processAvatarPicksReply(LLMessageSystem *msg, void** userdata) -{ - LLUUID agent_id; - LLUUID target_id; - - msg->getUUID("AgentData", "AgentID", agent_id); - msg->getUUID("AgentData", "TargetID", target_id); - - // look up all panels which have this avatar target - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelAvatar* self = *iter; - if (self->mAvatarID != target_id) - { - continue; - } - - self->mPanelPicks->processAvatarPicksReply(msg, userdata); - } -} - -// static -void LLPanelAvatar::onClickKick(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect(left, top, left+400, top-300); - - LLSD payload; - payload["avatar_id"] = self->mAvatarID; - LLNotifications::instance().add("KickUser", LLSD(), payload, finishKick); -} - -//static -bool LLPanelAvatar::finishKick(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - LLMessageSystem* msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_GodKickUser); - msg->nextBlockFast(_PREHASH_UserInfo); - msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); - msg->addU32("KickFlags", KICK_FLAGS_DEFAULT ); - msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); - gAgent.sendReliableMessage(); - } - return false; -} - -// static -void LLPanelAvatar::onClickFreeze(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - LLSD payload; - payload["avatar_id"] = self->mAvatarID; - LLNotifications::instance().add("FreezeUser", LLSD(), payload, LLPanelAvatar::finishFreeze); -} - -// static -bool LLPanelAvatar::finishFreeze(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - - if (option == 0) - { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - LLMessageSystem* msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_GodKickUser); - msg->nextBlockFast(_PREHASH_UserInfo); - msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); - msg->addU32("KickFlags", KICK_FLAGS_FREEZE ); - msg->addStringFast(_PREHASH_Reason, response["message"].asString() ); - gAgent.sendReliableMessage(); - } - return false; -} - -// static -void LLPanelAvatar::onClickUnfreeze(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*) userdata; - LLSD payload; - payload["avatar_id"] = self->mAvatarID; - LLNotifications::instance().add("UnFreezeUser", LLSD(), payload, LLPanelAvatar::finishUnfreeze); -} - -// static -bool LLPanelAvatar::finishUnfreeze(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - std::string text = response["message"].asString(); - if (option == 0) - { - LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID(); - LLMessageSystem* msg = gMessageSystem; - - msg->newMessageFast(_PREHASH_GodKickUser); - msg->nextBlockFast(_PREHASH_UserInfo); - msg->addUUIDFast(_PREHASH_GodID, gAgent.getID() ); - msg->addUUIDFast(_PREHASH_GodSessionID, gAgent.getSessionID()); - msg->addUUIDFast(_PREHASH_AgentID, avatar_id ); - msg->addU32("KickFlags", KICK_FLAGS_UNFREEZE ); - msg->addStringFast(_PREHASH_Reason, text ); - gAgent.sendReliableMessage(); - } - return false; -} - -// static -void LLPanelAvatar::onClickCSR(void* userdata) -{ - LLPanelAvatar* self = (LLPanelAvatar*)userdata; - if (!self) return; - - LLNameEditor* name_edit = self->getChild("name"); - if (!name_edit) return; - - std::string name = name_edit->getText(); - if (name.empty()) return; - - std::string url = "http://csr.lindenlab.com/agent/"; - - // slow and stupid, but it's late - S32 len = name.length(); - for (S32 i = 0; i < len; i++) - { - if (name[i] == ' ') - { - url += "%20"; - } - else - { - url += name[i]; - } - } - LLWeb::loadURL(url); } - -void* LLPanelAvatar::createPanelAvatarSecondLife(void* data) +void LLPanelAvatarProfile::onHomepageTextboxClicked() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelSecondLife = new LLPanelAvatarSecondLife(std::string("2nd Life"),LLRect(),self); - return self->mPanelSecondLife; + std::string url = childGetValue("homepage_edit").asString(); + if(!url.empty()) + { + onUrlTextboxClicked(url); + } } -void* LLPanelAvatar::createPanelAvatarWeb(void* data) +void LLPanelAvatarProfile::onAddFriendButtonClick() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelWeb = new LLPanelAvatarWeb(std::string("Web"),LLRect(),self); - return self->mPanelWeb; + LLAvatarActions::requestFriendshipDialog(getAvatarId()); } -void* LLPanelAvatar::createPanelAvatarInterests(void* data) +void LLPanelAvatarProfile::onIMButtonClick() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelAdvanced = new LLPanelAvatarAdvanced(std::string("Interests"),LLRect(),self); - return self->mPanelAdvanced; + LLAvatarActions::startIM(getAvatarId()); } - -void* LLPanelAvatar::createPanelAvatarPicks(void* data) +void LLPanelAvatarProfile::onTeleportButtonClick() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelPicks = new LLPanelAvatarPicks(std::string("Picks"),LLRect(),self); - return self->mPanelPicks; + LLAvatarActions::offerTeleport(getAvatarId()); } -void* LLPanelAvatar::createPanelAvatarClassified(void* data) +void LLPanelAvatarProfile::onCallButtonClick() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelClassified = new LLPanelAvatarClassified(std::string("Classified"),LLRect(),self); - return self->mPanelClassified; + //*TODO not implemented } -void* LLPanelAvatar::createPanelAvatarFirstLife(void* data) +void LLPanelAvatarProfile::onShareButtonClick() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelFirstLife = new LLPanelAvatarFirstLife(std::string("1st Life"), LLRect(), self); - return self->mPanelFirstLife; + //*TODO not implemented } -void* LLPanelAvatar::createPanelAvatarNotes(void* data) +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////// + +LLPanelAvatarMeProfile::LLPanelAvatarMeProfile() +: LLPanelAvatarProfile() { - LLPanelAvatar* self = (LLPanelAvatar*)data; - self->mPanelNotes = new LLPanelAvatarNotes(std::string("My Notes"),LLRect(),self); - return self->mPanelNotes; +} + +BOOL LLPanelAvatarMeProfile::postBuild() +{ + LLPanelAvatarProfile::postBuild(); + + mStatusCombobox = getChild("status_combo"); + + childSetCommitCallback("status_combo", boost::bind(&LLPanelAvatarMeProfile::onStatusChanged, this), NULL); + childSetCommitCallback("status_me_message_text", boost::bind(&LLPanelAvatarMeProfile::onStatusMessageChanged, this), NULL); + childSetActionTextbox("payment_update_link", boost::bind(&LLPanelAvatarMeProfile::onUpdateAccountTextboxClicked, this)); + childSetActionTextbox("my_account_link", boost::bind(&LLPanelAvatarMeProfile::onMyAccountTextboxClicked, this)); + childSetActionTextbox("partner_edit_link", boost::bind(&LLPanelAvatarMeProfile::onPartnerEditTextboxClicked, this)); + + resetControls(); + resetData(); + + return TRUE; +} + +void LLPanelAvatarMeProfile::onOpen(const LLSD& key) +{ + LLPanelProfileTab::onOpen(key); +} + +void LLPanelAvatarMeProfile::processProfileProperties(const LLAvatarData* avatar_data) +{ + fillCommonData(avatar_data); + + fillPartnerData(avatar_data); + + fillStatusData(avatar_data); + + fillAccountStatus(avatar_data); +} + +void LLPanelAvatarMeProfile::fillStatusData(const LLAvatarData* avatar_data) +{ + std::string status; + if (gAgent.getAFK()) + { + status = "away"; + } + else if (gAgent.getBusy()) + { + status = "busy"; + } + else + { + status = "online"; + } + + mStatusCombobox->setValue(status); +} + +void LLPanelAvatarMeProfile::resetControls() +{ + childSetVisible("status_panel", false); + childSetVisible("profile_buttons_panel", false); + childSetVisible("title_groups_text", false); + childSetVisible("sl_groups", false); + childSetVisible("status_me_panel", true); + childSetVisible("profile_me_buttons_panel", true); +} + +void LLPanelAvatarMeProfile::onStatusChanged() +{ + LLSD::String status = mStatusCombobox->getValue().asString(); + + if ("online" == status) + { + gAgent.clearAFK(); + gAgent.clearBusy(); + } + else if ("away" == status) + { + gAgent.clearBusy(); + gAgent.setAFK(); + } + else if ("busy" == status) + { + gAgent.clearAFK(); + gAgent.setBusy(); + LLNotifications::instance().add("BusyModeSet"); + } +} + +void LLPanelAvatarMeProfile::onStatusMessageChanged() +{ + updateData(); +} + +void LLPanelAvatarMeProfile::onUpdateAccountTextboxClicked() +{ + onUrlTextboxClicked(getString("payment_update_link_url")); +} + +void LLPanelAvatarMeProfile::onMyAccountTextboxClicked() +{ + onUrlTextboxClicked(getString("my_account_link_url")); +} + +void LLPanelAvatarMeProfile::onPartnerEditTextboxClicked() +{ + onUrlTextboxClicked(getString("partner_edit_link_url")); } diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h index 12e1b99360..51bd619901 100644 --- a/indra/newview/llpanelavatar.h +++ b/indra/newview/llpanelavatar.h @@ -34,28 +34,10 @@ #define LL_LLPANELAVATAR_H #include "llpanel.h" -#include "v3dmath.h" -#include "lluuid.h" -#include "llwebbrowserctrl.h" +#include "llavatarpropertiesprocessor.h" -class LLButton; -class LLCheckBoxCtrl; -class LLDropTarget; -class LLInventoryItem; +class LLComboBox; class LLLineEditor; -class LLNameEditor; -class LLPanelAvatar; -class LLScrollListCtrl; -class LLTabContainer; -class LLTextBox; -class LLTextEditor; -class LLTextureCtrl; -class LLUICtrl; -class LLViewerImage; -class LLViewerObject; -class LLMessageSystem; -class LLIconCtrl; -class LLWebBrowserCtrl; enum EOnlineStatus { @@ -63,321 +45,209 @@ enum EOnlineStatus ONLINE_STATUS_YES = 1 }; -// Base class for all sub-tabs inside the avatar profile. Many of these -// panels need to keep track of the parent panel (to get the avatar id) -// and only request data from the database when they are first drawn. JC -class LLPanelAvatarTab : public LLPanel +/** +* Base class for any Profile View or Me Profile Panel. +*/ +class LLPanelProfileTab + : public LLPanel + , public LLAvatarPropertiesObserver { public: - LLPanelAvatarTab(const std::string& name, const LLRect &rect, - LLPanelAvatar* panel_avatar); - // Calls refresh() once per frame when panel is visible - /*virtual*/ void draw(); + /** + * Sets avatar ID, sets panel as observer of avatar related info replies from server. + */ + virtual void setAvatarId(const LLUUID& id); - LLPanelAvatar* getPanelAvatar() const { return mPanelAvatar; } + /** + * Returns avatar ID. + */ + virtual const LLUUID& getAvatarId() { return mAvatarId; } - void setDataRequested(bool requested) { mDataRequested = requested; } - bool isDataRequested() const { return mDataRequested; } + /** + * Sends update data request to server. + */ + virtual void updateData() = 0; - // If the data for this tab has not yet been requested, - // send the request. Used by tabs that are filled in only - // when they are first displayed. - // type is one of "avatarnotesrequest", "avatarpicksrequest", - // or "avatarclassifiedsrequest" - void sendAvatarProfileRequestIfNeeded(const std::string& method); + /** + * Clears panel data if viewing avatar info for first time and sends update data request. + */ + virtual void onOpen(const LLSD& key); + + /** + * Profile tabs should close any opened panels here. + * + * Called from LLPanelProfile::onOpen() before opening new profile. + * See LLPanelpicks::onClose for example. LLPanelPicks closes picture info panel + * before new profile is displayed, otherwise new profile will + * be hidden behind picture info panel. + */ + virtual void onClose() {} + + /** + * Resets controls visibility, state, etc. + */ + virtual void resetControls(){}; + + /** + * Clears all data received from server. + */ + virtual void resetData(){}; + + /*virtual*/ ~LLPanelProfileTab(); + +protected: + + LLPanelProfileTab(); + + /** + * Scrolls panel to top when viewing avatar info for first time. + */ + void scrollToTop(); private: - LLPanelAvatar* mPanelAvatar; - bool mDataRequested; + + LLUUID mAvatarId; }; - -class LLPanelAvatarFirstLife : public LLPanelAvatarTab +/** +* Panel for displaying Avatar's first and second life related info. +*/ +class LLPanelAvatarProfile + : public LLPanelProfileTab { public: - LLPanelAvatarFirstLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar); + LLPanelAvatarProfile(); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ void onOpen(const LLSD& key); - void enableControls(BOOL own_avatar); -}; + /** + * Processes data received from server. + */ + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + /*virtual*/ BOOL postBuild(); -class LLPanelAvatarSecondLife -: public LLPanelAvatarTab -{ -public: - LLPanelAvatarSecondLife(const std::string& name, const LLRect &rect, LLPanelAvatar* panel_avatar ); + /*virtual*/ void updateData(); - /*virtual*/ BOOL postBuild(void); - /*virtual*/ void refresh(); + /*virtual*/ void resetControls(); - static void onClickImage( void *userdata); - static void onClickFriends( void *userdata); - static void onDoubleClickGroup(void* userdata); - static void onClickPublishHelp(void *userdata); - static void onClickPartnerHelp(void *userdata); - static bool onClickPartnerHelpLoadURL(const LLSD& notification, const LLSD& response); - static void onClickPartnerInfo(void *userdata); + /*virtual*/ void resetData(); - // Clear out the controls anticipating new network data. - void clearControls(); - void enableControls(BOOL own_avatar); - void updateOnlineText(BOOL online, BOOL have_calling_card); - void updatePartnerName(); +protected: - void setPartnerID(LLUUID id) { mPartnerID = id; } + /** + * Process profile related data received from server. + */ + virtual void processProfileProperties(const LLAvatarData* avatar_data); + + /** + * Processes group related data received from server. + */ + virtual void processGroupProperties(const LLAvatarGroups* avatar_groups); + + /** + * Fills common for Avatar profile and Me Profile fields. + */ + virtual void fillCommonData(const LLAvatarData* avatar_data); + + /** + * Fills partner data. + */ + virtual void fillPartnerData(const LLAvatarData* avatar_data); + + /** + * Fills Avatar's online status. + */ + virtual void fillOnlineStatus(const LLAvatarData* avatar_data); -private: - LLUUID mPartnerID; + /** + * Fills account status. + */ + virtual void fillAccountStatus(const LLAvatarData* avatar_data); + + void onUrlTextboxClicked(std::string url); + void onHomepageTextboxClicked(); + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); }; - -// WARNING! The order of the inheritance here matters!! Do not change. - KLW -class LLPanelAvatarWeb : - public LLPanelAvatarTab - , public LLWebBrowserCtrlObserver +/** + * Panel for displaying own first and second life related info. + */ +class LLPanelAvatarMeProfile + : public LLPanelAvatarProfile { public: - LLPanelAvatarWeb(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - /*virtual*/ ~LLPanelAvatarWeb(); - /*virtual*/ BOOL postBuild(void); + LLPanelAvatarMeProfile(); - /*virtual*/ void refresh(); + /*virtual*/ BOOL postBuild(); - void enableControls(BOOL own_avatar); +protected: - void setWebURL(std::string url); + /*virtual*/ void onOpen(const LLSD& key); - void load(std::string url); - static void onURLKeystroke(LLLineEditor* editor, void* data); - static void onCommitLoad(LLUICtrl* ctrl, void* data); - static void onCommitURL(LLUICtrl* ctrl, void* data); - static void onClickWebProfileHelp(void *); + /*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data); - // browser observer impls - virtual void onStatusTextChange( const EventType& eventIn ); - virtual void onLocationChange( const EventType& eventIn ); + /** + * Fills Avatar status data. + */ + virtual void fillStatusData(const LLAvatarData* avatar_data); + + /*virtual*/ void resetControls(); + +protected: + + void onStatusChanged(); + void onStatusMessageChanged(); + void onUpdateAccountTextboxClicked(); + void onMyAccountTextboxClicked(); + void onPartnerEditTextboxClicked(); private: - std::string mHome; - std::string mNavigateTo; - LLWebBrowserCtrl* mWebBrowser; + + LLComboBox* mStatusCombobox; }; - -class LLPanelAvatarAdvanced : public LLPanelAvatarTab +/** +* Panel for displaying Avatar's notes and modifying friend's rights. +*/ +class LLPanelAvatarNotes + : public LLPanelProfileTab { public: - LLPanelAvatarAdvanced(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); + LLPanelAvatarNotes(); - /*virtual*/ BOOL postBuild(void); + /*virtual*/ void onOpen(const LLSD& key); - void enableControls(BOOL own_avatar); - void setWantSkills(U32 want_to_mask, const std::string& want_to_text, - U32 skills_mask, const std::string& skills_text, - const std::string& languages_text); - void getWantSkills(U32* want_to_mask, std::string& want_to_text, - U32* skills_mask, std::string& skills_text, - std::string& languages_text); + /*virtual*/ BOOL postBuild(); -private: - S32 mWantToCount; - S32 mSkillsCount; - LLCheckBoxCtrl *mWantToCheck[8]; - LLLineEditor *mWantToEdit; - LLCheckBoxCtrl *mSkillsCheck[8]; - LLLineEditor *mSkillsEdit; + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + /*virtual*/ void updateData(); + +protected: + + /*virtual*/ void resetControls(); + + /*virtual*/ void resetData(); + + /** + * Fills rights data for friends. + */ + void fillRightsData(); + + void onCommitRights(); + void onCommitNotes(); + + void onAddFriendButtonClick(); + void onIMButtonClick(); + void onCallButtonClick(); + void onTeleportButtonClick(); + void onShareButtonClick(); }; - -class LLPanelAvatarNotes : public LLPanelAvatarTab -{ -public: - LLPanelAvatarNotes(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void refresh(); - - void clearControls(); - - static void onCommitNotes(LLUICtrl* field, void* userdata); -}; - - -class LLPanelAvatarClassified : public LLPanelAvatarTab -{ -public: - LLPanelAvatarClassified(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void refresh(); - - // If can close, return TRUE. If cannot close, pop save/discard dialog - // and return FALSE. - BOOL canClose(); - - void apply(); - - BOOL titleIsValid(); - - // Delete all the classified sub-panels from the tab container - void deleteClassifiedPanels(); - - // Unpack the outline of classified for this avatar (count, names, but not - // actual data). - void processAvatarClassifiedReply(LLMessageSystem* msg, void**); - -private: - static void onClickNew(void* data); - static void onClickDelete(void* data); - - bool callbackDelete(const LLSD& notification, const LLSD& response); - bool callbackNew(const LLSD& notification, const LLSD& response); -}; - - -class LLPanelAvatarPicks : public LLPanelAvatarTab -{ -public: - LLPanelAvatarPicks(const std::string& name, const LLRect& rect, LLPanelAvatar* panel_avatar); - - /*virtual*/ BOOL postBuild(void); - - /*virtual*/ void refresh(); - - // Delete all the pick sub-panels from the tab container - void deletePickPanels(); - - // Unpack the outline of picks for this avatar (count, names, but not - // actual data). - void processAvatarPicksReply(LLMessageSystem* msg, void**); - void processAvatarClassifiedReply(LLMessageSystem* msg, void**); - -private: - static void onClickNew(void* data); - static void onClickDelete(void* data); - - bool callbackDelete(const LLSD& notification, const LLSD& response); -}; - - -class LLPanelAvatar : public LLPanel -{ -public: - LLPanelAvatar(const std::string& name, const LLRect &rect, BOOL allow_edit); - /*virtual*/ ~LLPanelAvatar(); - - /*virtual*/ BOOL postBuild(void); - - // If can close, return TRUE. If cannot close, pop save/discard dialog - // and return FALSE. - BOOL canClose(); - - void setAvatar(LLViewerObject *avatarp); - - // Fill in the avatar ID and handle some field fill-in, as well as - // button enablement. - // Pass one of the ONLINE_STATUS_foo constants above. - void setAvatarID(const LLUUID &avatar_id, const std::string &name, EOnlineStatus online_status); - - void setOnlineStatus(EOnlineStatus online_status); - - const LLUUID& getAvatarID() const { return mAvatarID; } - - void resetGroupList(); - - void sendAvatarStatisticsRequest(); - - void sendAvatarPropertiesRequest(); - void sendAvatarPropertiesUpdate(); - - void sendAvatarNotesRequest(); - void sendAvatarNotesUpdate(); - - void sendAvatarPicksRequest(); - - void selectTab(S32 tabnum); - void selectTabByName(std::string tab_name); - - BOOL haveData() { return mHaveProperties && mHaveStatistics; } - BOOL isEditable() const { return mAllowEdit; } - - static void processAvatarPropertiesReply(LLMessageSystem *msg, void **); - static void processAvatarInterestsReply(LLMessageSystem *msg, void **); - static void processAvatarGroupsReply(LLMessageSystem* msg, void**); - static void processAvatarNotesReply(LLMessageSystem *msg, void **); - static void processAvatarPicksReply(LLMessageSystem *msg, void **); - static void processAvatarClassifiedReply(LLMessageSystem *msg, void **); - - static void onClickTrack( void *userdata); - static void onClickIM( void *userdata); - static void onClickOfferTeleport( void *userdata); - static void onClickPay( void *userdata); - static void onClickAddFriend(void* userdata); - static void onClickOK( void *userdata); - static void onClickCancel( void *userdata); - static void onClickKick( void *userdata); - static void onClickFreeze( void *userdata); - static void onClickUnfreeze(void *userdata); - static void onClickCSR( void *userdata); - static void onClickMute( void *userdata); - -private: - void enableOKIfReady(); - - static bool finishKick(const LLSD& notification, const LLSD& response); - static bool finishFreeze(const LLSD& notification, const LLSD& response); - static bool finishUnfreeze(const LLSD& notification, const LLSD& response); - - static void showProfileCallback(S32 option, void *userdata); - - static void* createPanelAvatar(void* data); - static void* createFloaterAvatarInfo(void* data); - static void* createPanelAvatarSecondLife(void* data); - static void* createPanelAvatarWeb(void* data); - static void* createPanelAvatarInterests(void* data); - static void* createPanelAvatarPicks(void* data); - static void* createPanelAvatarClassified(void* data); - static void* createPanelAvatarFirstLife(void* data); - static void* createPanelAvatarNotes(void* data); - -public: - LLPanelAvatarSecondLife* mPanelSecondLife; - LLPanelAvatarAdvanced* mPanelAdvanced; - LLPanelAvatarClassified* mPanelClassified; - LLPanelAvatarPicks* mPanelPicks; - LLPanelAvatarNotes* mPanelNotes; - LLPanelAvatarFirstLife* mPanelFirstLife; - LLPanelAvatarWeb* mPanelWeb; - - LLDropTarget* mDropTarget; - - // Teen users are not allowed to see or enter data into the first life page, - // or their own about/interests text entry fields. - static BOOL sAllowFirstLife; - -private: - LLUUID mAvatarID; // for which avatar is this window? - BOOL mIsFriend; // Are we friends? - BOOL mHaveProperties; - BOOL mHaveStatistics; - // only update note if data received from database and - // note is changed from database version - bool mHaveNotes; - std::string mLastNotes; - LLTabContainer* mTab; - BOOL mAllowEdit; - - typedef std::list panel_list_t; - static panel_list_t sAllPanels; -}; - -// helper funcs -void add_left_label(LLPanel *panel, const std::string& name, S32 y); - - #endif // LL_LLPANELAVATAR_H diff --git a/indra/newview/llpanelavatartag.cpp b/indra/newview/llpanelavatartag.cpp new file mode 100644 index 0000000000..e66c36287b --- /dev/null +++ b/indra/newview/llpanelavatartag.cpp @@ -0,0 +1,129 @@ +/** + * @file llpanelavatartag.cpp + * @brief Avatar tag panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelavatartag.h" + +#include "lluictrlfactory.h" +#include "llavatariconctrl.h" +#include "lltextbox.h" + +LLPanelAvatarTag::LLPanelAvatarTag(const LLUUID& key, const std::string im_time) + : LLPanel() + , mAvatarId(LLUUID::null) +// , mFadeTimer() +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_tag.xml"); + setLeftButtonClickCallback(boost::bind(&LLPanelAvatarTag::onClick, this)); + setAvatarId(key); + setTime(im_time); +} + +LLPanelAvatarTag::~LLPanelAvatarTag() +{ + // Name callbacks will be automatically disconnected since LLPanel is trackable +} + +BOOL LLPanelAvatarTag::postBuild() +{ + mIcon = getChild("avatar_tag_icon"); + mName = getChild("sender_tag_name"); + mTime = getChild("tag_time"); + return TRUE; +} + +void LLPanelAvatarTag::draw() +{ + + ///TODO: ANGELA do something similar to fade the panel out +/* // HACK: assuming tooltip background is in ToolTipBGColor, perform fade out + LLColor4 bg_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" ); + if (tooltip_vis) + { + mToolTipFadeTimer.stop(); + mToolTip->setBackgroundColor(bg_color); + } + else + { + if (!mToolTipFadeTimer.getStarted()) + { + mToolTipFadeTimer.start(); + } + F32 tool_tip_fade_time = gSavedSettings.getF32("ToolTipFadeTime"); + bg_color.mV[VALPHA] = clamp_rescale(mToolTipFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, bg_color.mV[VALPHA], 0.f); + mToolTip->setBackgroundColor(bg_color); + } + + // above interpolation of bg_color alpha is guaranteed to reach 0.f exactly + mToolTip->setVisible( bg_color.mV[VALPHA] != 0.f ); + */ +} +void LLPanelAvatarTag::setName(const std::string& name) +{ + if (mName) + mName->setText(name); +} + +void LLPanelAvatarTag::setTime(const std::string& time) +{ + if (mTime) + mTime->setText(time); +} + + +void LLPanelAvatarTag::setAvatarId(const LLUUID& avatar_id) +{ + mAvatarId = avatar_id; + if (mIcon) + { + mIcon->setValue(avatar_id); + } + setName(std::string(mIcon->getFirstName()+ " "+ mIcon->getLastName())); +} + +boost::signals2::connection LLPanelAvatarTag::setLeftButtonClickCallback( + const commit_callback_t& cb) +{ + return mCommitSignal.connect(cb); +} + +BOOL LLPanelAvatarTag::handleMouseDown(S32 x, S32 y, MASK mask) +{ + onCommit(); + return TRUE; +} + +void LLPanelAvatarTag::onClick() +{ + // Do the on click stuff. +} diff --git a/indra/newview/llpanelavatartag.h b/indra/newview/llpanelavatartag.h new file mode 100644 index 0000000000..d68b0d7299 --- /dev/null +++ b/indra/newview/llpanelavatartag.h @@ -0,0 +1,93 @@ +/** + * @file llpanelavatartag.h + * @brief Avatar row panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELAVATARTAG_H +#define LL_LLPANELAVATARTAG_H + +#include "llpanel.h" +#include "llavatarpropertiesprocessor.h" + +class LLAvatarIconCtrl; +class LLTextBox; + +/** + * Avatar Tag panel. + * + * Test. + * + * Contains avatar name + * Provide methods for setting avatar id, state, muted status and speech power. + */ +class LLPanelAvatarTag : public LLPanel +{ +public: + LLPanelAvatarTag(const LLUUID& key, const std::string im_time); + virtual ~LLPanelAvatarTag(); + + /** + * Set avatar ID. + * + * After the ID is set, it is possible to track the avatar status and get its name. + */ + void setAvatarId(const LLUUID& avatar_id); + void setTime (const std::string& time); + + const LLUUID& getAvatarId() const { return mAvatarId; } + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + + virtual boost::signals2::connection setLeftButtonClickCallback( + const commit_callback_t& cb); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + + void onClick(); +private: + void setName(const std::string& name); + + /** + * Called by LLCacheName when the avatar name gets updated. + */ + void nameUpdatedCallback( + const LLUUID& id, + const std::string& first, + const std::string& last, + BOOL is_group); + + LLAvatarIconCtrl* mIcon; /// status tracking avatar icon + LLTextBox* mName; /// displays avatar name + LLTextBox* mTime; /// displays time + LLUUID mAvatarId; +// LLFrameTimer mFadeTimer; +}; + +#endif diff --git a/indra/newview/llpanelclassified.cpp b/indra/newview/llpanelclassified.cpp index 9e4f9709a8..c77d089af7 100644 --- a/indra/newview/llpanelclassified.cpp +++ b/indra/newview/llpanelclassified.cpp @@ -40,11 +40,14 @@ #include "lldir.h" #include "lldispatcher.h" +#include "llfloaterreg.h" #include "llparcel.h" +#include "lltabcontainer.h" #include "message.h" #include "llagent.h" #include "llalertdialog.h" +#include "llavataractions.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llclassifiedflags.h" @@ -52,13 +55,10 @@ #include "llcommandhandler.h" // for classified HTML detail page click tracking #include "llviewercontrol.h" #include "lllineeditor.h" -#include "llfloateravatarinfo.h" -#include "llfloaterclassified.h" -#include "lltabcontainervertical.h" #include "lltextbox.h" #include "llcombobox.h" -#include "llviewertexteditor.h" #include "lltexturectrl.h" +#include "lltexteditor.h" #include "lluiconstants.h" #include "llurldispatcher.h" // for classified HTML detail click teleports #include "lluictrlfactory.h" @@ -70,6 +70,7 @@ #include "llviewerregion.h" #include "llviewerwindow.h" // for window width, height #include "llappviewer.h" // abortQuit() +#include "lltrans.h" const S32 MINIMUM_PRICE_FOR_LISTING = 50; // L$ const S32 MATURE_UNDEFINED = -1; @@ -141,7 +142,7 @@ public: const bool from_search = true; LLPanelClassified::sendClassifiedClickMessage(classified_id, "teleport", from_search); // Invoke teleport - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = true; return LLURLDispatcher::dispatch(url, web, trusted_browser); } @@ -151,7 +152,7 @@ LLClassifiedTeleportHandler gClassifiedTeleportHandler; */ LLPanelClassified::LLPanelClassified(bool in_finder, bool from_search) -: LLPanel(std::string("Classified Panel")), +: LLPanel(), mInFinder(in_finder), mFromSearch(from_search), mDirty(false), @@ -231,44 +232,36 @@ void LLPanelClassified::reset() BOOL LLPanelClassified::postBuild() { mSnapshotCtrl = getChild("snapshot_ctrl"); - mSnapshotCtrl->setCommitCallback(onCommitAny); - mSnapshotCtrl->setCallbackUserData(this); + mSnapshotCtrl->setCommitCallback(onCommitAny, this); mSnapshotSize = mSnapshotCtrl->getRect(); mNameEditor = getChild("given_name_editor"); mNameEditor->setMaxTextLength(DB_PARCEL_NAME_LEN); mNameEditor->setCommitOnFocusLost(TRUE); mNameEditor->setFocusReceivedCallback(focusReceived, this); - mNameEditor->setCommitCallback(onCommitAny); - mNameEditor->setCallbackUserData(this); + mNameEditor->setCommitCallback(onCommitAny, this); mNameEditor->setPrevalidate( LLLineEditor::prevalidateASCII ); mDescEditor = getChild("desc_editor"); mDescEditor->setCommitOnFocusLost(TRUE); mDescEditor->setFocusReceivedCallback(focusReceived, this); - mDescEditor->setCommitCallback(onCommitAny); - mDescEditor->setCallbackUserData(this); - mDescEditor->setTabsToNextField(TRUE); - + mDescEditor->setCommitCallback(onCommitAny, this); + mLocationEditor = getChild("location_editor"); mSetBtn = getChild( "set_location_btn"); - mSetBtn->setClickedCallback(onClickSet); - mSetBtn->setCallbackUserData(this); + mSetBtn->setClickedCallback(onClickSet, this); mTeleportBtn = getChild( "classified_teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(onClickTeleport, this); mMapBtn = getChild( "classified_map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(onClickMap, this); if(mInFinder) { mProfileBtn = getChild( "classified_profile_btn"); - mProfileBtn->setClickedCallback(onClickProfile); - mProfileBtn->setCallbackUserData(this); + mProfileBtn->setClickedCallback(onClickProfile, this); } mCategoryCombo = getChild( "classified_category_combo"); @@ -277,16 +270,14 @@ BOOL LLPanelClassified::postBuild() iter != LLClassifiedInfo::sCategories.end(); iter++) { - mCategoryCombo->add(iter->second, (void *)((intptr_t)iter->first), ADD_BOTTOM); + mCategoryCombo->add(LLTrans::getString(iter->second), (void *)((intptr_t)iter->first), ADD_BOTTOM); } mCategoryCombo->setCurrentByIndex(0); - mCategoryCombo->setCommitCallback(onCommitAny); - mCategoryCombo->setCallbackUserData(this); + mCategoryCombo->setCommitCallback(onCommitAny, this); mMatureCombo = getChild( "classified_mature_check"); mMatureCombo->setCurrentByIndex(0); - mMatureCombo->setCommitCallback(onCommitAny); - mMatureCombo->setCallbackUserData(this); + mMatureCombo->setCommitCallback(onCommitAny, this); if (gAgent.wantsPGOnly()) { // Teens don't get to set mature flag. JC @@ -297,13 +288,11 @@ BOOL LLPanelClassified::postBuild() if (!mInFinder) { mAutoRenewCheck = getChild( "auto_renew_check"); - mAutoRenewCheck->setCommitCallback(onCommitAny); - mAutoRenewCheck->setCallbackUserData(this); + mAutoRenewCheck->setCommitCallback(onCommitAny, this); } mUpdateBtn = getChild("classified_update_btn"); - mUpdateBtn->setClickedCallback(onClickUpdate); - mUpdateBtn->setCallbackUserData(this); + mUpdateBtn->setClickedCallback(onClickUpdate, this); if (!mInFinder) { @@ -360,7 +349,7 @@ bool LLPanelClassified::saveCallback(const LLSD& notification, const LLSD& respo LLFloater* parent_floater = gFloaterView->getParentFloater(this); if (parent_floater) { - parent_floater->close(); + parent_floater->closeFloater(); } } break; @@ -455,10 +444,11 @@ void LLPanelClassified::setClickThrough(const LLUUID& classified_id, if (self->mClickThroughText) { - std::string msg = llformat("Clicks: %d teleport, %d map, %d profile", - self->mTeleportClicksNew + self->mTeleportClicksOld, - self->mMapClicksNew + self->mMapClicksOld, - self->mProfileClicksNew + self->mProfileClicksOld); + LLStringUtil::format_map_t args; + args["[TELEPORT]"] = llformat ("%d", self->mTeleportClicksNew + self->mTeleportClicksOld); + args["[MAP]"] = llformat ("%d", self->mMapClicksNew + self->mMapClicksOld); + args["[PROFILE]"] = llformat ("%d", self->mProfileClicksNew + self->mProfileClicksOld); + std::string msg = LLTrans::getString ("ClassifiedClicksTxt", args); self->mClickThroughText->setText(msg); } } @@ -623,7 +613,6 @@ void LLPanelClassified::processClassifiedInfoReply(LLMessageSystem *msg, void ** U32 date = 0; msg->getU32Fast(_PREHASH_Data, _PREHASH_CreationDate, date); time_t tim = date; - tm *now=localtime(&tim); // future use U32 expiration_date = 0; @@ -674,9 +663,13 @@ void LLPanelClassified::processClassifiedInfoReply(LLMessageSystem *msg, void ** self->mAutoRenewCheck->set(auto_renew); } - std::string datestr = llformat("%02d/%02d/%d", now->tm_mon+1, now->tm_mday, now->tm_year+1900); + std::string dateStr = self->getString("dateStr"); + LLSD substitution; + substitution["datetime"] = (S32) tim; + LLStringUtil::format (dateStr, substitution); + LLStringUtil::format_map_t string_args; - string_args["[DATE]"] = datestr; + string_args["[DATE]"] = dateStr; string_args["[AMT]"] = llformat("%d", price_for_listing); self->childSetText("classified_info_text", self->getString("ad_placed_paid", string_args)); @@ -846,7 +839,7 @@ void LLPanelClassified::gotMature() if (mPaidFor) { LLNotification::Params params("PublishClassified"); - params.functor(boost::bind(&LLPanelClassified::confirmPublish, this, _1, _2)); + params.functor.function(boost::bind(&LLPanelClassified::confirmPublish, this, _1, _2)); LLNotifications::instance().forceResponse(params, 0); } else @@ -937,12 +930,12 @@ bool LLPanelClassified::confirmPublish(const LLSD& notification, const LLSD& res void LLPanelClassified::onClickTeleport(void* data) { LLPanelClassified* self = (LLPanelClassified*)data; - - if (!self->mPosGlobal.isExactlyZero()) + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + + if (!self->mPosGlobal.isExactlyZero()&&worldmap_instance) { - gAgent.teleportViaLocation(self->mPosGlobal); - gFloaterWorldMap->trackLocation(self->mPosGlobal); - + gAgent.teleportViaLocation(self->mPosGlobal); + worldmap_instance->trackLocation(self->mPosGlobal); self->sendClassifiedClickMessage("teleport"); } } @@ -952,9 +945,12 @@ void LLPanelClassified::onClickTeleport(void* data) void LLPanelClassified::onClickMap(void* data) { LLPanelClassified* self = (LLPanelClassified*)data; - gFloaterWorldMap->trackLocation(self->mPosGlobal); - LLFloaterWorldMap::show(NULL, TRUE); - + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if(worldmap_instance) + { + worldmap_instance->trackLocation(self->mPosGlobal); + LLFloaterReg::showInstance("world_map", "center"); + } self->sendClassifiedClickMessage("map"); } @@ -962,7 +958,7 @@ void LLPanelClassified::onClickMap(void* data) void LLPanelClassified::onClickProfile(void* data) { LLPanelClassified* self = (LLPanelClassified*)data; - LLFloaterAvatarInfo::showFromDirectory(self->mCreatorID); + LLAvatarActions::showProfile(self->mCreatorID); self->sendClassifiedClickMessage("profile"); } @@ -984,7 +980,7 @@ void LLPanelClassified::onClickSet(void* data) self->mPosGlobal = gAgent.getPositionGlobal(); std::string location_text; - std::string regionName = "(will update after publish)"; + std::string regionName = LLTrans::getString("ClassifiedUpdateAfterPublish"); LLViewerRegion* pRegion = gAgent.getRegion(); if (pRegion) { @@ -1065,7 +1061,7 @@ void LLPanelClassified::sendClassifiedClickMessage(const std::string& type) //////////////////////////////////////////////////////////////////////////////////////////// LLFloaterPriceForListing::LLFloaterPriceForListing() -: LLFloater(std::string("PriceForListing")), +: LLFloater(LLSD()), mCallback(NULL), mUserData(NULL) { } @@ -1101,7 +1097,7 @@ void LLFloaterPriceForListing::show( void (*callback)(S32, std::string, void*), LLFloaterPriceForListing *self = new LLFloaterPriceForListing(); // Builds and adds to gFloaterView - LLUICtrlFactory::getInstance()->buildFloater(self, "floater_price_for_listing.xml"); + LLUICtrlFactory::getInstance()->buildFloater(self, "floater_price_for_listing.xml", NULL); self->center(); self->mCallback = callback; @@ -1129,7 +1125,7 @@ void LLFloaterPriceForListing::buttonCore(S32 button, void* data) { std::string text = self->childGetText("price_edit"); self->mCallback(button, text, self->mUserData); - self->close(); + self->closeFloater(); } } diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index a2f3d9e12c..5da646497b 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -36,37 +36,33 @@ #include "llpanelcontents.h" // linden library includes +#include "lleconomy.h" #include "llerror.h" +#include "llfloaterreg.h" +#include "llfontgl.h" +#include "llmaterialtable.h" +#include "llpermissionsflags.h" #include "llrect.h" #include "llstring.h" -#include "llmaterialtable.h" -#include "llfontgl.h" +#include "llui.h" #include "m3math.h" -#include "llpermissionsflags.h" -#include "lleconomy.h" #include "material_codes.h" // project includes -#include "llui.h" -#include "llspinctrl.h" -#include "llcheckboxctrl.h" -#include "lltextbox.h" -#include "llbutton.h" -#include "llcombobox.h" -#include "llfloaterbulkpermission.h" - #include "llagent.h" -#include "llviewerwindow.h" -#include "llworld.h" -#include "llviewerobject.h" -#include "llviewerregion.h" +#include "llfloaterbulkpermission.h" +#include "llpanelinventory.h" +#include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" -#include "llpreviewscript.h" #include "lltool.h" -#include "lltoolmgr.h" #include "lltoolcomp.h" -#include "llpanelinventory.h" +#include "lltoolmgr.h" +#include "lltrans.h" +#include "llviewerobject.h" +#include "llviewerregion.h" +#include "llviewerwindow.h" +#include "llworld.h" // // Imported globals @@ -86,11 +82,13 @@ BOOL LLPanelContents::postBuild() childSetAction("button new script",&LLPanelContents::onClickNewScript, this); childSetAction("button permissions",&LLPanelContents::onClickPermissions, this); + mPanelInventory = getChild("contents_inventory"); + return TRUE; } -LLPanelContents::LLPanelContents(const std::string& name) - : LLPanel(name), +LLPanelContents::LLPanelContents() + : LLPanel(), mPanelInventory(NULL) { } @@ -171,7 +169,7 @@ void LLPanelContents::onClickNewScript(void *userdata) LLUUID::null, LLAssetType::AT_LSL_TEXT, LLInventoryType::IT_LSL, - std::string("New Script"), + LLTrans::getString("PanelContentsNewScript"), desc, LLSaleInfo::DEFAULT, LLViewerInventoryItem::II_FLAGS_NONE, @@ -185,21 +183,7 @@ void LLPanelContents::onClickNewScript(void *userdata) // viewer so the viewer can auto-open the script and start // editing ASAP. #if 0 - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewScriptRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - - LLLiveLSLEditor* editor; - editor = new LLLiveLSLEditor("script ed", - rect, - "Script: New Script", - object->mID, - LLUUID::null); - editor->open(); /*Flawfinder: ignore*/ - - // keep onscreen - gFloaterView->adjustToFitScreen(editor, FALSE); + LLFloaterReg::showInstance("preview_scriptedit", LLSD(inv_item->getUUID()), TAKE_FOCUS_YES); #endif } } @@ -209,5 +193,5 @@ void LLPanelContents::onClickNewScript(void *userdata) void LLPanelContents::onClickPermissions(void *userdata) { LLPanelContents* self = (LLPanelContents*)userdata; - gFloaterView->getParentFloater(self)->addDependentFloater(LLFloaterBulkPermission::showInstance()); + gFloaterView->getParentFloater(self)->addDependentFloater(LLFloaterReg::showInstance("bulk_perms")); } diff --git a/indra/newview/llpanelcontents.h b/indra/newview/llpanelcontents.h index ea06707494..de1914bff9 100644 --- a/indra/newview/llpanelcontents.h +++ b/indra/newview/llpanelcontents.h @@ -46,7 +46,7 @@ class LLPanelContents : public LLPanel { public: virtual BOOL postBuild(); - LLPanelContents(const std::string& name); + LLPanelContents(); virtual ~LLPanelContents(); void refresh(); diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp index e93a5be8ed..08a50d4b6e 100644 --- a/indra/newview/llpanelface.cpp +++ b/indra/newview/llpanelface.cpp @@ -62,6 +62,7 @@ #include "llviewerobject.h" #include "llviewerstats.h" #include "lluictrlfactory.h" +#include "llpluginclassmedia.h" // // Methods @@ -87,11 +88,10 @@ BOOL LLPanelFace::postBuild() if(mTextureCtrl) { mTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectTexture" ))); - mTextureCtrl->setCommitCallback( LLPanelFace::onCommitTexture ); - mTextureCtrl->setOnCancelCallback( LLPanelFace::onCancelTexture ); - mTextureCtrl->setOnSelectCallback( LLPanelFace::onSelectTexture ); - mTextureCtrl->setDragCallback(LLPanelFace::onDragTexture); - mTextureCtrl->setCallbackUserData( this ); + mTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitTexture, this, _2) ); + mTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelTexture, this, _2) ); + mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) ); + mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, _2)); mTextureCtrl->setFollowsTop(); mTextureCtrl->setFollowsLeft(); // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode @@ -118,10 +118,9 @@ BOOL LLPanelFace::postBuild() mColorSwatch = getChild("colorswatch"); if(mColorSwatch) { - mColorSwatch->setCommitCallback(LLPanelFace::onCommitColor); - mColorSwatch->setOnCancelCallback(LLPanelFace::onCancelColor); - mColorSwatch->setOnSelectCallback(LLPanelFace::onSelectColor); - mColorSwatch->setCallbackUserData( this ); + mColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitColor, this, _2)); + mColorSwatch->setOnCancelCallback(boost::bind(&LLPanelFace::onCancelColor, this, _2)); + mColorSwatch->setOnSelectCallback(boost::bind(&LLPanelFace::onSelectColor, this, _2)); mColorSwatch->setFollowsTop(); mColorSwatch->setFollowsLeft(); mColorSwatch->setCanApplyImmediately(TRUE); @@ -137,8 +136,7 @@ BOOL LLPanelFace::postBuild() mCtrlColorTransp = getChild("ColorTrans"); if(mCtrlColorTransp) { - mCtrlColorTransp->setCommitCallback(LLPanelFace::onCommitAlpha); - mCtrlColorTransp->setCallbackUserData(this); + mCtrlColorTransp->setCommitCallback(boost::bind(&LLPanelFace::onCommitAlpha, this, _2)); mCtrlColorTransp->setPrecision(0); mCtrlColorTransp->setFollowsTop(); mCtrlColorTransp->setFollowsLeft(); @@ -147,23 +145,20 @@ BOOL LLPanelFace::postBuild() mCheckFullbright = getChild("checkbox fullbright"); if (mCheckFullbright) { - mCheckFullbright->setCommitCallback(LLPanelFace::onCommitFullbright); - mCheckFullbright->setCallbackUserData( this ); + mCheckFullbright->setCommitCallback(LLPanelFace::onCommitFullbright, this); } mComboTexGen = getChild("combobox texgen"); if(mComboTexGen) { - mComboTexGen->setCommitCallback(LLPanelFace::onCommitTexGen); + mComboTexGen->setCommitCallback(LLPanelFace::onCommitTexGen, this); mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP); - mComboTexGen->setCallbackUserData( this ); } mCtrlGlow = getChild("glow"); if(mCtrlGlow) { - mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow); - mCtrlGlow->setCallbackUserData(this); + mCtrlGlow->setCommitCallback(LLPanelFace::onCommitGlow, this); } childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this); @@ -183,8 +178,8 @@ BOOL LLPanelFace::postBuild() return TRUE; } -LLPanelFace::LLPanelFace(const std::string& name) -: LLPanel(name) +LLPanelFace::LLPanelFace() +: LLPanel() { } @@ -392,11 +387,6 @@ void LLPanelFace::getState() childSetEnabled("button align",FALSE); //mBtnAutoFix->setEnabled ( FALSE ); - if(LLViewerMedia::hasMedia()) - { - childSetEnabled("textbox autofix",editable); - childSetEnabled("button align",editable); - } //if ( LLMediaEngine::getInstance()->getMediaRenderer () ) // if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () ) // { @@ -417,7 +407,7 @@ void LLPanelFace::getState() { LLUUID get(LLViewerObject* object, S32 te) { - LLViewerImage* image = object->getTEImage(te); + LLViewerTexture* image = object->getTEImage(te); return image ? image->getID() : LLUUID::null; } } func; @@ -453,7 +443,15 @@ void LLPanelFace::getState() } } } + + if(LLViewerMedia::textureHasMedia(id)) + { + childSetEnabled("textbox autofix",editable); + childSetEnabled("button align",editable); + } + } + LLAggregatePermissions texture_perms; if(texture_ctrl) @@ -807,32 +805,25 @@ F32 LLPanelFace::valueGlow(LLViewerObject* object, S32 face) } -// static -void LLPanelFace::onCommitColor(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCommitColor(const LLSD& data) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendColor(); + sendColor(); } -// static -void LLPanelFace::onCommitAlpha(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCommitAlpha(const LLSD& data) { - LLPanelFace* self = (LLPanelFace*) userdata; - self->sendAlpha(); + sendAlpha(); } -// static -void LLPanelFace::onCancelColor(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCancelColor(const LLSD& data) { LLSelectMgr::getInstance()->selectionRevertColors(); } -// static -void LLPanelFace::onSelectColor(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onSelectColor(const LLSD& data) { - LLPanelFace* self = (LLPanelFace*) userdata; LLSelectMgr::getInstance()->saveSelectedObjectColors(); - self->sendColor(); + sendColor(); } // static @@ -871,7 +862,7 @@ void LLPanelFace::onCommitGlow(LLUICtrl* ctrl, void* userdata) } // static -BOOL LLPanelFace::onDragTexture(LLUICtrl*, LLInventoryItem* item, void*) +BOOL LLPanelFace::onDragTexture(LLInventoryItem* item) { BOOL accept = TRUE; for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin(); @@ -888,28 +879,21 @@ BOOL LLPanelFace::onDragTexture(LLUICtrl*, LLInventoryItem* item, void*) return accept; } -// static -void LLPanelFace::onCommitTexture( LLUICtrl* ctrl, void* userdata ) +void LLPanelFace::onCommitTexture( const LLSD& data ) { - LLPanelFace* self = (LLPanelFace*) userdata; - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT ); - - self->sendTexture(); + sendTexture(); } -// static -void LLPanelFace::onCancelTexture(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onCancelTexture(const LLSD& data) { LLSelectMgr::getInstance()->selectionRevertTextures(); } -// static -void LLPanelFace::onSelectTexture(LLUICtrl* ctrl, void* userdata) +void LLPanelFace::onSelectTexture(const LLSD& data) { - LLPanelFace* self = (LLPanelFace*) userdata; LLSelectMgr::getInstance()->saveSelectedObjectTextures(); - self->sendTexture(); + sendTexture(); } @@ -939,14 +923,18 @@ struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor { virtual bool apply(LLViewerObject* object, S32 te) { + // TODO: the media impl pointer should actually be stored by the texture + viewer_media_t pMediaImpl = LLViewerMedia::getMediaImplFromTextureID(object->getTE ( te )->getID()); // only do this if it's a media texture - if ( object->getTE ( te )->getID() == LLViewerMedia::getMediaTextureID() ) + if ( pMediaImpl.notNull()) { - S32 media_width, media_height; - S32 texture_width, texture_height; - if ( LLViewerMedia::getMediaSize( &media_width, &media_height ) - && LLViewerMedia::getTextureSize( &texture_width, &texture_height ) ) + LLPluginClassMedia *media = pMediaImpl->getMediaPlugin(); + if(media) { + S32 media_width = media->getWidth(); + S32 media_height = media->getHeight(); + S32 texture_width = media->getTextureWidth(); + S32 texture_height = media->getTextureHeight(); F32 scale_s = (F32)media_width / (F32)texture_width; F32 scale_t = (F32)media_height / (F32)texture_height; diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h index a2ead0c8a2..9600129696 100644 --- a/indra/newview/llpanelface.h +++ b/indra/newview/llpanelface.h @@ -52,7 +52,7 @@ class LLPanelFace : public LLPanel { public: virtual BOOL postBuild(); - LLPanelFace(const std::string& name); + LLPanelFace(); virtual ~LLPanelFace(); void refresh(); @@ -70,17 +70,18 @@ protected: void sendFullbright(); // applies and sends full bright void sendGlow(); - // this function is to return TRUE if the dra should succeed. - static BOOL onDragTexture(LLUICtrl* ctrl, LLInventoryItem* item, void* ud); + // this function is to return TRUE if the drag should succeed. + static BOOL onDragTexture(LLInventoryItem* item); - static void onCommitTexture( LLUICtrl* ctrl, void* userdata); - static void onCancelTexture( LLUICtrl* ctrl, void* userdata); - static void onSelectTexture( LLUICtrl* ctrl, void* userdata); - static void onCommitTextureInfo( LLUICtrl* ctrl, void* userdata); - static void onCommitColor( LLUICtrl* ctrl, void* userdata); - static void onCommitAlpha( LLUICtrl* ctrl, void* userdata); - static void onCancelColor( LLUICtrl* ctrl, void* userdata); - static void onSelectColor( LLUICtrl* ctrl, void* userdata); + void onCommitTexture(const LLSD& data); + void onCancelTexture(const LLSD& data); + void onSelectTexture(const LLSD& data); + void onCommitColor(const LLSD& data); + void onCommitAlpha(const LLSD& data); + void onCancelColor(const LLSD& data); + void onSelectColor(const LLSD& data); + + static void onCommitTextureInfo( LLUICtrl* ctrl, void* userdata); static void onCommitBump( LLUICtrl* ctrl, void* userdata); static void onCommitTexGen( LLUICtrl* ctrl, void* userdata); static void onCommitShiny( LLUICtrl* ctrl, void* userdata); diff --git a/indra/newview/llpanelgroup.cpp b/indra/newview/llpanelgroup.cpp index d9d796fd9e..4cbb018ce9 100644 --- a/indra/newview/llpanelgroup.cpp +++ b/indra/newview/llpanelgroup.cpp @@ -33,12 +33,7 @@ #include "llpanelgroup.h" -#include "llagent.h" #include "llbutton.h" -#include "llpanelgroupgeneral.h" -#include "llpanelgrouproles.h" -#include "llpanelgrouplandmoney.h" -#include "llpanelgroupnotices.h" #include "lltabcontainer.h" #include "lltextbox.h" #include "llviewermessage.h" @@ -46,17 +41,31 @@ #include "llviewerwindow.h" #include "llappviewer.h" #include "llnotifications.h" +#include "llfloaterreg.h" +#include "llfloater.h" -// static -void* LLPanelGroupTab::createTab(void* data) +#include "llsidetraypanelcontainer.h" + +#include "llpanelgroupnotices.h" +#include "llpanelgroupgeneral.h" + +#include "llsidetray.h" +#include "llaccordionctrltab.h" + +static LLRegisterPanelClassWrapper t_panel_group("panel_group_info_sidetray"); + + + +LLPanelGroupTab::LLPanelGroupTab() + : LLPanel(), + mAllowEdit(TRUE), + mHasModal(FALSE) { - LLUUID* group_id = static_cast(data); - return new LLPanelGroupTab("panel group tab", *group_id); + mGroupID = LLUUID::null; } LLPanelGroupTab::~LLPanelGroupTab() { - mObservers.clear(); } BOOL LLPanelGroupTab::isVisibleByAgent(LLAgent* agentp) @@ -67,48 +76,10 @@ BOOL LLPanelGroupTab::isVisibleByAgent(LLAgent* agentp) BOOL LLPanelGroupTab::postBuild() { - // Hook up the help button callback. - LLButton* button = getChild("help_button"); - if (button) - { - button->setClickedCallback(onClickHelp); - button->setCallbackUserData(this); - } - - mHelpText = getString("help_text"); return TRUE; } -void LLPanelGroupTab::addObserver(LLPanelGroupTabObserver *obs) -{ - mObservers.insert(obs); -} -void LLPanelGroupTab::removeObserver(LLPanelGroupTabObserver *obs) -{ - mObservers.erase(obs); -} - -void LLPanelGroupTab::notifyObservers() -{ - - for (observer_list_t::iterator iter = mObservers.begin(); - iter != mObservers.end(); ) - { - LLPanelGroupTabObserver* observer = *iter; - observer->tabChanged(); - - // safe way to incrament since changed may delete entries! (@!##%@!@&*!) - iter = mObservers.upper_bound(observer); - } -} - -// static -void LLPanelGroupTab::onClickHelp(void* user_data) -{ - LLPanelGroupTab* self = static_cast(user_data); - self->handleClickHelp(); -} void LLPanelGroupTab::handleClickHelp() { @@ -125,450 +96,281 @@ void LLPanelGroupTab::handleClickHelp() } } -LLPanelGroup::LLPanelGroup(const std::string& filename, - const std::string& name, - const LLUUID& group_id, - const std::string& initial_tab_selected) -: LLPanel(name, LLRect(), FALSE), - LLGroupMgrObserver( group_id ), - mCurrentTab( NULL ), - mRequestedTab( NULL ), - mTabContainer( NULL ), - mIgnoreTransition( FALSE ), - mForceClose( FALSE ), - mInitialTab(initial_tab_selected), - mAllowEdit( TRUE ), - mShowingNotifyDialog( FALSE ) +LLPanelGroup::LLPanelGroup() +: LLPanel() + ,LLGroupMgrObserver( LLUUID() ) + ,mAllowEdit(TRUE) { // Set up the factory callbacks. - mFactoryMap["general_tab"] = LLCallbackMap(LLPanelGroupGeneral::createTab, - &mID); - mFactoryMap["roles_tab"] = LLCallbackMap(LLPanelGroupRoles::createTab, - &mID); - mFactoryMap["notices_tab"] = LLCallbackMap(LLPanelGroupNotices::createTab, - &mID); - mFactoryMap["land_money_tab"]= LLCallbackMap(LLPanelGroupLandMoney::createTab, - &mID); // Roles sub tabs - mFactoryMap["members_sub_tab"] = LLCallbackMap(LLPanelGroupMembersSubTab::createTab, &mID); - mFactoryMap["roles_sub_tab"] = LLCallbackMap(LLPanelGroupRolesSubTab::createTab, &mID); - mFactoryMap["actions_sub_tab"] = LLCallbackMap(LLPanelGroupActionsSubTab::createTab, &mID); - LLGroupMgr::getInstance()->addObserver(this); - // Pass on construction of this panel to the control factory. - LLUICtrlFactory::getInstance()->buildPanel(this, filename, &getFactoryMap()); - mFilename = filename; } + LLPanelGroup::~LLPanelGroup() { LLGroupMgr::getInstance()->removeObserver(this); - - int i; - int tab_count = mTabContainer->getTabCount(); - - for (i = tab_count - 1; i >=0; --i) - { - LLPanelGroupTab* panelp = - (LLPanelGroupTab*) mTabContainer->getPanelByIndex(i); - - if ( panelp ) panelp->removeObserver(this); - } } -void LLPanelGroup::updateTabVisibility() +void LLPanelGroup::onOpen(const LLSD& key) { - S32 i; - S32 tab_count = mTabContainer->getTabCount(); - - for (i = tab_count - 1; i >=0; --i) + if(!key.has("group_id")) + return; + + LLUUID group_id = key["group_id"]; + if(!key.has("action")) { - LLPanelGroupTab* panelp = - (LLPanelGroupTab*) mTabContainer->getPanelByIndex(i); - - BOOL visible = panelp->isVisibleByAgent(&gAgent) || gAgent.isGodlike(); - mTabContainer->enableTabButton(i, visible); - - if ( !visible && mCurrentTab == panelp ) - { - //we are disabling the currently selected tab - //select the previous one - mTabContainer->selectPrevTab(); - mCurrentTab = - (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); - } + setGroupID(group_id); + return; } + + std::string str_action = key["action"]; + + if(str_action == "refresh") + { + if(mID == group_id || group_id == LLUUID::null) + refreshData(); + } + else if(str_action == "close") + { + onBackBtnClick(); + } + else if(str_action == "create") + { + setGroupID(LLUUID::null); + } + else if(str_action == "refresh_notices") + { + LLPanelGroupNotices* panel_notices = findChild("group_notices_tab_panel"); + if(panel_notices) + panel_notices->refreshNotices(); + } + } - - BOOL LLPanelGroup::postBuild() { - mTabContainer = getChild("group_tab_container"); - - if (mTabContainer) - { - // Select the initial tab specified via constructor - const BOOL recurse = TRUE; - LLPanelGroupTab* tabp = - getChild(mInitialTab, recurse); - - if (!tabp) - { - //our initial tab selection was invalid, just select the - //first tab then or default to selecting the initial - //selected tab specified in the layout file - tabp = (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); - - //no tab was initially selected through constructor - //or the XML, select the first tab - if (!tabp) - { - mTabContainer->selectFirstTab(); - tabp = (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); - } - } - else - { - mTabContainer->selectTabPanel(tabp); - } - - mCurrentTab = tabp; - - // Add click callbacks. - S32 i; - S32 tab_count = mTabContainer->getTabCount(); - - for (i = tab_count - 1; i >=0; --i) - { - LLPanel* tab_panel = mTabContainer->getPanelByIndex(i); - LLPanelGroupTab* panelp =(LLPanelGroupTab*)tab_panel; // bit of a hack - - // Pass on whether or not to allow edit to tabs. - panelp->setAllowEdit(mAllowEdit); - panelp->addObserver(this); - - mTabContainer->setTabChangeCallback(panelp, onClickTab); - mTabContainer->setTabUserData(panelp, this); - } - updateTabVisibility(); - - // Act as though this tab was just activated. - mCurrentTab->activate(); - } - mDefaultNeedsApplyMesg = getString("default_needs_apply_text"); mWantApplyMesg = getString("want_apply_text"); - LLButton* button = getChild("btn_ok"); - if (button) - { - button->setClickedCallback(onBtnOK); - button->setCallbackUserData(this); - button->setVisible(mAllowEdit); - } - - button = getChild("btn_cancel"); - if (button) - { - button->setClickedCallback(onBtnCancel); - button->setCallbackUserData(this); - button->setVisible(mAllowEdit); - } + LLButton* button; button = getChild("btn_apply"); - if (button) - { - button->setClickedCallback(onBtnApply); - button->setVisible(mAllowEdit); - button->setEnabled(FALSE); + button->setClickedCallback(onBtnApply, this); + button->setVisible(true); + button->setEnabled(false); - mApplyBtn = button; - } button = getChild("btn_refresh"); - if (button) - { - button->setClickedCallback(onBtnRefresh); - button->setCallbackUserData(this); - button->setVisible(mAllowEdit); - } + button->setClickedCallback(onBtnRefresh, this); + button->setVisible(mAllowEdit); + getChild("btn_create")->setVisible(false); + + childSetCommitCallback("btn_create",boost::bind(&LLPanelGroup::onBtnCreate,this),NULL); + childSetCommitCallback("back",boost::bind(&LLPanelGroup::onBackBtnClick,this),NULL); + + LLPanelGroupTab* panel_general = findChild("group_general_tab_panel"); + LLPanelGroupTab* panel_roles = findChild("group_roles_tab_panel"); + LLPanelGroupTab* panel_notices = findChild("group_notices_tab_panel"); + LLPanelGroupTab* panel_land = findChild("group_land_tab_panel"); + + if(panel_general) mTabs.push_back(panel_general); + if(panel_roles) mTabs.push_back(panel_roles); + if(panel_notices) mTabs.push_back(panel_notices); + if(panel_land) mTabs.push_back(panel_land); + + panel_general->setupCtrls(this); + return TRUE; } -void LLPanelGroup::changed(LLGroupChange gc) +void LLPanelGroup::reshape(S32 width, S32 height, BOOL called_from_parent ) { - updateTabVisibility(); - // Notify the currently active panel that group manager information has changed. - LLPanelGroupTab* panelp = (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); + LLPanel::reshape(width, height, called_from_parent ); - if (panelp) + LLRect btn_rect; + + LLButton* button = findChild("btn_apply"); + if(button) { - panelp->update(gc); + btn_rect = button->getRect(); + btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); + button->setRect(btn_rect); + } + + button = findChild("btn_create"); + if(button) + { + btn_rect = button->getRect(); + btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); + button->setRect(btn_rect); + } + + + button = findChild("btn_refresh"); + if(button) + { + btn_rect = button->getRect(); + btn_rect.setLeftTopAndSize( btn_rect.mLeft, btn_rect.getHeight() + 2, btn_rect.getWidth(), btn_rect.getHeight()); + button->setRect(btn_rect); } } -// PanelGroupTab observer trigger -void LLPanelGroup::tabChanged() +void LLPanelGroup::onBackBtnClick() { - //some tab information has changed,....enable/disable the apply button - //based on if they need an apply - if ( mApplyBtn ) + LLSideTrayPanelContainer* parent = dynamic_cast(getParent()); + if(parent) { - std::string mesg; - mApplyBtn->setEnabled(mCurrentTab->needsApply(mesg)); + parent->openPreviousPanel(); } } -// static -void LLPanelGroup::onClickTab(void* user_data, bool from_click) +void LLPanelGroup::onBtnCreate() { - LLPanelGroup* self = static_cast(user_data); - self->handleClickTab(); -} - -void LLPanelGroup::handleClickTab() -{ - // If we are already handling a transition, - // ignore this. - if (mIgnoreTransition) - { + LLPanelGroupGeneral* panel_general = findChild("group_general_tab_panel"); + if(!panel_general) return; - } - - mRequestedTab = (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); - - // Make sure they aren't just clicking the same tab... - if (mRequestedTab == mCurrentTab) - { - return; - } - - // Try to switch from the current panel to the panel the user selected. - attemptTransition(); + std::string apply_mesg; + panel_general->apply(apply_mesg);//yes yes you need to call apply to create... } -void LLPanelGroup::setGroupID(const LLUUID& group_id) -{ - LLRect rect(getRect()); - - LLGroupMgr::getInstance()->removeObserver(this); - mID = group_id; - LLGroupMgr::getInstance()->addObserver(this); - //TODO: this is really bad, we should add a method - // where the panels can just update themselves - // on a group id change. Similar to update() but with a group - // id change. - - // For now, rebuild panel - //delete children and rebuild panel - deleteAllChildren(); - LLUICtrlFactory::getInstance()->buildPanel(this, mFilename, &getFactoryMap()); -} - -void LLPanelGroup::selectTab(std::string tab_name) -{ - const BOOL recurse = TRUE; - - LLPanelGroupTab* tabp = - getChild(tab_name, recurse); - - if ( tabp && mTabContainer ) - { - mTabContainer->selectTabPanel(tabp); - onClickTab(this, false); - } -} - -BOOL LLPanelGroup::canClose() -{ - if (mShowingNotifyDialog) return FALSE; - if (mCurrentTab && mCurrentTab->hasModal()) return FALSE; - if (mForceClose || !mAllowEdit) return TRUE; - - // Try to switch from the current panel to nothing, indicating a close action. - mRequestedTab = NULL; - return attemptTransition(); -} - -BOOL LLPanelGroup::attemptTransition() -{ - // Check if the current tab needs to be applied. - std::string mesg; - if (mCurrentTab && mCurrentTab->needsApply(mesg)) - { - // If no message was provided, give a generic one. - if (mesg.empty()) - { - mesg = mDefaultNeedsApplyMesg; - } - // Create a notify box, telling the user about the unapplied tab. - LLSD args; - args["NEEDS_APPLY_MESSAGE"] = mesg; - args["WANT_APPLY_MESSAGE"] = mWantApplyMesg; - LLNotifications::instance().add("PanelGroupApply", args, LLSD(), - boost::bind(&LLPanelGroup::handleNotifyCallback, this, _1, _2)); - mShowingNotifyDialog = TRUE; - - // We need to reselect the current tab, since it isn't finished. - if (mTabContainer) - { - // selectTabPanel is going to trigger another - // click event. We want to ignore it so that - // mRequestedTab is not updated. - mIgnoreTransition = TRUE; - mTabContainer->selectTabPanel( mCurrentTab ); - mIgnoreTransition = FALSE; - } - // Returning FALSE will block a close action from finishing until - // we get a response back from the user. - return FALSE; - } - else - { - // The current panel didn't have anything it needed to apply. - if ( mRequestedTab ) - { - transitionToTab(); - } - // Returning TRUE will allow any close action to proceed. - return TRUE; - } -} - -void LLPanelGroup::transitionToTab() -{ - // Tell the current panel that it is being deactivated. - if (mCurrentTab) - { - mCurrentTab->deactivate(); - } - - // If the requested panel exists, activate it. - if (mRequestedTab) - { - // This is now the current tab; - mCurrentTab = mRequestedTab; - mCurrentTab->activate(); - } - else // NULL requested indicates a close action. - { - close(); - } -} - -bool LLPanelGroup::handleNotifyCallback(const LLSD& notification, const LLSD& response) -{ - S32 option = LLNotification::getSelectedOption(notification, response); - mShowingNotifyDialog = FALSE; - switch (option) - { - case 0: // "Apply Changes" - // Try to apply changes, and switch to the requested tab. - if ( !apply() ) - { - // There was a problem doing the apply. - // Skip switching tabs. - break; - } - - // This panel's info successfully applied. - // Switch to the next panel. - mIgnoreTransition = TRUE; - mTabContainer->selectTabPanel( mRequestedTab ); - mIgnoreTransition = FALSE; - transitionToTab(); - break; - case 1: // "Ignore Changes" - // Switch to the requested panel without applying changes - // (Changes may already have been applied in the previous block) - mCurrentTab->cancel(); - mIgnoreTransition = TRUE; - mTabContainer->selectTabPanel( mRequestedTab ); - mIgnoreTransition = FALSE; - transitionToTab(); - break; - case 2: // "Cancel" - default: - // Do nothing. The user is canceling the action. - // If we were quitting, we didn't really mean it. - LLAppViewer::instance()->abortQuit(); - break; - } - return false; -} - -// static -void LLPanelGroup::onBtnOK(void* user_data) +void LLPanelGroup::onBtnRefresh(void* user_data) { LLPanelGroup* self = static_cast(user_data); - // If we are able to apply changes, then close. - if(self->apply()) - { - self->close(); - } + self->refreshData(); } -// static -void LLPanelGroup::onBtnCancel(void* user_data) -{ - LLPanelGroup* self = static_cast(user_data); - self->close(); -} - -// static void LLPanelGroup::onBtnApply(void* user_data) { LLPanelGroup* self = static_cast(user_data); self->apply(); } -bool LLPanelGroup::apply() + +void LLPanelGroup::changed(LLGroupChange gc) { - // Pass this along to the currently visible tab. - if (!mTabContainer) return false; + for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) + (*it)->update(gc); - LLPanelGroupTab* panelp = (LLPanelGroupTab*) mTabContainer->getCurrentPanel(); - if (!panelp) return false; + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID); + if(gdatap) + childSetValue("group_name", gdatap->mName); +} + +void LLPanelGroup::notifyObservers() +{ + for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) + (*it)->update(GC_ALL); + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID); + if(gdatap) + childSetValue("group_name", gdatap->mName); +} + + + +void LLPanelGroup::setGroupID(const LLUUID& group_id) +{ + LLGroupMgr::getInstance()->removeObserver(this); + mID = group_id; + LLGroupMgr::getInstance()->addObserver(this); + + for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) + (*it)->setGroupID(group_id); + + LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mID); + if(gdatap) + childSetValue("group_name", gdatap->mName); + + LLButton* button_apply = findChild("btn_apply"); + LLButton* button_refresh = findChild("btn_refresh"); + LLButton* button_create = findChild("btn_create"); + + + bool is_null_group_id = group_id == LLUUID::null; + if(button_apply) + button_apply->setVisible(!is_null_group_id); + if(button_refresh) + button_refresh->setVisible(!is_null_group_id); + if(button_create) + button_create->setVisible(is_null_group_id); + + LLAccordionCtrlTab* tab_general = findChild("group_general_tab"); + LLAccordionCtrlTab* tab_roles = findChild("group_roles_tab"); + LLAccordionCtrlTab* tab_notices = findChild("group_notices_tab"); + LLAccordionCtrlTab* tab_land = findChild("group_land_tab"); + + if(!tab_general || !tab_roles || !tab_notices || !tab_land) + return; + + if(is_null_group_id)//creating new group + { + if(!tab_general->getDisplayChildren()) + tab_general->changeOpenClose(tab_general->getDisplayChildren()); + + if(tab_roles->getDisplayChildren()) + tab_roles->changeOpenClose(tab_roles->getDisplayChildren()); + if(tab_notices->getDisplayChildren()) + tab_notices->changeOpenClose(tab_notices->getDisplayChildren()); + if(tab_land->getDisplayChildren()) + tab_land->changeOpenClose(tab_land->getDisplayChildren()); + + tab_roles->canOpenClose(false); + tab_notices->canOpenClose(false); + tab_land->canOpenClose(false); + } + else + { + if(!tab_general->getDisplayChildren()) + tab_general->changeOpenClose(tab_general->getDisplayChildren()); + if(!tab_roles->getDisplayChildren()) + tab_roles->changeOpenClose(tab_roles->getDisplayChildren()); + if(!tab_notices->getDisplayChildren()) + tab_notices->changeOpenClose(tab_notices->getDisplayChildren()); + if(!tab_land->getDisplayChildren()) + tab_land->changeOpenClose(tab_land->getDisplayChildren()); + + tab_roles->canOpenClose(true); + tab_notices->canOpenClose(true); + tab_land->canOpenClose(true); + } +} + +bool LLPanelGroup::apply(LLPanelGroupTab* tab) +{ + if(!tab) + return false; + std::string mesg; - if ( !panelp->needsApply(mesg) ) - { - // We don't need to apply anything. - // We're done. + if ( !tab->needsApply(mesg) ) return true; - } - - // Ignore the needs apply message. - // Try to do the actual apply. + std::string apply_mesg; - if ( panelp->apply( apply_mesg ) ) - { - // Everything worked. We're done. + if(tab->apply( apply_mesg ) ) return true; - } - - // There was a problem doing the actual apply. - // Inform the user. + if ( !apply_mesg.empty() ) { LLSD args; args["MESSAGE"] = apply_mesg; LLNotifications::instance().add("GenericAlert", args); } - return false; } -// static -void LLPanelGroup::onBtnRefresh(void* user_data) +bool LLPanelGroup::apply() { - LLPanelGroup* self = static_cast(user_data); - self->refreshData(); + return apply(findChild("group_general_tab_panel")) + && apply(findChild("group_roles_tab_panel")) + && apply(findChild("group_notices_tab_panel")) + && apply(findChild("group_land_tab_panel")) + ; } + // virtual void LLPanelGroup::draw() { @@ -579,18 +381,22 @@ void LLPanelGroup::draw() mRefreshTimer.stop(); childEnable("btn_refresh"); } - if (mCurrentTab) - { - std::string mesg; - childSetEnabled("btn_apply", mCurrentTab->needsApply(mesg)); - } + bool enable = false; + std::string mesg; + for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) + enable = enable || (*it)->needsApply(mesg); + + childSetEnabled("btn_apply", enable); } void LLPanelGroup::refreshData() { LLGroupMgr::getInstance()->clearGroupData(getID()); - mCurrentTab->activate(); + + for(std::vector::iterator it = mTabs.begin();it!=mTabs.end();++it) + (*it)->activate(); + // 5 second timeout childDisable("btn_refresh"); @@ -598,20 +404,6 @@ void LLPanelGroup::refreshData() mRefreshTimer.setTimerExpirySec(5); } -void LLPanelGroup::close() -{ - // Pass this to the parent, if it is a floater. - LLView* viewp = getParent(); - LLFloater* floaterp = dynamic_cast(viewp); - if (floaterp) - { - // First, set the force close flag, since the floater - // will be asking us whether it can close. - mForceClose = TRUE; - // Tell the parent floater to close. - floaterp->close(); - } -} void LLPanelGroup::showNotice(const std::string& subject, const std::string& message, @@ -619,7 +411,8 @@ void LLPanelGroup::showNotice(const std::string& subject, const std::string& inventory_name, LLOfferInfo* inventory_offer) { - if (mCurrentTab->getName() != "notices_tab") + LLPanelGroupNotices* panel_notices = findChild("group_notices_tab_panel"); + if(!panel_notices) { // We need to clean up that inventory offer. if (inventory_offer) @@ -628,8 +421,37 @@ void LLPanelGroup::showNotice(const std::string& subject, } return; } - - LLPanelGroupNotices* notices = static_cast(mCurrentTab); - - notices->showNotice(subject,message,has_inventory,inventory_name,inventory_offer); + panel_notices->showNotice(subject,message,has_inventory,inventory_name,inventory_offer); } + + + + +//static +void LLPanelGroup::refreshCreatedGroup(const LLUUID& group_id) +{ + LLPanelGroup* panel = LLSideTray::getInstance()->findChild("panel_group_info_sidetray"); + if(!panel) + return; + panel->setGroupID(group_id); +} + +//static + +void LLPanelGroup::showNotice(const std::string& subject, + const std::string& message, + const LLUUID& group_id, + const bool& has_inventory, + const std::string& inventory_name, + LLOfferInfo* inventory_offer) +{ + LLPanelGroup* panel = LLSideTray::getInstance()->findChild("panel_group_info_sidetray"); + if(!panel) + return; + + if(panel->getID() != group_id)//???? only for current group_id or switch panels? FIXME + return; + panel->showNotice(subject,message,has_inventory,inventory_name,inventory_offer); + +} + diff --git a/indra/newview/llpanelgroup.h b/indra/newview/llpanelgroup.h index 445fb28502..6db6738d18 100644 --- a/indra/newview/llpanelgroup.h +++ b/indra/newview/llpanelgroup.h @@ -45,101 +45,79 @@ class LLPanelGroupTab; class LLTabContainer; class LLAgent; -class LLPanelGroupTabObserver -{ -public: - LLPanelGroupTabObserver() {}; - virtual ~LLPanelGroupTabObserver(){}; - virtual void tabChanged() = 0; -}; class LLPanelGroup : public LLPanel, - public LLGroupMgrObserver, - public LLPanelGroupTabObserver + public LLGroupMgrObserver { public: - LLPanelGroup(const std::string& filename, - const std::string& name, - const LLUUID& group_id, - const std::string& initial_tab_selected = std::string()); + LLPanelGroup(); virtual ~LLPanelGroup(); virtual BOOL postBuild(); - static void onBtnOK(void*); - static void onBtnCancel(void*); - static void onBtnApply(void*); - static void onBtnRefresh(void*); - static void onClickTab(void*,bool); - void handleClickTab(); - void setGroupID(const LLUUID& group_id); - void selectTab(std::string tab_name); - // Called when embedded in a floater during a close attempt. - BOOL canClose(); - - // Checks if the current tab needs to be applied, and tries to switch to the requested tab. - BOOL attemptTransition(); - - // Switches to the requested tab (will close() if requested is NULL) - void transitionToTab(); - - void updateTabVisibility(); - - // Used by attemptTransition to query the user's response to a tab that needs to apply. - bool handleNotifyCallback(const LLSD& notification, const LLSD& response); - - bool apply(); - void refreshData(); - void close(); void draw(); + void onOpen(const LLSD& key); + // Group manager observer trigger. virtual void changed(LLGroupChange gc); - // PanelGroupTab observer trigger - virtual void tabChanged(); - - void setAllowEdit(BOOL v) { mAllowEdit = v; } - void showNotice(const std::string& subject, const std::string& message, const bool& has_inventory, const std::string& inventory_name, LLOfferInfo* inventory_offer); -protected: - LLPanelGroupTab* mCurrentTab; - LLPanelGroupTab* mRequestedTab; - LLTabContainer* mTabContainer; - BOOL mIgnoreTransition; - LLButton* mApplyBtn; + void notifyObservers(); + + bool apply(); + void refreshData(); + + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + + void setAllowEdit(BOOL v) { mAllowEdit = v; } + + + static void refreshCreatedGroup(const LLUUID& group_id); + + static void showNotice(const std::string& subject, + const std::string& message, + const LLUUID& group_id, + const bool& has_inventory, + const std::string& inventory_name, + LLOfferInfo* inventory_offer); + + +protected: + void onBtnCreate(); + void onBackBtnClick(); + + static void onBtnApply(void*); + static void onBtnRefresh(void*); + + +protected: + bool apply(LLPanelGroupTab* tab); LLTimer mRefreshTimer; - BOOL mForceClose; - - std::string mInitialTab; - std::string mFilename; + BOOL mAllowEdit; std::string mDefaultNeedsApplyMesg; std::string mWantApplyMesg; - BOOL mAllowEdit; - BOOL mShowingNotifyDialog; + std::vector mTabs; + }; class LLPanelGroupTab : public LLPanel { public: - LLPanelGroupTab(const std::string& name, const LLUUID& group_id) - : LLPanel(name), mGroupID(group_id), mAllowEdit(TRUE), mHasModal(FALSE) { } + LLPanelGroupTab(); virtual ~LLPanelGroupTab(); - // Factory that returns a new LLPanelGroupFoo tab. - static void* createTab(void* data); - // Triggered when the tab becomes active. virtual void activate() { } @@ -167,7 +145,6 @@ public: virtual std::string getHelpText() const { return mHelpText; } // Display anything returned by getHelpText - static void onClickHelp(void* data); void handleClickHelp(); // This just connects the help button callback. @@ -177,20 +154,21 @@ public: void setAllowEdit(BOOL v) { mAllowEdit = v; } - void addObserver(LLPanelGroupTabObserver *obs); - void removeObserver(LLPanelGroupTabObserver *obs); - void notifyObservers(); + virtual void setGroupID(const LLUUID& id) {mGroupID = id;}; + + void notifyObservers() {}; + + const LLUUID& getGroupID() const { return mGroupID;} + + virtual void setupCtrls (LLPanel* parent) {}; protected: LLUUID mGroupID; - LLTabContainer* mTabContainer; std::string mHelpText; BOOL mAllowEdit; BOOL mHasModal; - typedef std::set observer_list_t; - observer_list_t mObservers; }; #endif // LL_LLPANELGROUP_H diff --git a/indra/newview/llpanelgroupgeneral.cpp b/indra/newview/llpanelgroupgeneral.cpp index 3dc5e032c5..73ea990b3f 100644 --- a/indra/newview/llpanelgroupgeneral.cpp +++ b/indra/newview/llpanelgroupgeneral.cpp @@ -37,49 +37,43 @@ #include "lluictrlfactory.h" #include "llagent.h" #include "roles_constants.h" -#include "llfloateravatarinfo.h" -#include "llfloatergroupinfo.h" // UI elements #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldbstrings.h" +#include "llavataractions.h" +#include "llgroupactions.h" #include "lllineeditor.h" #include "llnamebox.h" #include "llnamelistctrl.h" +#include "llscrolllistitem.h" #include "llspinctrl.h" #include "llstatusbar.h" // can_afford_transaction() #include "lltextbox.h" #include "lltexteditor.h" #include "lltexturectrl.h" +#include "lltrans.h" #include "llviewerwindow.h" +static LLRegisterPanelClassWrapper t_panel_group_general("panel_group_general"); + // consts const S32 MATURE_CONTENT = 1; const S32 NON_MATURE_CONTENT = 2; const S32 DECLINE_TO_STATE = 0; -// static -void* LLPanelGroupGeneral::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupGeneral("panel group general", *group_id); -} - -LLPanelGroupGeneral::LLPanelGroupGeneral(const std::string& name, - const LLUUID& group_id) -: LLPanelGroupTab(name, group_id), +LLPanelGroupGeneral::LLPanelGroupGeneral() +: LLPanelGroupTab(), mPendingMemberUpdate(FALSE), mChanged(FALSE), mFirstUse(TRUE), mGroupNameEditor(NULL), - mGroupName(NULL), mFounderName(NULL), mInsignia(NULL), mEditCharter(NULL), - mBtnJoinGroup(NULL), mListVisibleMembers(NULL), mCtrlShowInGroupList(NULL), mComboMature(NULL), @@ -100,74 +94,39 @@ LLPanelGroupGeneral::~LLPanelGroupGeneral() BOOL LLPanelGroupGeneral::postBuild() { - llinfos << "LLPanelGroupGeneral::postBuild()" << llendl; - bool recurse = true; // General info mGroupNameEditor = getChild("group_name_editor", recurse); - mGroupName = getChild("group_name", recurse); - - mInsignia = getChild("insignia", recurse); - if (mInsignia) - { - mInsignia->setCommitCallback(onCommitAny); - mInsignia->setCallbackUserData(this); - mDefaultIconID = mInsignia->getImageAssetID(); - } mEditCharter = getChild("charter", recurse); if(mEditCharter) { - mEditCharter->setCommitCallback(onCommitAny); + mEditCharter->setCommitCallback(onCommitAny, this); mEditCharter->setFocusReceivedCallback(onFocusEdit, this); mEditCharter->setFocusChangedCallback(onFocusEdit, this); - mEditCharter->setCallbackUserData(this); } - mBtnJoinGroup = getChild("join_button", recurse); - if ( mBtnJoinGroup ) - { - mBtnJoinGroup->setClickedCallback(onClickJoin); - mBtnJoinGroup->setCallbackUserData(this); - } - mBtnInfo = getChild("info_button", recurse); - if ( mBtnInfo ) - { - mBtnInfo->setClickedCallback(onClickInfo); - mBtnInfo->setCallbackUserData(this); - } - - LLTextBox* founder = getChild("founder_name"); - if (founder) - { - mFounderName = new LLNameBox(founder->getName(),founder->getRect(),LLUUID::null,FALSE,founder->getFont(),founder->getMouseOpaque()); - removeChild(founder, TRUE); - addChild(mFounderName); - } mListVisibleMembers = getChild("visible_members", recurse); if (mListVisibleMembers) { - mListVisibleMembers->setDoubleClickCallback(openProfile); - mListVisibleMembers->setCallbackUserData(this); + mListVisibleMembers->setDoubleClickCallback(openProfile, this); } // Options mCtrlShowInGroupList = getChild("show_in_group_list", recurse); if (mCtrlShowInGroupList) { - mCtrlShowInGroupList->setCommitCallback(onCommitAny); - mCtrlShowInGroupList->setCallbackUserData(this); + mCtrlShowInGroupList->setCommitCallback(onCommitAny, this); } mComboMature = getChild("group_mature_check", recurse); if(mComboMature) { mComboMature->setCurrentByIndex(0); - mComboMature->setCommitCallback(onCommitAny); - mComboMature->setCallbackUserData(this); + mComboMature->setCommitCallback(onCommitAny, this); if (gAgent.isTeen()) { // Teens don't get to set mature flag. JC @@ -178,22 +137,19 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlOpenEnrollment = getChild("open_enrollement", recurse); if (mCtrlOpenEnrollment) { - mCtrlOpenEnrollment->setCommitCallback(onCommitAny); - mCtrlOpenEnrollment->setCallbackUserData(this); + mCtrlOpenEnrollment->setCommitCallback(onCommitAny, this); } mCtrlEnrollmentFee = getChild("check_enrollment_fee", recurse); if (mCtrlEnrollmentFee) { - mCtrlEnrollmentFee->setCommitCallback(onCommitEnrollment); - mCtrlEnrollmentFee->setCallbackUserData(this); + mCtrlEnrollmentFee->setCommitCallback(onCommitEnrollment, this); } mSpinEnrollmentFee = getChild("spin_enrollment_fee", recurse); if (mSpinEnrollmentFee) { - mSpinEnrollmentFee->setCommitCallback(onCommitAny); - mSpinEnrollmentFee->setCallbackUserData(this); + mSpinEnrollmentFee->setCommitCallback(onCommitAny, this); mSpinEnrollmentFee->setPrecision(0); mSpinEnrollmentFee->resetDirty(); } @@ -209,8 +165,7 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlReceiveNotices = getChild("receive_notices", recurse); if (mCtrlReceiveNotices) { - mCtrlReceiveNotices->setCommitCallback(onCommitUserOnly); - mCtrlReceiveNotices->setCallbackUserData(this); + mCtrlReceiveNotices->setCommitCallback(onCommitUserOnly, this); mCtrlReceiveNotices->set(accept_notices); mCtrlReceiveNotices->setEnabled(data.mID.notNull()); } @@ -218,8 +173,7 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlListGroup = getChild("list_groups_in_profile", recurse); if (mCtrlListGroup) { - mCtrlListGroup->setCommitCallback(onCommitUserOnly); - mCtrlListGroup->setCallbackUserData(this); + mCtrlListGroup->setCommitCallback(onCommitUserOnly, this); mCtrlListGroup->set(list_in_profile); mCtrlListGroup->setEnabled(data.mID.notNull()); mCtrlListGroup->resetDirty(); @@ -230,14 +184,12 @@ BOOL LLPanelGroupGeneral::postBuild() mComboActiveTitle = getChild("active_title", recurse); if (mComboActiveTitle) { - mComboActiveTitle->setCommitCallback(onCommitTitle); - mComboActiveTitle->setCallbackUserData(this); + mComboActiveTitle->setCommitCallback(onCommitTitle, this); mComboActiveTitle->resetDirty(); } mIncompleteMemberDataStr = getString("incomplete_member_data_str"); - mConfirmGroupCreateStr = getString("confirm_group_create_str"); - + // If the group_id is null, then we are creating a new group if (mGroupID.isNull()) { @@ -250,14 +202,22 @@ BOOL LLPanelGroupGeneral::postBuild() mCtrlEnrollmentFee->setEnabled(TRUE); mSpinEnrollmentFee->setEnabled(TRUE); - mBtnJoinGroup->setVisible(FALSE); - mBtnInfo->setVisible(FALSE); - mGroupName->setVisible(FALSE); } return LLPanelGroupTab::postBuild(); } +void LLPanelGroupGeneral::setupCtrls(LLPanel* panel_group) +{ + mInsignia = panel_group->getChild("insignia"); + if (mInsignia) + { + mInsignia->setCommitCallback(onCommitAny, this); + mDefaultIconID = mInsignia->getImageAssetID(); + } + mFounderName = panel_group->getChild("founder_name"); +} + // static void LLPanelGroupGeneral::onFocusEdit(LLFocusableElement* ctrl, void* data) { @@ -332,7 +292,8 @@ void LLPanelGroupGeneral::onClickInfo(void *userdata) lldebugs << "open group info: " << self->mGroupID << llendl; - LLFloaterGroupInfo::showFromUUID(self->mGroupID); + LLGroupActions::show(self->mGroupID); + } // static @@ -395,7 +356,7 @@ void LLPanelGroupGeneral::openProfile(void* data) LLScrollListItem* selected = self->mListVisibleMembers->getFirstSelected(); if (selected) { - LLFloaterAvatarInfo::showFromDirectory( selected->getUUID() ); + LLAvatarActions::showProfile(selected->getUUID()); } } } @@ -470,9 +431,7 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) return false; } - LLSD args; - args["MESSAGE"] = mConfirmGroupCreateStr; - LLNotifications::instance().add("GenericAlertYesCancel", args, LLSD(), boost::bind(&LLPanelGroupGeneral::createGroupCallback, this, _1, _2)); + LLNotifications::instance().add("CreateGroupCost", LLSD(), LLSD(), boost::bind(&LLPanelGroupGeneral::createGroupCallback, this, _1, _2)); return false; } @@ -480,8 +439,7 @@ bool LLPanelGroupGeneral::apply(std::string& mesg) LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); if (!gdatap) { - // *TODO: Translate - mesg = std::string("No group data found for group "); + mesg = LLTrans::getString("NoGroupDataFound"); mesg.append(mGroupID.asString()); return false; } @@ -720,26 +678,6 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) can_change_member_opts); mSpinEnrollmentFee->resetDirty(); } - if ( mBtnJoinGroup ) - { - std::string fee_buff; - bool visible; - - visible = !is_member && gdatap->mOpenEnrollment; - mBtnJoinGroup->setVisible(visible); - - if ( visible ) - { - fee_buff = llformat( "Join (L$%d)", gdatap->mMembershipFee); - mBtnJoinGroup->setLabelSelected(fee_buff); - mBtnJoinGroup->setLabelUnselected(fee_buff); - } - } - if ( mBtnInfo ) - { - mBtnInfo->setVisible(is_member && !mAllowEdit); - } - if (mCtrlReceiveNotices) { mCtrlReceiveNotices->setVisible(is_member); @@ -754,7 +692,6 @@ void LLPanelGroupGeneral::update(LLGroupChange gc) if (mInsignia) mInsignia->setEnabled(mAllowEdit && can_change_ident); if (mEditCharter) mEditCharter->setEnabled(mAllowEdit && can_change_ident); - if (mGroupName) mGroupName->setText(gdatap->mName); if (mGroupNameEditor) mGroupNameEditor->setVisible(FALSE); if (mFounderName) mFounderName->setNameID(gdatap->mFounderID,FALSE); if (mInsignia) @@ -842,16 +779,16 @@ void LLPanelGroupGeneral::updateMembers() row["id"] = member->getID(); row["columns"][0]["column"] = "name"; - row["columns"][0]["font-style"] = style; + row["columns"][0]["font"]["style"] = style; // value is filled in by name list control row["columns"][1]["column"] = "title"; row["columns"][1]["value"] = member->getTitle(); - row["columns"][1]["font-style"] = style; + row["columns"][1]["font"]["style"] = style; row["columns"][2]["column"] = "online"; row["columns"][2]["value"] = member->getOnlineStatus(); - row["columns"][2]["font-style"] = style; + row["columns"][2]["font"]["style"] = style; sSDTime += sd_timer.getElapsedTimeF32(); @@ -884,7 +821,6 @@ void LLPanelGroupGeneral::updateChanged() LLUICtrl *check_list[] = { mGroupNameEditor, - mGroupName, mFounderName, mInsignia, mEditCharter, @@ -910,3 +846,136 @@ void LLPanelGroupGeneral::updateChanged() } } } + +void LLPanelGroupGeneral::reset() +{ + mFounderName->setVisible(false); + + + mCtrlReceiveNotices->set(false); + + + mCtrlListGroup->set(true); + + mCtrlReceiveNotices->setEnabled(true); + mCtrlReceiveNotices->setVisible(true); + + mCtrlListGroup->setEnabled(true); + + mGroupNameEditor->setEnabled(TRUE); + mEditCharter->setEnabled(TRUE); + + mCtrlShowInGroupList->setEnabled(TRUE); + mComboMature->setEnabled(TRUE); + + mCtrlOpenEnrollment->setEnabled(TRUE); + + mCtrlEnrollmentFee->setEnabled(TRUE); + + mSpinEnrollmentFee->setEnabled(TRUE); + mSpinEnrollmentFee->set((F32)0); + + mGroupNameEditor->setVisible(true); + + mComboActiveTitle->setVisible(false); + + mInsignia->setImageAssetID(LLUUID::null); + + { + std::string empty_str = ""; + mEditCharter->setText(empty_str); + } + + { + LLSD row; + row["columns"][0]["value"] = "no members yet"; + + mListVisibleMembers->deleteAllItems(); + mListVisibleMembers->setEnabled(FALSE); + mListVisibleMembers->addElement(row); + } + + + { + mComboMature->setEnabled(true); + mComboMature->setVisible( !gAgent.isTeen() ); + } + + + resetDirty(); +} + +void LLPanelGroupGeneral::resetDirty() +{ + // List all the controls we want to check for changes... + LLUICtrl *check_list[] = + { + mGroupNameEditor, + mFounderName, + mInsignia, + mEditCharter, + mCtrlShowInGroupList, + mComboMature, + mCtrlOpenEnrollment, + mCtrlEnrollmentFee, + mSpinEnrollmentFee, + mCtrlReceiveNotices, + mCtrlListGroup, + mActiveTitleLabel, + mComboActiveTitle + }; + + for( size_t i=0; iresetDirty() ; + } + + +} + +void LLPanelGroupGeneral::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + if(id == LLUUID::null) + { + reset(); + return; + } + + BOOL accept_notices = FALSE; + BOOL list_in_profile = FALSE; + LLGroupData data; + if(gAgent.getGroupData(mGroupID,data)) + { + accept_notices = data.mAcceptNotices; + list_in_profile = data.mListInProfile; + } + mCtrlReceiveNotices = getChild("receive_notices"); + if (mCtrlReceiveNotices) + { + mCtrlReceiveNotices->set(accept_notices); + mCtrlReceiveNotices->setEnabled(data.mID.notNull()); + } + + mCtrlListGroup = getChild("list_groups_in_profile"); + if (mCtrlListGroup) + { + mCtrlListGroup->set(list_in_profile); + mCtrlListGroup->setEnabled(data.mID.notNull()); + } + + mActiveTitleLabel = getChild("active_title_label"); + + mComboActiveTitle = getChild("active_title"); + + mFounderName->setVisible(true); + + mInsignia->setImageAssetID(LLUUID::null); + + resetDirty(); + + activate(); +} + diff --git a/indra/newview/llpanelgroupgeneral.h b/indra/newview/llpanelgroupgeneral.h index 71356677fc..b828480a12 100644 --- a/indra/newview/llpanelgroupgeneral.h +++ b/indra/newview/llpanelgroupgeneral.h @@ -49,11 +49,10 @@ class LLSpinCtrl; class LLPanelGroupGeneral : public LLPanelGroupTab { public: - LLPanelGroupGeneral(const std::string& name, const LLUUID& group_id); + LLPanelGroupGeneral(); virtual ~LLPanelGroupGeneral(); // LLPanelGroupTab - static void* createTab(void* data); virtual void activate(); virtual bool needsApply(std::string& mesg); virtual bool apply(std::string& mesg); @@ -66,7 +65,15 @@ public: virtual void draw(); + virtual void setGroupID(const LLUUID& id); + + virtual void setupCtrls (LLPanel* parent); + private: + void reset(); + + void resetDirty(); + static void onFocusEdit(LLFocusableElement* ctrl, void* data); static void onCommitAny(LLUICtrl* ctrl, void* data); static void onCommitUserOnly(LLUICtrl* ctrl, void* data); @@ -87,17 +94,13 @@ private: BOOL mChanged; BOOL mFirstUse; std::string mIncompleteMemberDataStr; - std::string mConfirmGroupCreateStr; LLUUID mDefaultIconID; // Group information (include any updates in updateChanged) LLLineEditor *mGroupNameEditor; - LLTextBox *mGroupName; LLNameBox *mFounderName; LLTextureCtrl *mInsignia; LLTextEditor *mEditCharter; - LLButton *mBtnJoinGroup; - LLButton *mBtnInfo; LLNameListCtrl *mListVisibleMembers; diff --git a/indra/newview/llpanelgroupinvite.cpp b/indra/newview/llpanelgroupinvite.cpp index eedec9c8eb..c5eaa34204 100644 --- a/indra/newview/llpanelgroupinvite.cpp +++ b/indra/newview/llpanelgroupinvite.cpp @@ -37,8 +37,10 @@ #include "llfloateravatarpicker.h" #include "llbutton.h" #include "llcombobox.h" +#include "llgroupactions.h" #include "llgroupmgr.h" #include "llnamelistctrl.h" +#include "llscrolllistitem.h" #include "llspinctrl.h" #include "lltextbox.h" #include "llviewerobject.h" @@ -79,6 +81,7 @@ public: LLButton *mRemoveButton; LLTextBox *mGroupName; std::string mOwnerWarning; + std::string mAlreadyInGroup; bool mConfirmedOwnerInvite; void (*mCloseCallback)(void* data); @@ -166,16 +169,29 @@ void LLPanelGroupInvite::impl::submitInvitations() } } + bool already_in_group = false; //loop over the users std::vector items = mInvitees->getAllData(); for (std::vector::iterator iter = items.begin(); iter != items.end(); ++iter) { LLScrollListItem* item = *iter; + if(LLGroupActions::isAvatarMemberOfGroup(mGroupID, item->getUUID())) + { + already_in_group = true; + continue; + } role_member_pairs[item->getUUID()] = role_id; } - + LLGroupMgr::getInstance()->sendGroupMemberInvites(mGroupID, role_member_pairs); + + if(already_in_group) + { + LLSD msg; + msg["MESSAGE"] = mAlreadyInGroup; + LLNotifications::instance().add("GenericAlert", msg); + } //then close (*mCloseCallback)(mCloseCallbackUserData); @@ -351,18 +367,13 @@ void LLPanelGroupInvite::impl::callbackAddUsers(const std::vector& if ( selfp) selfp->addUsers(names, ids); } -LLPanelGroupInvite::LLPanelGroupInvite(const std::string& name, - const LLUUID& group_id) - : LLPanel(name) +LLPanelGroupInvite::LLPanelGroupInvite(const LLUUID& group_id) + : LLPanel(), + mImplementation(new impl(group_id)), + mPendingUpdate(FALSE) { - mImplementation = new impl(group_id); - mPendingUpdate = FALSE; - mStoreSelected = LLUUID::null; - - std::string panel_def_file; - // Pass on construction of this panel to the control factory. - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_invite.xml", &getFactoryMap()); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_invite.xml"); } LLPanelGroupInvite::~LLPanelGroupInvite() @@ -519,9 +530,8 @@ BOOL LLPanelGroupInvite::postBuild() getChild("invitee_list", recurse); if ( mImplementation->mInvitees ) { - mImplementation->mInvitees->setCallbackUserData(mImplementation); mImplementation->mInvitees->setCommitOnSelectionChange(TRUE); - mImplementation->mInvitees->setCommitCallback(impl::callbackSelect); + mImplementation->mInvitees->setCommitCallback(impl::callbackSelect, mImplementation); } LLButton* button = getChild("add_button", recurse); @@ -529,17 +539,14 @@ BOOL LLPanelGroupInvite::postBuild() { // default to opening avatarpicker automatically // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(impl::callbackClickAdd); - button->setCallbackUserData(this); + button->setClickedCallback(impl::callbackClickAdd, this); } mImplementation->mRemoveButton = getChild("remove_button", recurse); if ( mImplementation->mRemoveButton ) { - mImplementation->mRemoveButton-> - setClickedCallback(impl::callbackClickRemove); - mImplementation->mRemoveButton->setCallbackUserData(mImplementation); + mImplementation->mRemoveButton->setClickedCallback(impl::callbackClickRemove, mImplementation); mImplementation->mRemoveButton->setEnabled(FALSE); } @@ -547,20 +554,18 @@ BOOL LLPanelGroupInvite::postBuild() getChild("ok_button", recurse); if ( mImplementation->mOKButton ) { - mImplementation->mOKButton-> - setClickedCallback(impl::callbackClickOK); - mImplementation->mOKButton->setCallbackUserData(mImplementation); + mImplementation->mOKButton->setClickedCallback(impl::callbackClickOK, mImplementation); mImplementation->mOKButton->setEnabled(FALSE); } button = getChild("cancel_button", recurse); if ( button ) { - button->setClickedCallback(impl::callbackClickCancel); - button->setCallbackUserData(mImplementation); + button->setClickedCallback(impl::callbackClickCancel, mImplementation); } mImplementation->mOwnerWarning = getString("confirm_invite_owner_str"); + mImplementation->mAlreadyInGroup = getString("already_in_group"); update(); diff --git a/indra/newview/llpanelgroupinvite.h b/indra/newview/llpanelgroupinvite.h index 9117b83e7d..37135b488a 100644 --- a/indra/newview/llpanelgroupinvite.h +++ b/indra/newview/llpanelgroupinvite.h @@ -39,7 +39,7 @@ class LLPanelGroupInvite : public LLPanel { public: - LLPanelGroupInvite(const std::string& name, const LLUUID& group_id); + LLPanelGroupInvite(const LLUUID& group_id); ~LLPanelGroupInvite(); void addUsers(std::vector& agent_ids); diff --git a/indra/newview/llpanelgrouplandmoney.cpp b/indra/newview/llpanelgrouplandmoney.cpp index 73a9868962..e40fa19bb6 100644 --- a/indra/newview/llpanelgrouplandmoney.cpp +++ b/indra/newview/llpanelgrouplandmoney.cpp @@ -42,20 +42,72 @@ #include "llagent.h" #include "lliconctrl.h" +#include "llfloaterreg.h" #include "lllineeditor.h" #include "llproductinforequest.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lltextbox.h" #include "lltabcontainer.h" +#include "lltexteditor.h" #include "lltrans.h" #include "lltransactiontypes.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "llstatusbar.h" #include "llfloaterworldmap.h" #include "llviewermessage.h" +static LLRegisterPanelClassWrapper t_panel_group_money("panel_group_land_money"); + + + //////////////////////////////////////////////////////////////////////////// +//************************************************* +//** LLGroupMoneyTabEventHandler::impl Functions ** +//************************************************* + +class LLGroupMoneyTabEventHandlerImpl +{ +public: + LLGroupMoneyTabEventHandlerImpl(LLButton* earlier_buttonp, + LLButton* later_buttonp, + LLTextEditor* text_editorp, + LLPanel* tabpanelp, + const std::string& loading_text, + S32 interval_length_days, + S32 max_interval_days); + ~LLGroupMoneyTabEventHandlerImpl(); + + bool getCanClickLater(); + bool getCanClickEarlier(); + + void updateButtons(); + + void setGroupID(const LLUUID& group_id) { mGroupID = group_id; } ; + const LLUUID& getGroupID() const { return mGroupID;} + + +//member variables +public: + LLUUID mPanelID; + LLUUID mGroupID; + + LLPanel* mTabPanelp; + + int mIntervalLength; + int mMaxInterval; + int mCurrentInterval; + + LLTextEditor* mTextEditorp; + LLButton* mEarlierButtonp; + LLButton* mLaterButtonp; + + std::string mLoadingText; +}; + class LLGroupMoneyTabEventHandler { @@ -66,7 +118,6 @@ public: LLTabContainer* tab_containerp, LLPanel* panelp, const std::string& loading_text, - const LLUUID& group_id, S32 interval_length_days, S32 max_interval_days); virtual ~LLGroupMoneyTabEventHandler(); @@ -78,15 +129,17 @@ public: virtual void onClickLater(); virtual void onClickTab(); + void setGroupID(const LLUUID& group_id) { if(mImplementationp) mImplementationp->setGroupID(group_id); } ; + static void clickEarlierCallback(void* data); static void clickLaterCallback(void* data); - static void clickTabCallback(void* user_data, bool from_click); + + static LLMap sInstanceIDs; static std::map sTabsToHandlers; protected: - class impl; - impl* mImplementationp; + LLGroupMoneyTabEventHandlerImpl* mImplementationp; }; class LLGroupMoneyDetailsTabEventHandler : public LLGroupMoneyTabEventHandler @@ -97,8 +150,8 @@ public: LLTextEditor* text_editorp, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id); + const std::string& loading_text + ); virtual ~LLGroupMoneyDetailsTabEventHandler(); virtual void requestData(LLMessageSystem* msg); @@ -114,8 +167,8 @@ public: LLTextEditor* text_editorp, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id); + const std::string& loading_text + ); virtual ~LLGroupMoneySalesTabEventHandler(); virtual void requestData(LLMessageSystem* msg); @@ -128,8 +181,8 @@ public: LLGroupMoneyPlanningTabEventHandler(LLTextEditor* text_editor, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id); + const std::string& loading_text + ); virtual ~LLGroupMoneyPlanningTabEventHandler(); virtual void requestData(LLMessageSystem* msg); @@ -141,7 +194,7 @@ public: class LLPanelGroupLandMoney::impl { public: - impl(LLPanelGroupLandMoney& panel, const LLUUID& group_id); //constructor + impl(LLPanelGroupLandMoney& panel); //constructor virtual ~impl(); void requestGroupLandInfo(); @@ -175,7 +228,6 @@ public: LLScrollListCtrl* mGroupParcelsp; - LLUUID mGroupID; LLUUID mTransID; bool mBeenActivated; @@ -189,9 +241,8 @@ public: //******************************************* //** LLPanelGroupLandMoney::impl Functions ** //******************************************* -LLPanelGroupLandMoney::impl::impl(LLPanelGroupLandMoney& panel, const LLUUID& group_id) - : mPanel(panel), - mGroupID(group_id) +LLPanelGroupLandMoney::impl::impl(LLPanelGroupLandMoney& panel) + : mPanel(panel) { mTransID = LLUUID::null; @@ -224,7 +275,7 @@ void LLPanelGroupLandMoney::impl::requestGroupLandInfo() mTransID.generate(); mGroupParcelsp->deleteAllItems(); - send_places_query(mGroupID, mTransID, "", query_flags, LLParcel::C_ANY, ""); + send_places_query(mPanel.mGroupID, mTransID, "", query_flags, LLParcel::C_ANY, ""); } void LLPanelGroupLandMoney::impl::onMapButton() @@ -244,9 +295,12 @@ void LLPanelGroupLandMoney::impl::onMapButton() F64 global_z = gAgent.getPositionGlobal().mdV[VZ]; LLVector3d pos_global(global_x, global_y, global_z); - gFloaterWorldMap->trackLocation(pos_global); - - LLFloaterWorldMap::show(NULL, TRUE); + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if(worldmap_instance) + { + worldmap_instance->trackLocation(pos_global); + LLFloaterReg::showInstance("world_map", "center"); + } } bool LLPanelGroupLandMoney::impl::applyContribution() @@ -271,7 +325,7 @@ bool LLPanelGroupLandMoney::impl::applyContribution() new_contribution <= sqm_avail ) { // update group info and server - if(!gAgent.setGroupContribution(mGroupID, new_contribution)) + if(!gAgent.setGroupContribution(mPanel.mGroupID, new_contribution)) { // should never happen... llwarns << "Unable to set contribution." << llendl; @@ -298,7 +352,7 @@ int LLPanelGroupLandMoney::impl::getStoredContribution() LLGroupData group_data; group_data.mContribution = 0; - gAgent.getGroupData(mGroupID, group_data); + gAgent.getGroupData(mPanel.mGroupID, group_data); return group_data.mContribution; } @@ -397,13 +451,7 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) if ( trans_id != mTransID ) return; // This power was removed to make group roles simpler //if ( !gAgent.hasPowerInGroup(mGroupID, GP_LAND_VIEW_OWNED) ) return; - if (!gAgent.isInGroup(mGroupID)) return; - - //we updated more than just the available area special block - if ( count > 1) - { - mMapButtonp->setEnabled(TRUE); - } + if (!gAgent.isInGroup(mPanel.mGroupID)) return; std::string name; std::string desc; @@ -460,15 +508,15 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) row["columns"][0]["column"] = "name"; row["columns"][0]["value"] = name; - row["columns"][0]["font"] = "SANSSERIFSMALL"; + row["columns"][0]["font"] = "SANSSERIF_SMALL"; row["columns"][1]["column"] = "location"; row["columns"][1]["value"] = location; - row["columns"][1]["font"] = "SANSSERIFSMALL"; + row["columns"][1]["font"] = "SANSSERIF_SMALL"; row["columns"][2]["column"] = "area"; row["columns"][2]["value"] = area; - row["columns"][2]["font"] = "SANSSERIFSMALL"; + row["columns"][2]["font"] = "SANSSERIF_SMALL"; row["columns"][3]["column"] = "type"; row["columns"][3]["value"] = land_type; @@ -487,26 +535,22 @@ void LLPanelGroupLandMoney::impl::processGroupLand(LLMessageSystem* msg) //** LLPanelGroupLandMoney Functions ** //************************************* -//static -void* LLPanelGroupLandMoney::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupLandMoney("panel group land money", *group_id); -} //static LLMap LLPanelGroupLandMoney::sGroupIDs; -LLPanelGroupLandMoney::LLPanelGroupLandMoney(const std::string& name, - const LLUUID& group_id) : - LLPanelGroupTab(name, group_id) +LLPanelGroupLandMoney::LLPanelGroupLandMoney() : + LLPanelGroupTab() { - mImplementationp = new impl(*this, group_id); + //FIXME - add setGroupID(); + mImplementationp = new impl(*this); //problem what if someone has both the group floater open and the finder //open to the same group? Some maps that map group ids to panels //will then only be working for the last panel for a given group id :( - LLPanelGroupLandMoney::sGroupIDs.addData(group_id, this); + + //FIXME - add to setGroupID() + //LLPanelGroupLandMoney::sGroupIDs.addData(group_id, this); } LLPanelGroupLandMoney::~LLPanelGroupLandMoney() @@ -553,6 +597,7 @@ void LLPanelGroupLandMoney::activate() mImplementationp->setYourMaxContributionTextBox(max_avail); } + mImplementationp->mMapButtonp->setEnabled(false); update(GC_ALL); } @@ -634,9 +679,8 @@ BOOL LLPanelGroupLandMoney::postBuild() { LLLineEditor* editor = mImplementationp->mYourContributionEditorp; - editor->setCommitCallback(mImplementationp->contributionCommitCallback); - editor->setKeystrokeCallback(mImplementationp->contributionKeystrokeCallback); - editor->setCallbackUserData(this); + editor->setCommitCallback(mImplementationp->contributionCommitCallback, this); + editor->setKeystrokeCallback(mImplementationp->contributionKeystrokeCallback, this); } mImplementationp->mMapButtonp = getChild("map_button"); @@ -644,6 +688,12 @@ BOOL LLPanelGroupLandMoney::postBuild() mImplementationp->mGroupParcelsp = getChild("group_parcel_list"); + if ( mImplementationp->mGroupParcelsp ) + { + mImplementationp->mGroupParcelsp->setCommitCallback(boost::bind(&LLButton::setEnabled, mImplementationp->mMapButtonp, true)); + mImplementationp->mGroupParcelsp->setCommitOnSelectionChange(true); + } + mImplementationp->mCantViewParcelsText = getString("cant_view_group_land_text"); mImplementationp->mCantViewAccountsText = getString("cant_view_group_accounting_text"); @@ -662,16 +712,11 @@ BOOL LLPanelGroupLandMoney::postBuild() mImplementationp->mGroupOverLimitIconp->setVisible(FALSE); } - if ( mImplementationp->mMapButtonp ) - { - mImplementationp->mMapButtonp->setEnabled(FALSE); - } - if ( !can_view ) { if ( mImplementationp->mGroupParcelsp ) { - mImplementationp->mGroupParcelsp->addCommentText( + mImplementationp->mGroupParcelsp->setCommentText( mImplementationp->mCantViewParcelsText); mImplementationp->mGroupParcelsp->setEnabled(FALSE); } @@ -719,8 +764,7 @@ BOOL LLPanelGroupLandMoney::postBuild() textp, tabcp, panelp, - loading_text, - mGroupID); + loading_text); } textp = getChild("group_money_planning_text", true); @@ -737,8 +781,7 @@ BOOL LLPanelGroupLandMoney::postBuild() new LLGroupMoneyPlanningTabEventHandler(textp, tabcp, panelp, - loading_text, - mGroupID); + loading_text); } //pull out the widgets for the L$ sales tab @@ -759,8 +802,7 @@ BOOL LLPanelGroupLandMoney::postBuild() textp, tabcp, panelp, - loading_text, - mGroupID); + loading_text); } return LLPanelGroupTab::postBuild(); @@ -787,56 +829,15 @@ void LLPanelGroupLandMoney::processPlacesReply(LLMessageSystem* msg, void**) selfp->mImplementationp->processGroupLand(msg); } -//************************************************* -//** LLGroupMoneyTabEventHandler::impl Functions ** -//************************************************* -class LLGroupMoneyTabEventHandler::impl -{ -public: - impl(LLButton* earlier_buttonp, - LLButton* later_buttonp, - LLTextEditor* text_editorp, - LLPanel* tabpanelp, - const std::string& loading_text, - const LLUUID& group_id, - S32 interval_length_days, - S32 max_interval_days); - ~impl(); - - bool getCanClickLater(); - bool getCanClickEarlier(); - - void updateButtons(); - -//member variables -public: - LLUUID mGroupID; - LLUUID mPanelID; - - LLPanel* mTabPanelp; - - int mIntervalLength; - int mMaxInterval; - int mCurrentInterval; - - LLTextEditor* mTextEditorp; - LLButton* mEarlierButtonp; - LLButton* mLaterButtonp; - - std::string mLoadingText; -}; - -LLGroupMoneyTabEventHandler::impl::impl(LLButton* earlier_buttonp, +LLGroupMoneyTabEventHandlerImpl::LLGroupMoneyTabEventHandlerImpl(LLButton* earlier_buttonp, LLButton* later_buttonp, LLTextEditor* text_editorp, LLPanel* tabpanelp, const std::string& loading_text, - const LLUUID& group_id, S32 interval_length_days, S32 max_interval_days) { - mGroupID = group_id; mPanelID.generate(); mIntervalLength = interval_length_days; @@ -851,21 +852,21 @@ LLGroupMoneyTabEventHandler::impl::impl(LLButton* earlier_buttonp, mLoadingText = loading_text; } -LLGroupMoneyTabEventHandler::impl::~impl() +LLGroupMoneyTabEventHandlerImpl::~LLGroupMoneyTabEventHandlerImpl() { } -bool LLGroupMoneyTabEventHandler::impl::getCanClickEarlier() +bool LLGroupMoneyTabEventHandlerImpl::getCanClickEarlier() { return (mCurrentInterval < mMaxInterval); } -bool LLGroupMoneyTabEventHandler::impl::getCanClickLater() +bool LLGroupMoneyTabEventHandlerImpl::getCanClickLater() { return ( mCurrentInterval > 0 ); } -void LLGroupMoneyTabEventHandler::impl::updateButtons() +void LLGroupMoneyTabEventHandlerImpl::updateButtons() { if ( mEarlierButtonp ) { @@ -890,16 +891,14 @@ LLGroupMoneyTabEventHandler::LLGroupMoneyTabEventHandler(LLButton* earlier_butto LLTabContainer* tab_containerp, LLPanel* panelp, const std::string& loading_text, - const LLUUID& group_id, S32 interval_length_days, S32 max_interval_days) { - mImplementationp = new impl(earlier_buttonp, + mImplementationp = new LLGroupMoneyTabEventHandlerImpl(earlier_buttonp, later_buttonp, text_editorp, panelp, loading_text, - group_id, interval_length_days, max_interval_days); @@ -917,8 +916,7 @@ LLGroupMoneyTabEventHandler::LLGroupMoneyTabEventHandler(LLButton* earlier_butto if ( tab_containerp && panelp ) { - tab_containerp->setTabChangeCallback(panelp, clickTabCallback); - tab_containerp->setTabUserData(panelp, this); + tab_containerp->setCommitCallback(boost::bind(&LLGroupMoneyTabEventHandler::onClickTab, this)); } sInstanceIDs.addData(mImplementationp->mPanelID, this); @@ -990,13 +988,6 @@ void LLGroupMoneyTabEventHandler::clickLaterCallback(void* data) if ( selfp ) selfp->onClickLater(); } -//static -void LLGroupMoneyTabEventHandler::clickTabCallback(void* data, bool from_click) -{ - LLGroupMoneyTabEventHandler* selfp = (LLGroupMoneyTabEventHandler*) data; - if ( selfp && from_click ) selfp->onClickTab(); -} - //************************************************** //** LLGroupMoneyDetailsTabEventHandler Functions ** //************************************************** @@ -1006,15 +997,13 @@ LLGroupMoneyDetailsTabEventHandler::LLGroupMoneyDetailsTabEventHandler(LLButton* LLTextEditor* text_editorp, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id) + const std::string& loading_text) : LLGroupMoneyTabEventHandler(earlier_buttonp, later_buttonp, text_editorp, tab_containerp, panelp, loading_text, - group_id, SUMMARY_INTERVAL, SUMMARY_MAX) { @@ -1030,7 +1019,7 @@ void LLGroupMoneyDetailsTabEventHandler::requestData(LLMessageSystem* msg) msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->mGroupID ); + msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->getGroupID() ); msg->nextBlockFast(_PREHASH_MoneyData); msg->addUUIDFast(_PREHASH_RequestID, mImplementationp->mPanelID ); msg->addS32Fast(_PREHASH_IntervalDays, mImplementationp->mIntervalLength ); @@ -1051,7 +1040,7 @@ void LLGroupMoneyDetailsTabEventHandler::processReply(LLMessageSystem* msg, { LLUUID group_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); - if (mImplementationp->mGroupID != group_id) + if (mImplementationp->getGroupID() != group_id) { llwarns << "Group Account details not for this group!" << llendl; return; @@ -1100,7 +1089,7 @@ void LLGroupMoneyDetailsTabEventHandler::processReply(LLMessageSystem* msg, text.append(1, '\n'); - text.append(llformat("%-24s %6d\n", "Total", total_amount)); + text.append(llformat("%-24s %6d\n", LLTrans::getString("GroupMoneyTotal").c_str(), total_amount)); if ( mImplementationp->mTextEditorp ) { @@ -1141,15 +1130,13 @@ LLGroupMoneySalesTabEventHandler::LLGroupMoneySalesTabEventHandler(LLButton* ear LLTextEditor* text_editorp, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id) + const std::string& loading_text) : LLGroupMoneyTabEventHandler(earlier_buttonp, later_buttonp, text_editorp, tab_containerp, panelp, loading_text, - group_id, SUMMARY_INTERVAL, SUMMARY_MAX) { @@ -1165,7 +1152,7 @@ void LLGroupMoneySalesTabEventHandler::requestData(LLMessageSystem* msg) msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->mGroupID ); + msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->getGroupID() ); msg->nextBlockFast(_PREHASH_MoneyData); msg->addUUIDFast(_PREHASH_RequestID, mImplementationp->mPanelID ); msg->addS32Fast(_PREHASH_IntervalDays, mImplementationp->mIntervalLength ); @@ -1186,7 +1173,7 @@ void LLGroupMoneySalesTabEventHandler::processReply(LLMessageSystem* msg, { LLUUID group_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); - if (mImplementationp->mGroupID != group_id) + if (mImplementationp->getGroupID() != group_id) { llwarns << "Group Account Transactions not for this group!" << llendl; return; @@ -1220,7 +1207,7 @@ void LLGroupMoneySalesTabEventHandler::processReply(LLMessageSystem* msg, S32 transactions = msg->getNumberOfBlocksFast(_PREHASH_HistoryData); if (transactions == 0) { - text.append("(none)"); + text.append(LLTrans::getString("none_text")); } else { @@ -1245,22 +1232,22 @@ void LLGroupMoneySalesTabEventHandler::processReply(LLMessageSystem* msg, switch(type) { case TRANS_OBJECT_SALE: - verb = "bought"; + verb = LLTrans::getString("GroupMoneyBought").c_str(); break; case TRANS_GIFT: - verb = "paid you"; + verb = LLTrans::getString("GroupMoneyPaidYou").c_str(); break; case TRANS_PAY_OBJECT: - verb = "paid into"; + verb = LLTrans::getString("GroupMoneyPaidInto").c_str(); break; case TRANS_LAND_PASS_SALE: - verb = "bought pass to"; + verb = LLTrans::getString("GroupMoneyBoughtPassTo").c_str(); break; case TRANS_EVENT_FEE: - verb = "paid fee for event"; + verb = LLTrans::getString("GroupMoneyPaidFeeForEvent").c_str(); break; case TRANS_EVENT_PRIZE: - verb = "paid prize for event"; + verb = LLTrans::getString("GroupMoneyPaidPrizeForEvent").c_str(); break; default: verb = ""; @@ -1313,15 +1300,13 @@ void LLPanelGroupLandMoney::processGroupAccountTransactionsReply(LLMessageSystem LLGroupMoneyPlanningTabEventHandler::LLGroupMoneyPlanningTabEventHandler(LLTextEditor* text_editorp, LLTabContainer* tab_containerp, LLPanel* panelp, - const std::string& loading_text, - const LLUUID& group_id) + const std::string& loading_text) : LLGroupMoneyTabEventHandler(NULL, NULL, text_editorp, tab_containerp, panelp, loading_text, - group_id, SUMMARY_INTERVAL, SUMMARY_MAX) { @@ -1337,7 +1322,7 @@ void LLGroupMoneyPlanningTabEventHandler::requestData(LLMessageSystem* msg) msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID() ); - msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->mGroupID ); + msg->addUUIDFast(_PREHASH_GroupID, mImplementationp->getGroupID() ); msg->nextBlockFast(_PREHASH_MoneyData); msg->addUUIDFast(_PREHASH_RequestID, mImplementationp->mPanelID ); msg->addS32Fast(_PREHASH_IntervalDays, mImplementationp->mIntervalLength); @@ -1358,7 +1343,7 @@ void LLGroupMoneyPlanningTabEventHandler::processReply(LLMessageSystem* msg, { LLUUID group_id; msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_GroupID, group_id ); - if (mImplementationp->mGroupID != group_id) + if (mImplementationp->getGroupID() != group_id) { llwarns << "Group Account Summary received not for this group!" << llendl; return; @@ -1420,24 +1405,24 @@ void LLGroupMoneyPlanningTabEventHandler::processReply(LLMessageSystem* msg, return; } - text.append("Summary for this week, beginning on "); + text.append(LLTrans::getString("SummaryForTheWeek")); text.append(start_date); if (current_interval == 0) { - text.append("The next stipend day is "); + text.append(LLTrans::getString("NextStipendDay")); text.append(next_stipend_date); text.append("\n\n"); - text.append(llformat("%-24sL$%6d\n", "Balance", balance )); + text.append(llformat("%-24sL$%6d\n", LLTrans::getString("GroupMoneyBalance").c_str(), balance )); text.append(1, '\n'); } // [DEV-29503] Hide the individual info since // non_exempt_member here is a wrong choice to calculate individual shares. - // text.append( " Group Individual Share\n"); - // text.append(llformat( "%-24s %6d %6d \n", "Credits", total_credits, (S32)floor((F32)total_credits/(F32)non_exempt_members))); - // text.append(llformat( "%-24s %6d %6d \n", "Debits", total_debits, (S32)floor((F32)total_debits/(F32)non_exempt_members))); - // text.append(llformat( "%-24s %6d %6d \n", "Total", total_credits + total_debits, (S32)floor((F32)(total_credits + total_debits)/(F32)non_exempt_members))); +// text.append( LLTrans::getString("GroupIndividualShare")); +// text.append(llformat( "%-24s %6d %6d \n", LLTrans::getString("GroupMoneyCredits").c_str(), total_credits, (S32)floor((F32)total_credits/(F32)non_exempt_members))); +// text.append(llformat( "%-24s %6d %6d \n", LLTrans::getString("GroupMoneyDebits").c_str(), total_debits, (S32)floor((F32)total_debits/(F32)non_exempt_members))); +// text.append(llformat( "%-24s %6d %6d \n", LLTrans::getString("GroupMoneyTotal").c_str(), total_credits + total_debits, (S32)floor((F32)(total_credits + total_debits)/(F32)non_exempt_members))); text.append( " Group\n"); text.append(llformat( "%-24s %6d\n", "Credits", total_credits)); @@ -1476,3 +1461,140 @@ void LLPanelGroupLandMoney::processGroupAccountSummaryReply(LLMessageSystem* msg self->processReply(msg, data); } + +void LLPanelGroupLandMoney::setGroupID(const LLUUID& id) +{ + LLPanelGroupLandMoney::sGroupIDs.removeData(mGroupID); + LLPanelGroupTab::setGroupID(id); + LLPanelGroupLandMoney::sGroupIDs.addData(mGroupID, this); + + + bool can_view = gAgent.isInGroup(mGroupID); + + mImplementationp->mGroupOverLimitIconp = + getChild("group_over_limit_icon"); + mImplementationp->mGroupOverLimitTextp = + getChild("group_over_limit_text"); + + mImplementationp->mYourContributionEditorp + = getChild("your_contribution_line_editor"); + if ( mImplementationp->mYourContributionEditorp ) + { + LLLineEditor* editor = mImplementationp->mYourContributionEditorp; + + editor->setCommitCallback(mImplementationp->contributionCommitCallback, this); + editor->setKeystrokeCallback(mImplementationp->contributionKeystrokeCallback, this); + } + + mImplementationp->mMapButtonp = getChild("map_button"); + + mImplementationp->mGroupParcelsp = + getChild("group_parcel_list"); + + if ( mImplementationp->mGroupParcelsp ) + { + mImplementationp->mGroupParcelsp->setCommitCallback(boost::bind(&LLButton::setEnabled, mImplementationp->mMapButtonp, true)); + mImplementationp->mGroupParcelsp->setCommitOnSelectionChange(true); + } + + mImplementationp->mCantViewParcelsText = getString("cant_view_group_land_text"); + mImplementationp->mCantViewAccountsText = getString("cant_view_group_accounting_text"); + + if ( mImplementationp->mMapButtonp ) + { + mImplementationp->mMapButtonp->setClickedCallback(LLPanelGroupLandMoney::impl::mapCallback, mImplementationp); + } + + if ( mImplementationp->mGroupOverLimitTextp ) + { + mImplementationp->mGroupOverLimitTextp->setVisible(FALSE); + } + + if ( mImplementationp->mGroupOverLimitIconp ) + { + mImplementationp->mGroupOverLimitIconp->setVisible(FALSE); + } + + if ( mImplementationp->mGroupParcelsp ) + { + mImplementationp->mGroupParcelsp->setEnabled(can_view); + } + + if ( !can_view && mImplementationp->mGroupParcelsp ) + { + mImplementationp->mGroupParcelsp->setEnabled(FALSE); + } + + + LLButton* earlierp, *laterp; + LLTextEditor* textp; + LLPanel* panelp; + + LLTabContainer* tabcp = getChild("group_money_tab_container"); + + if ( tabcp ) + { + S32 i; + S32 tab_count = tabcp->getTabCount(); + + for (i = tab_count - 1; i >=0; --i) + { + tabcp->enableTabButton(i, can_view ); + } + } + + std::string loading_text = getString("loading_txt"); + + //pull out the widgets for the L$ details tab + earlierp = getChild("earlier_details_button", true); + laterp = getChild("later_details_button", true); + textp = getChild("group_money_details_text", true); + panelp = getChild("group_money_details_tab", true); + + if ( !can_view ) + { + textp->setText(mImplementationp->mCantViewAccountsText); + } + else + { + if(mImplementationp->mMoneyDetailsTabEHp == 0) + mImplementationp->mMoneyDetailsTabEHp = new LLGroupMoneyDetailsTabEventHandler(earlierp,laterp,textp,tabcp,panelp,loading_text); + mImplementationp->mMoneyDetailsTabEHp->setGroupID(mGroupID); + } + + textp = getChild("group_money_planning_text", true); + + + if ( !can_view ) + { + textp->setText(mImplementationp->mCantViewAccountsText); + } + else + { + panelp = getChild("group_money_planning_tab", true); + if(mImplementationp->mMoneyPlanningTabEHp == 0) + mImplementationp->mMoneyPlanningTabEHp = new LLGroupMoneyPlanningTabEventHandler(textp,tabcp,panelp,loading_text); + mImplementationp->mMoneyPlanningTabEHp->setGroupID(mGroupID); + } + + //pull out the widgets for the L$ sales tab + textp = getChild("group_money_sales_text", true); + + + if ( !can_view ) + { + textp->setText(mImplementationp->mCantViewAccountsText); + } + else + { + earlierp = getChild("earlier_sales_button", true); + laterp = getChild("later_sales_button", true); + panelp = getChild("group_money_sales_tab", true); + if(mImplementationp->mMoneySalesTabEHp == NULL) + mImplementationp->mMoneySalesTabEHp = new LLGroupMoneySalesTabEventHandler(earlierp,laterp,textp,tabcp,panelp,loading_text); + mImplementationp->mMoneySalesTabEHp->setGroupID(mGroupID); + } + + activate(); +} + diff --git a/indra/newview/llpanelgrouplandmoney.h b/indra/newview/llpanelgrouplandmoney.h index 591511a5fb..0f275ea9a8 100644 --- a/indra/newview/llpanelgrouplandmoney.h +++ b/indra/newview/llpanelgrouplandmoney.h @@ -37,20 +37,14 @@ #include "llmap.h" #include "lluuid.h" -#include "llbutton.h" -#include "lltexteditor.h" -#include "llpanel.h" - class LLPanelGroupLandMoney : public LLPanelGroupTab { public: - LLPanelGroupLandMoney(const std::string& name, const LLUUID& group_id); + LLPanelGroupLandMoney(); virtual ~LLPanelGroupLandMoney(); virtual BOOL postBuild(); virtual BOOL isVisibleByAgent(LLAgent* agentp); - static void* createTab(void* data); - virtual void activate(); virtual bool needsApply(std::string& mesg); virtual bool apply(std::string& mesg); @@ -64,6 +58,8 @@ public: static void processGroupAccountDetailsReply(LLMessageSystem* msg, void** data); static void processGroupAccountTransactionsReply(LLMessageSystem* msg, void** data); static void processGroupAccountSummaryReply(LLMessageSystem* msg, void** data); + + virtual void setGroupID(const LLUUID& id); protected: class impl; diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 5824df46e2..0ce85818dd 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -39,8 +39,9 @@ #include "llinventory.h" #include "llviewerinventory.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llagent.h" +#include "llagentui.h" #include "lltooldraganddrop.h" #include "lllineeditor.h" @@ -49,13 +50,18 @@ #include "lliconctrl.h" #include "llcheckboxctrl.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" #include "lltextbox.h" +#include "lltrans.h" #include "roles_constants.h" #include "llviewerwindow.h" #include "llviewermessage.h" #include "llnotifications.h" +static LLRegisterPanelClassWrapper t_panel_group_notices("panel_group_notices"); + + ///////////////////////// // LLPanelGroupNotices // ///////////////////////// @@ -69,7 +75,21 @@ class LLGroupDropTarget : public LLView { public: - LLGroupDropTarget(const std::string& name, const LLRect& rect, LLPanelGroupNotices* panel, const LLUUID& group_id); + struct Params : public LLInitParam::Block + { + // *NOTE: These parameters logically Mandatory, but are not + // specified in XML files, hence Optional + Optional panel; + Optional group_id; + Params() + : panel("panel"), + group_id("group_id") + { + mouse_opaque(false); + follows.flags(FOLLOWS_ALL); + } + }; + LLGroupDropTarget(const Params&); ~LLGroupDropTarget() {}; void doDrop(EDragAndDropType cargo_type, void* cargo_data); @@ -81,18 +101,21 @@ public: void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); + void setPanel (LLPanelGroupNotices* panel) {mGroupNoticesPanel = panel;}; + void setGroup (LLUUID group) {mGroupID = group;}; + protected: LLPanelGroupNotices* mGroupNoticesPanel; LLUUID mGroupID; }; -LLGroupDropTarget::LLGroupDropTarget(const std::string& name, const LLRect& rect, - LLPanelGroupNotices* panel, const LLUUID& group_id) : - LLView(name, rect, NOT_MOUSE_OPAQUE, FOLLOWS_ALL), - mGroupNoticesPanel(panel), - mGroupID(group_id) -{ -} +static LLDefaultChildRegistry::Register r("group_drop_target"); + +LLGroupDropTarget::LLGroupDropTarget(const LLGroupDropTarget::Params& p) +: LLView(p), + mGroupNoticesPanel(p.panel), + mGroupID(p.group_id) +{} void LLGroupDropTarget::doDrop(EDragAndDropType cargo_type, void* cargo_data) { @@ -133,6 +156,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: + case DAD_CALLINGCARD: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) @@ -156,7 +180,6 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, break; } case DAD_CATEGORY: - case DAD_CALLINGCARD: default: *accept = ACCEPT_NO; break; @@ -179,22 +202,22 @@ std::string build_notice_date(const U32& the_time) time(&t); } - tm* lt = localtime(&t); - - //for some reason, the month is off by 1. See other uses of - //"local" time in the code... - std::string buffer = llformat("%04i-%02i-%02i", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday); - - return buffer; + std::string dateStr = "["+LLTrans::getString("LTimeMthNum")+"]/[" + +LLTrans::getString("LTimeDay")+"]/[" + +LLTrans::getString("LTimeYear")+"]"; + LLSD substitution; + substitution["datetime"] = (S32) t; + LLStringUtil::format (dateStr, substitution); + return dateStr; } -LLPanelGroupNotices::LLPanelGroupNotices(const std::string& name, - const LLUUID& group_id) : - LLPanelGroupTab(name,group_id), +LLPanelGroupNotices::LLPanelGroupNotices() : + LLPanelGroupTab(), mInventoryItem(NULL), mInventoryOffer(NULL) { - sInstances[group_id] = this; + + } LLPanelGroupNotices::~LLPanelGroupNotices() @@ -210,12 +233,6 @@ LLPanelGroupNotices::~LLPanelGroupNotices() } } -// static -void* LLPanelGroupNotices::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupNotices("panel group notices", *group_id); -} BOOL LLPanelGroupNotices::isVisibleByAgent(LLAgent* agentp) { @@ -229,17 +246,14 @@ BOOL LLPanelGroupNotices::postBuild() mNoticesList = getChild("notice_list",recurse); mNoticesList->setCommitOnSelectionChange(TRUE); - mNoticesList->setCommitCallback(onSelectNotice); - mNoticesList->setCallbackUserData(this); + mNoticesList->setCommitCallback(onSelectNotice, this); mBtnNewMessage = getChild("create_new_notice",recurse); - mBtnNewMessage->setClickedCallback(onClickNewMessage); - mBtnNewMessage->setCallbackUserData(this); + mBtnNewMessage->setClickedCallback(onClickNewMessage, this); mBtnNewMessage->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_NOTICES_SEND)); mBtnGetPastNotices = getChild("refresh_notices",recurse); - mBtnGetPastNotices->setClickedCallback(onClickRefreshNotices); - mBtnGetPastNotices->setCallbackUserData(this); + mBtnGetPastNotices->setClickedCallback(onClickRefreshNotices, this); // Create mCreateSubject = getChild("create_subject",recurse); @@ -253,12 +267,10 @@ BOOL LLPanelGroupNotices::postBuild() mCreateInventoryIcon->setVisible(FALSE); mBtnSendMessage = getChild("send_notice",recurse); - mBtnSendMessage->setClickedCallback(onClickSendMessage); - mBtnSendMessage->setCallbackUserData(this); + mBtnSendMessage->setClickedCallback(onClickSendMessage, this); mBtnRemoveAttachment = getChild("remove_attachment",recurse); - mBtnRemoveAttachment->setClickedCallback(onClickRemoveAttachment); - mBtnRemoveAttachment->setCallbackUserData(this); + mBtnRemoveAttachment->setClickedCallback(onClickRemoveAttachment, this); mBtnRemoveAttachment->setEnabled(FALSE); // View @@ -273,24 +285,16 @@ BOOL LLPanelGroupNotices::postBuild() mViewInventoryIcon->setVisible(FALSE); mBtnOpenAttachment = getChild("open_attachment",recurse); - mBtnOpenAttachment->setClickedCallback(onClickOpenAttachment); - mBtnOpenAttachment->setCallbackUserData(this); + mBtnOpenAttachment->setClickedCallback(onClickOpenAttachment, this); mNoNoticesStr = getString("no_notices_text"); mPanelCreateNotice = getChild("panel_create_new_notice",recurse); mPanelViewNotice = getChild("panel_view_past_notice",recurse); - // Must be in front of all other UI elements. - LLPanel* dtv = getChild("drop_target",recurse); - LLGroupDropTarget* target = new LLGroupDropTarget("drop_target", - dtv->getRect(), - this, mGroupID); - target->setEnabled(TRUE); - target->setToolTip(dtv->getToolTip()); - - mPanelCreateNotice->addChild(target); - mPanelCreateNotice->removeChild(dtv, TRUE); + LLGroupDropTarget* target = getChild ("drop_target"); + target->setPanel (this); + target->setGroup (mGroupID); arrangeNoticeView(VIEW_PAST_NOTICE); @@ -331,7 +335,7 @@ void LLPanelGroupNotices::setItem(LLPointer inv_item) inv_item->getFlags(), item_is_multi ); - mCreateInventoryIcon->setImage(icon_name); + mCreateInventoryIcon->setValue(icon_name); mCreateInventoryIcon->setVisible(TRUE); std::stringstream ss; @@ -376,13 +380,38 @@ void LLPanelGroupNotices::onClickSendMessage(void* data) self->mCreateMessage->getText(), self->mInventoryItem); + + //instantly add new notice. actual notice will be added after ferreshNotices call + LLUUID id = LLUUID::generateNewID(); + std::string subj = self->mCreateSubject->getText(); + std::string name ; + LLAgentUI::buildFullname(name); + U32 timestamp = 0; + + LLSD row; + row["id"] = id; + + row["columns"][0]["column"] = "icon"; + + row["columns"][1]["column"] = "subject"; + row["columns"][1]["value"] = subj; + + row["columns"][2]["column"] = "from"; + row["columns"][2]["value"] = name; + + row["columns"][3]["column"] = "date"; + row["columns"][3]["value"] = build_notice_date(timestamp); + + row["columns"][4]["column"] = "sort"; + row["columns"][4]["value"] = llformat( "%u", timestamp); + + self->mNoticesList->addElement(row, ADD_BOTTOM); + self->mCreateMessage->clear(); self->mCreateSubject->clear(); onClickRemoveAttachment(data); self->arrangeNoticeView(VIEW_PAST_NOTICE); - onClickRefreshNotices(self); - } //static @@ -404,6 +433,26 @@ void LLPanelGroupNotices::onClickNewMessage(void* data) self->mNoticesList->deselectAllItems(TRUE); // TRUE == don't commit on chnage } +void LLPanelGroupNotices::refreshNotices() +{ + onClickRefreshNotices(this); + /* + lldebugs << "LLPanelGroupNotices::onClickGetPastNotices" << llendl; + + mNoticesList->deleteAllItems(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessage("GroupNoticesListRequest"); + msg->nextBlock("AgentData"); + msg->addUUID("AgentID",gAgent.getID()); + msg->addUUID("SessionID",gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("GroupID",self->mGroupID); + gAgent.sendReliableMessage(); + */ + +} + void LLPanelGroupNotices::onClickRefreshNotices(void* data) { lldebugs << "LLPanelGroupNotices::onClickGetPastNotices" << llendl; @@ -466,7 +515,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) if (1 == count && id.isNull()) { // Only one entry, the dummy entry. - mNoticesList->addCommentText(mNoNoticesStr); + mNoticesList->setCommentText(mNoNoticesStr); mNoticesList->setEnabled(FALSE); return; } @@ -505,7 +554,7 @@ void LLPanelGroupNotices::processNotices(LLMessageSystem* msg) mNoticesList->addElement(row, ADD_BOTTOM); } - mNoticesList->sortItems(); + mNoticesList->updateSort(); } void LLPanelGroupNotices::onSelectNotice(LLUICtrl* ctrl, void* data) @@ -554,7 +603,7 @@ void LLPanelGroupNotices::showNotice(const std::string& subject, LLInventoryType::IT_TEXTURE, 0, FALSE); - mViewInventoryIcon->setImage(icon_name); + mViewInventoryIcon->setValue(icon_name); mViewInventoryIcon->setVisible(TRUE); std::stringstream ss; @@ -585,3 +634,17 @@ void LLPanelGroupNotices::arrangeNoticeView(ENoticeView view_type) mBtnOpenAttachment->setEnabled(FALSE); } } +void LLPanelGroupNotices::setGroupID(const LLUUID& id) +{ + sInstances.erase(mGroupID); + LLPanelGroupTab::setGroupID(id); + sInstances[mGroupID] = this; + + mBtnNewMessage->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_NOTICES_SEND)); + + LLGroupDropTarget* target = getChild ("drop_target"); + target->setPanel (this); + target->setGroup (mGroupID); + + activate(); +} diff --git a/indra/newview/llpanelgroupnotices.h b/indra/newview/llpanelgroupnotices.h index 916032c1b6..4bda38c897 100644 --- a/indra/newview/llpanelgroupnotices.h +++ b/indra/newview/llpanelgroupnotices.h @@ -34,7 +34,7 @@ #define LL_LLPANELGROUPNOTICES_H #include "llpanelgroup.h" -#include "llmemory.h" +#include "llpointer.h" #include "llinventory.h" class LLLineEditor; @@ -47,11 +47,10 @@ class LLScrollListCtrl; class LLPanelGroupNotices : public LLPanelGroupTab { public: - LLPanelGroupNotices(const std::string& name, const LLUUID& group_id); + LLPanelGroupNotices(); virtual ~LLPanelGroupNotices(); // LLPanelGroupTab - static void* createTab(void* data); virtual void activate(); //virtual bool needsApply(std::string& mesg); //virtual bool apply(std::string& mesg); @@ -70,6 +69,10 @@ public: const std::string& inventory_name, LLOfferInfo* inventory_offer); + void refreshNotices(); + + virtual void setGroupID(const LLUUID& id); + private: static void onClickRemoveAttachment(void* data); static void onClickOpenAttachment(void* data); diff --git a/indra/newview/llpanelgrouproles.cpp b/indra/newview/llpanelgrouproles.cpp index 6e65181f99..4618b49df4 100644 --- a/indra/newview/llpanelgrouproles.cpp +++ b/indra/newview/llpanelgrouproles.cpp @@ -36,23 +36,28 @@ #include "llagent.h" #include "llbutton.h" -#include "llfloateravatarinfo.h" #include "llfloatergroupinvite.h" +#include "llavataractions.h" #include "lliconctrl.h" #include "lllineeditor.h" #include "llnamelistctrl.h" #include "llnotify.h" #include "llpanelgrouproles.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lltabcontainer.h" #include "lltextbox.h" #include "lltexteditor.h" -#include "llviewerimagelist.h" +#include "llsearcheditor.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llfocusmgr.h" #include "roles_constants.h" +static LLRegisterPanelClassWrapper t_panel_group_roles("panel_group_roles"); + bool agentCanRemoveFromRole(const LLUUID& group_id, const LLUUID& role_id) { @@ -106,14 +111,9 @@ bool agentCanAddToRole(const LLUUID& group_id, } // static -void* LLPanelGroupRoles::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupRoles("panel group roles", *group_id); -} -LLPanelGroupRoles::LLPanelGroupRoles(const std::string& name, const LLUUID& group_id) -: LLPanelGroupTab(name, group_id), +LLPanelGroupRoles::LLPanelGroupRoles() +: LLPanelGroupTab(), mCurrentTab(NULL), mRequestedTab( NULL ), mSubTabContainer( NULL ), @@ -124,13 +124,6 @@ LLPanelGroupRoles::LLPanelGroupRoles(const std::string& name, const LLUUID& grou LLPanelGroupRoles::~LLPanelGroupRoles() { - int i; - for (i = 0; i < mSubTabContainer->getTabCount(); ++i) - { - LLPanelGroupSubTab* subtabp = (LLPanelGroupSubTab*) mSubTabContainer->getPanelByIndex(i); - - subtabp->removeObserver(this); - } } BOOL LLPanelGroupRoles::postBuild() @@ -142,20 +135,24 @@ BOOL LLPanelGroupRoles::postBuild() if (!mSubTabContainer) return FALSE; // Hook up each sub-tabs callback and widgets. - S32 i; - for (i = 0; i < mSubTabContainer->getTabCount(); ++i) + for (S32 i = 0; i < mSubTabContainer->getTabCount(); ++i) { - LLPanelGroupSubTab* subtabp = (LLPanelGroupSubTab*) mSubTabContainer->getPanelByIndex(i); - + LLPanel* panel = mSubTabContainer->getPanelByIndex(i); + LLPanelGroupSubTab* subtabp = dynamic_cast(panel); + if (!subtabp) + { + llwarns << "Invalid subtab panel: " << panel->getName() << llendl; + return FALSE; + } // Add click callbacks to all the tabs. - mSubTabContainer->setTabChangeCallback(subtabp, onClickSubTab); - mSubTabContainer->setTabUserData(subtabp, this); + mSubTabContainer->setCommitCallback(boost::bind(&LLPanelGroupRoles::handleClickSubTab, this)); // Hand the subtab a pointer to this LLPanelGroupRoles, so that it can // look around for the widgets it is interested in. - if (!subtabp->postBuildSubTab(this)) return FALSE; + if (!subtabp->postBuildSubTab(this)) + return FALSE; - subtabp->addObserver(this); + //subtabp->addObserver(this); } // Set the current tab to whatever is currently being shown. @@ -198,13 +195,6 @@ BOOL LLPanelGroupRoles::isVisibleByAgent(LLAgent* agentp) } -// static -void LLPanelGroupRoles::onClickSubTab(void* user_data, bool from_click) -{ - LLPanelGroupRoles* self = static_cast(user_data); - self->handleClickSubTab(); -} - void LLPanelGroupRoles::handleClickSubTab() { // If we are already handling a transition, @@ -388,7 +378,8 @@ std::string LLPanelGroupRoles::getHelpText() const void LLPanelGroupRoles::update(LLGroupChange gc) { if (mGroupID.isNull()) return; - + + LLPanelGroupTab* panelp = (LLPanelGroupTab*) mSubTabContainer->getCurrentPanel(); if (panelp) { @@ -398,6 +389,7 @@ void LLPanelGroupRoles::update(LLGroupChange gc) { llwarns << "LLPanelGroupRoles::update() -- No subtab to update!" << llendl; } + } void LLPanelGroupRoles::activate() @@ -465,22 +457,15 @@ BOOL LLPanelGroupRoles::hasModal() return panelp->hasModal(); } -// PanelGroupTab observer trigger -void LLPanelGroupRoles::tabChanged() -{ - notifyObservers(); -} //////////////////////////// // LLPanelGroupSubTab //////////////////////////// -LLPanelGroupSubTab::LLPanelGroupSubTab(const std::string& name, const LLUUID& group_id) -: LLPanelGroupTab(name, group_id), +LLPanelGroupSubTab::LLPanelGroupSubTab() +: LLPanelGroupTab(), mHeader(NULL), mFooter(NULL), - mSearchLineEditor(NULL), - mSearchButton(NULL), - mShowAllButton(NULL) + mSearchEditor(NULL) { } @@ -492,112 +477,65 @@ BOOL LLPanelGroupSubTab::postBuild() { // Hook up the search widgets. bool recurse = true; - mSearchLineEditor = getChild("search_text", recurse); + mSearchEditor = getChild("filter_input", recurse); - if (!mSearchLineEditor) return FALSE; - mSearchLineEditor->setKeystrokeCallback(onSearchKeystroke); - mSearchLineEditor->setCallbackUserData(this); + if (!mSearchEditor) + return FALSE; - mSearchButton = getChild("search_button", recurse); + mSearchEditor->setCommitCallback(boost::bind(&LLPanelGroupSubTab::onClickSearch, this)); + mSearchEditor->setKeystrokeCallback(onSearchKeystroke, this); - if (!mSearchButton) return FALSE; - mSearchButton->setClickedCallback(onClickSearch); - mSearchButton->setCallbackUserData(this); - mSearchButton->setEnabled(FALSE); - - mShowAllButton = getChild("show_all_button", recurse); - - if (!mShowAllButton) return FALSE; - mShowAllButton->setClickedCallback(onClickShowAll); - mShowAllButton->setCallbackUserData(this); - mShowAllButton->setEnabled(FALSE); // Get icons for later use. mActionIcons.clear(); - bool no_recurse = false; - - LLIconCtrl* icon = getChild("power_folder_icon",no_recurse); - if (icon && !icon->getImageName().empty()) + if (hasString("power_folder_icon")) { - mActionIcons["folder"] = icon->getImageName(); - removeChild(icon, TRUE); + mActionIcons["folder"] = getString("power_folder_icon"); } - icon = getChild("power_all_have_icon",no_recurse); - if (icon && !icon->getImageName().empty()) + if (hasString("power_all_have_icon")) { - mActionIcons["full"] = icon->getImageName(); - removeChild(icon, TRUE); + mActionIcons["full"] = getString("power_all_have_icon"); } - icon = getChild("power_partial_icon",no_recurse); - if (icon && !icon->getImageName().empty()) + if (hasString("power_partial_icon")) { - mActionIcons["partial"] = icon->getImageName(); - removeChild(icon, TRUE); + mActionIcons["partial"] = getString("power_partial_icon"); } return LLPanelGroupTab::postBuild(); } +void LLPanelGroupSubTab::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + if(mSearchEditor) + { + mSearchEditor->clear(); + setSearchFilter(""); + } +} + // static void LLPanelGroupSubTab::onSearchKeystroke(LLLineEditor* caller, void* user_data) { LLPanelGroupSubTab* self = static_cast(user_data); self->handleSearchKeystroke(caller); + } void LLPanelGroupSubTab::handleSearchKeystroke(LLLineEditor* caller) { - if (caller->getText().size()) - { - setDefaultBtn( mSearchButton ); - mSearchButton->setEnabled(TRUE); - } - else - { - setDefaultBtn( NULL ); - mSearchButton->setEnabled(FALSE); - } + setSearchFilter( caller->getText() ); } // static -void LLPanelGroupSubTab::onClickSearch(void* user_data) +void LLPanelGroupSubTab::onClickSearch() { - LLPanelGroupSubTab* self = static_cast(user_data); - self->handleClickSearch(); + setSearchFilter( mSearchEditor->getText() ); } -void LLPanelGroupSubTab::handleClickSearch() -{ - lldebugs << "LLPanelGroupSubTab::handleClickSearch()" << llendl; - - if (0 == mSearchLineEditor->getText().size()) - { - // No search text. (This shouldn't happen... the search button should have been disabled). - llwarns << "handleClickSearch with no search text!" << llendl; - mSearchButton->setEnabled(FALSE); - return; - } - - setSearchFilter( mSearchLineEditor->getText() ); - mShowAllButton->setEnabled(TRUE); -} - -// static -void LLPanelGroupSubTab::onClickShowAll(void* user_data) -{ - LLPanelGroupSubTab* self = static_cast(user_data); - self->handleClickShowAll(); -} - -void LLPanelGroupSubTab::handleClickShowAll() -{ - lldebugs << "LLPanelGroupSubTab::handleClickShowAll()" << llendl; - setSearchFilter( LLStringUtil::null ); - mShowAllButton->setEnabled(FALSE); -} void LLPanelGroupSubTab::setSearchFilter(const std::string& filter) { @@ -663,7 +601,7 @@ void LLPanelGroupSubTab::buildActionsList(LLScrollListCtrl* ctrl, U64 allowed_by_some, U64 allowed_by_all, icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role) @@ -696,7 +634,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, U64 allowed_by_all, LLRoleActionSet* action_set, icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role) @@ -718,7 +656,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][1]["column"] = "action"; row["columns"][1]["value"] = action_set->mActionSetData->mName; - row["columns"][1]["font-style"] = "BOLD"; + row["columns"][1]["font"]["style"] = "BOLD"; LLScrollListItem* title_row = ctrl->addElement(row, ADD_BOTTOM, action_set->mActionSetData); @@ -799,7 +737,7 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, row["columns"][column_index]["column"] = "action"; row["columns"][column_index]["value"] = (*ra_it)->mDescription; - row["columns"][column_index]["font"] = "SANSSERIFSMALL"; + row["columns"][column_index]["font"] = "SANSSERIF_SMALL"; LLScrollListItem* item = ctrl->addElement(row, ADD_BOTTOM, (*ra_it)); @@ -810,7 +748,6 @@ void LLPanelGroupSubTab::buildActionCategory(LLScrollListCtrl* ctrl, LLCheckBoxCtrl* check = check_cell->getCheckBox(); check->setEnabled(can_change_actions); check->setCommitCallback(commit_callback); - check->setCallbackUserData(ctrl->getCallbackUserData()); check->setToolTip( check->getLabel() ); if (show_all) @@ -860,15 +797,11 @@ void LLPanelGroupSubTab::setFooterEnabled(BOOL enable) // LLPanelGroupMembersSubTab //////////////////////////// -// static -void* LLPanelGroupMembersSubTab::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupMembersSubTab("panel group members sub tab", *group_id); -} -LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab(const std::string& name, const LLUUID& group_id) -: LLPanelGroupSubTab(name, group_id), +static LLRegisterPanelClassWrapper t_panel_group_members_subtab("panel_group_members_subtab"); + +LLPanelGroupMembersSubTab::LLPanelGroupMembersSubTab() +: LLPanelGroupSubTab(), mMembersList(NULL), mAssignedRolesList(NULL), mAllowedActionsList(NULL), @@ -900,31 +833,34 @@ BOOL LLPanelGroupMembersSubTab::postBuildSubTab(LLView* root) if (!mMembersList || !mAssignedRolesList || !mAllowedActionsList) return FALSE; // We want to be notified whenever a member is selected. - mMembersList->setCallbackUserData(this); mMembersList->setCommitOnSelectionChange(TRUE); - mMembersList->setCommitCallback(onMemberSelect); + mMembersList->setCommitCallback(onMemberSelect, this); // Show the member's profile on double click. - mMembersList->setDoubleClickCallback(onMemberDoubleClick); + mMembersList->setDoubleClickCallback(onMemberDoubleClick, this); LLButton* button = parent->getChild("member_invite", recurse); if ( button ) { - button->setClickedCallback(onInviteMember); - button->setCallbackUserData(this); + button->setClickedCallback(onInviteMember, this); button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); } mEjectBtn = parent->getChild("member_eject", recurse); if ( mEjectBtn ) { - mEjectBtn->setClickedCallback(onEjectMembers); - mEjectBtn->setCallbackUserData(this); + mEjectBtn->setClickedCallback(onEjectMembers, this); mEjectBtn->setEnabled(FALSE); } return TRUE; } +void LLPanelGroupMembersSubTab::setGroupID(const LLUUID& id) +{ + LLPanelGroupSubTab::setGroupID(id); + +} + // static void LLPanelGroupMembersSubTab::onMemberSelect(LLUICtrl* ctrl, void* user_data) @@ -1097,8 +1033,7 @@ void LLPanelGroupMembersSubTab::handleMemberSelect() // Extract the checkbox that was created. LLScrollListCheck* check_cell = (LLScrollListCheck*) item->getColumn(0); LLCheckBoxCtrl* check = check_cell->getCheckBox(); - check->setCommitCallback(onRoleCheck); - check->setCallbackUserData(this); + check->setCommitCallback(onRoleCheck, this); check->set( count > 0 ); check->setTentative( (0 != count) @@ -1311,7 +1246,7 @@ void LLPanelGroupMembersSubTab::handleMemberDoubleClick() LLScrollListItem* selected = mMembersList->getFirstSelected(); if (selected) { - LLFloaterAvatarInfo::showFromDirectory( selected->getUUID() ); + LLAvatarActions::showProfile(selected->getUUID()); } } @@ -1628,7 +1563,7 @@ void LLPanelGroupMembersSubTab::update(LLGroupChange gc) retrieved << "Retrieving role member mappings..."; } mMembersList->setEnabled(FALSE); - mMembersList->addCommentText(retrieved.str()); + mMembersList->setCommentText(retrieved.str()); } } @@ -1691,7 +1626,7 @@ void LLPanelGroupMembersSubTab::updateMembers() row["columns"][2]["column"] = "online"; row["columns"][2]["value"] = mMemberProgress->second->getOnlineStatus(); - row["columns"][2]["font"] = "SANSSERIFSMALL"; + row["columns"][2]["font"] = "SANSSERIF_SMALL"; mMembersList->addElement(row);//, ADD_SORTED); mHasMatch = TRUE; @@ -1707,7 +1642,7 @@ void LLPanelGroupMembersSubTab::updateMembers() else { mMembersList->setEnabled(FALSE); - mMembersList->addCommentText(std::string("No match.")); + mMembersList->setCommentText(std::string("No match.")); } } else @@ -1725,15 +1660,21 @@ void LLPanelGroupMembersSubTab::updateMembers() // LLPanelGroupRolesSubTab //////////////////////////// -// static -void* LLPanelGroupRolesSubTab::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupRolesSubTab("panel group roles sub tab", *group_id); -} +static LLRegisterPanelClassWrapper t_panel_group_roles_subtab("panel_group_roles_subtab"); -LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab(const std::string& name, const LLUUID& group_id) -: LLPanelGroupSubTab(name, group_id), mHasRoleChange(FALSE) +LLPanelGroupRolesSubTab::LLPanelGroupRolesSubTab() + : LLPanelGroupSubTab(), + mRolesList(NULL), + mAssignedMembersList(NULL), + mAllowedActionsList(NULL), + mRoleName(NULL), + mRoleTitle(NULL), + mRoleDescription(NULL), + mMemberVisibleCheck(NULL), + mDeleteRoleButton(NULL), + mCreateRoleButton(NULL), + + mHasRoleChange(FALSE) { } @@ -1775,8 +1716,7 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) parent->getChild("role_create", recurse); if ( mCreateRoleButton ) { - mCreateRoleButton->setCallbackUserData(this); - mCreateRoleButton->setClickedCallback(onCreateRole); + mCreateRoleButton->setClickedCallback(onCreateRole, this); mCreateRoleButton->setEnabled(FALSE); } @@ -1784,32 +1724,25 @@ BOOL LLPanelGroupRolesSubTab::postBuildSubTab(LLView* root) parent->getChild("role_delete", recurse); if ( mDeleteRoleButton ) { - mDeleteRoleButton->setCallbackUserData(this); - mDeleteRoleButton->setClickedCallback(onDeleteRole); + mDeleteRoleButton->setClickedCallback(onDeleteRole, this); mDeleteRoleButton->setEnabled(FALSE); } mRolesList->setCommitOnSelectionChange(TRUE); - mRolesList->setCallbackUserData(this); - mRolesList->setCommitCallback(onRoleSelect); + mRolesList->setCommitCallback(onRoleSelect, this); - mMemberVisibleCheck->setCallbackUserData(this); - mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange); + mMemberVisibleCheck->setCommitCallback(onMemberVisibilityChange, this); mAllowedActionsList->setCommitOnSelectionChange(TRUE); - mAllowedActionsList->setCallbackUserData(this); mRoleName->setCommitOnFocusLost(TRUE); - mRoleName->setCallbackUserData(this); - mRoleName->setKeystrokeCallback(onPropertiesKey); + mRoleName->setKeystrokeCallback(onPropertiesKey, this); mRoleTitle->setCommitOnFocusLost(TRUE); - mRoleTitle->setCallbackUserData(this); - mRoleTitle->setKeystrokeCallback(onPropertiesKey); + mRoleTitle->setKeystrokeCallback(onPropertiesKey, this); mRoleDescription->setCommitOnFocusLost(TRUE); - mRoleDescription->setCallbackUserData(this); - mRoleDescription->setCommitCallback(onDescriptionCommit); + mRoleDescription->setCommitCallback(onDescriptionCommit, this); mRoleDescription->setFocusReceivedCallback(onDescriptionFocus, this); setFooterEnabled(FALSE); @@ -2060,7 +1993,7 @@ void LLPanelGroupRolesSubTab::handleRoleSelect() rd.mRolePowers, 0LL, mActionIcons, - onActionCheck, + boost::bind(&LLPanelGroupRolesSubTab::handleActionCheck, this, _1, false), TRUE, FALSE, is_owner_role); @@ -2157,24 +2090,18 @@ void LLPanelGroupRolesSubTab::buildMembersList() } } -// static -void LLPanelGroupRolesSubTab::onActionCheck(LLUICtrl* ctrl, void* user_data) -{ - LLPanelGroupRolesSubTab* self = static_cast(user_data); - LLCheckBoxCtrl* check = static_cast(ctrl); - if (!check || !self) return; - - self->handleActionCheck(check); -} - struct ActionCBData { LLPanelGroupRolesSubTab* mSelf; LLCheckBoxCtrl* mCheck; }; -void LLPanelGroupRolesSubTab::handleActionCheck(LLCheckBoxCtrl* check, bool force) +void LLPanelGroupRolesSubTab::handleActionCheck(LLUICtrl* ctrl, bool force) { + LLCheckBoxCtrl* check = dynamic_cast(ctrl); + if (!check) + return; + lldebugs << "LLPanelGroupRolesSubTab::handleActionSelect()" << llendl; LLGroupMgrGroupData* gdatap = LLGroupMgr::getInstance()->getGroupData(mGroupID); @@ -2438,15 +2365,11 @@ void LLPanelGroupRolesSubTab::saveRoleChanges() // LLPanelGroupActionsSubTab //////////////////////////// -// static -void* LLPanelGroupActionsSubTab::createTab(void* data) -{ - LLUUID* group_id = static_cast(data); - return new LLPanelGroupActionsSubTab("panel group actions sub tab", *group_id); -} +static LLRegisterPanelClassWrapper t_panel_group_actions_subtab("panel_group_actions_subtab"); -LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab(const std::string& name, const LLUUID& group_id) -: LLPanelGroupSubTab(name, group_id) + +LLPanelGroupActionsSubTab::LLPanelGroupActionsSubTab() +: LLPanelGroupSubTab() { } @@ -2472,12 +2395,8 @@ BOOL LLPanelGroupActionsSubTab::postBuildSubTab(LLView* root) if (!mActionList || !mActionDescription || !mActionRoles || !mActionMembers) return FALSE; - mActionList->setCallbackUserData(this); mActionList->setCommitOnSelectionChange(TRUE); - mActionList->setCommitCallback(onActionSelect); - - mActionMembers->setCallbackUserData(this); - mActionRoles->setCallbackUserData(this); + mActionList->setCommitCallback(boost::bind(&LLPanelGroupActionsSubTab::handleActionSelect, this)); update(GC_ALL); @@ -2537,13 +2456,6 @@ void LLPanelGroupActionsSubTab::update(LLGroupChange gc) FALSE); } -// static -void LLPanelGroupActionsSubTab::onActionSelect(LLUICtrl* scroll, void* data) -{ - LLPanelGroupActionsSubTab* self = static_cast(data); - self->handleActionSelect(); -} - void LLPanelGroupActionsSubTab::handleActionSelect() { mActionMembers->deleteAllItems(); @@ -2629,3 +2541,26 @@ void LLPanelGroupActionsSubTab::handleActionSelect() LLGroupMgr::getInstance()->sendGroupRoleDataRequest(mGroupID); } } +void LLPanelGroupRoles::setGroupID(const LLUUID& id) +{ + LLPanelGroupTab::setGroupID(id); + + LLPanelGroupMembersSubTab* group_members_tab = findChild("members_sub_tab"); + LLPanelGroupRolesSubTab* group_roles_tab = findChild("roles_sub_tab"); + LLPanelGroupActionsSubTab* group_actions_tab = findChild("actions_sub_tab"); + + if(group_members_tab) group_members_tab->setGroupID(id); + if(group_roles_tab) group_roles_tab->setGroupID(id); + if(group_actions_tab) group_actions_tab->setGroupID(id); + + LLButton* button = getChild("member_invite"); + if ( button ) + button->setEnabled(gAgent.hasPowerInGroup(mGroupID, GP_MEMBER_INVITE)); + + if(mSubTabContainer) + mSubTabContainer->selectTab(0); + + activate(); +} + + diff --git a/indra/newview/llpanelgrouproles.h b/indra/newview/llpanelgrouproles.h index 95057bbfaf..2a0f31fa0f 100644 --- a/indra/newview/llpanelgrouproles.h +++ b/indra/newview/llpanelgrouproles.h @@ -42,17 +42,18 @@ class LLPanelGroupRolesSubTab; class LLPanelGroupActionsSubTab; class LLScrollListCtrl; class LLScrollListItem; +class LLTextEditor; +class LLSearchEditor; // Forward declare for friend usage. //virtual BOOL LLPanelGroupSubTab::postBuildSubTab(LLView*); typedef std::map icon_map_t; -class LLPanelGroupRoles : public LLPanelGroupTab, - public LLPanelGroupTabObserver +class LLPanelGroupRoles : public LLPanelGroupTab { public: - LLPanelGroupRoles(const std::string& name, const LLUUID& group_id); + LLPanelGroupRoles(); virtual ~LLPanelGroupRoles(); // Allow sub tabs to ask for sibling controls. @@ -63,8 +64,7 @@ public: virtual BOOL postBuild(); virtual BOOL isVisibleByAgent(LLAgent* agentp); - static void* createTab(void* data); - static void onClickSubTab(void*,bool); + void handleClickSubTab(); // Checks if the current tab needs to be applied, and tries to switch to the requested tab. @@ -87,8 +87,7 @@ public: virtual void cancel(); virtual void update(LLGroupChange gc); - // PanelGroupTab observer trigger - virtual void tabChanged(); + virtual void setGroupID(const LLUUID& id); protected: LLPanelGroupTab* mCurrentTab; @@ -104,7 +103,7 @@ protected: class LLPanelGroupSubTab : public LLPanelGroupTab { public: - LLPanelGroupSubTab(const std::string& name, const LLUUID& group_id); + LLPanelGroupSubTab(); virtual ~LLPanelGroupSubTab(); virtual BOOL postBuild(); @@ -115,10 +114,7 @@ public: static void onSearchKeystroke(LLLineEditor* caller, void* user_data); void handleSearchKeystroke(LLLineEditor* caller); - static void onClickSearch(void*); - void handleClickSearch(); - static void onClickShowAll(void*); - void handleClickShowAll(); + void onClickSearch(); virtual void setSearchFilter( const std::string& filter ); @@ -131,7 +127,7 @@ public: U64 allowed_by_some, U64 allowed_by_all, icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role); @@ -140,19 +136,19 @@ public: U64 allowed_by_all, LLRoleActionSet* action_set, icon_map_t& icons, - void (*commit_callback)(LLUICtrl*,void*), + LLUICtrl::commit_callback_t commit_callback, BOOL show_all, BOOL filter, BOOL is_owner_role); void setFooterEnabled(BOOL enable); + + virtual void setGroupID(const LLUUID& id); protected: LLPanel* mHeader; LLPanel* mFooter; - LLLineEditor* mSearchLineEditor; - LLButton* mSearchButton; - LLButton* mShowAllButton; + LLSearchEditor* mSearchEditor; std::string mSearchFilter; @@ -164,13 +160,11 @@ protected: class LLPanelGroupMembersSubTab : public LLPanelGroupSubTab { public: - LLPanelGroupMembersSubTab(const std::string& name, const LLUUID& group_id); + LLPanelGroupMembersSubTab(); virtual ~LLPanelGroupMembersSubTab(); virtual BOOL postBuildSubTab(LLView* root); - static void* createTab(void* data); - static void onMemberSelect(LLUICtrl*, void*); void handleMemberSelect(); @@ -200,6 +194,8 @@ public: virtual void draw(); + virtual void setGroupID(const LLUUID& id); + protected: typedef std::map role_change_data_map_t; typedef std::map member_role_changes_map_t; @@ -229,13 +225,11 @@ protected: class LLPanelGroupRolesSubTab : public LLPanelGroupSubTab { public: - LLPanelGroupRolesSubTab(const std::string& name, const LLUUID& group_id); + LLPanelGroupRolesSubTab(); virtual ~LLPanelGroupRolesSubTab(); virtual BOOL postBuildSubTab(LLView* root); - static void* createTab(void* data); - virtual void activate(); virtual void deactivate(); virtual bool needsApply(std::string& mesg); @@ -249,7 +243,6 @@ public: void buildMembersList(); static void onActionCheck(LLUICtrl*, void*); - void handleActionCheck(LLCheckBoxCtrl*, bool force=false); bool addActionCB(const LLSD& notification, const LLSD& response, LLCheckBoxCtrl* check); static void onPropertiesKey(LLLineEditor*, void*); @@ -268,10 +261,8 @@ public: void saveRoleChanges(); protected: - LLSD createRoleItem(const LLUUID& role_id, - std::string name, - std::string title, - S32 members); + void handleActionCheck(LLUICtrl* ctrl, bool force); + LLSD createRoleItem(const LLUUID& role_id, std::string name, std::string title, S32 members); LLScrollListCtrl* mRolesList; LLNameListCtrl* mAssignedMembersList; @@ -293,12 +284,11 @@ protected: class LLPanelGroupActionsSubTab : public LLPanelGroupSubTab { public: - LLPanelGroupActionsSubTab(const std::string& name, const LLUUID& group_id); + LLPanelGroupActionsSubTab(); virtual ~LLPanelGroupActionsSubTab(); virtual BOOL postBuildSubTab(LLView* root); - static void* createTab(void* data); virtual void activate(); virtual void deactivate(); @@ -306,7 +296,6 @@ public: virtual bool apply(std::string& mesg); virtual void update(LLGroupChange gc); - static void onActionSelect(LLUICtrl*, void*); void handleActionSelect(); protected: LLScrollListCtrl* mActionList; diff --git a/indra/newview/llpanelimcontrolpanel.cpp b/indra/newview/llpanelimcontrolpanel.cpp new file mode 100644 index 0000000000..51cdc5af93 --- /dev/null +++ b/indra/newview/llpanelimcontrolpanel.cpp @@ -0,0 +1,113 @@ +/** + * @file llpanelavatar.cpp + * @brief LLPanelAvatar and related class implementations + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelimcontrolpanel.h" + +#include "llavataractions.h" +#include "llavatariconctrl.h" +#include "llbutton.h" +#include "llgroupactions.h" + +LLPanelIMControlPanel::LLPanelIMControlPanel() +{ +} + +LLPanelIMControlPanel::~LLPanelIMControlPanel() +{ +} + +BOOL LLPanelIMControlPanel::postBuild() +{ + childSetAction("view_profile_btn", boost::bind(&LLPanelIMControlPanel::onViewProfileButtonClicked, this)); + childSetAction("add_friend_btn", boost::bind(&LLPanelIMControlPanel::onAddFriendButtonClicked, this)); + childSetAction("call_btn", boost::bind(&LLPanelIMControlPanel::onCallButtonClicked, this)); + childSetAction("share_btn", boost::bind(&LLPanelIMControlPanel::onShareButtonClicked, this)); + childSetEnabled("add_friend_btn", !LLAvatarActions::isFriend(getChild("avatar_icon")->getAvatarId())); + + return TRUE; +} + +void LLPanelIMControlPanel::onViewProfileButtonClicked() +{ + LLAvatarActions::showProfile(getChild("avatar_icon")->getAvatarId()); +} + +void LLPanelIMControlPanel::onAddFriendButtonClicked() +{ + LLAvatarIconCtrl* avatar_icon = getChild("avatar_icon"); + std::string full_name = avatar_icon->getFirstName() + " " + avatar_icon->getLastName(); + LLAvatarActions::requestFriendshipDialog(avatar_icon->getAvatarId(), full_name); +} + +void LLPanelIMControlPanel::onCallButtonClicked() +{ + // *TODO: Implement +} + +void LLPanelIMControlPanel::onShareButtonClicked() +{ + // *TODO: Implement +} + +void LLPanelIMControlPanel::setID(const LLUUID& avatar_id) +{ + getChild("avatar_icon")->setValue(avatar_id); +} + + + +BOOL LLPanelGroupControlPanel::postBuild() +{ + childSetAction("group_info_btn", boost::bind(&LLPanelGroupControlPanel::onGroupInfoButtonClicked, this)); + childSetAction("call_btn", boost::bind(&LLPanelGroupControlPanel::onCallButtonClicked, this)); + + return TRUE; +} + +void LLPanelGroupControlPanel::onGroupInfoButtonClicked() +{ + LLGroupActions::show(mGroupID); +} + + +void LLPanelGroupControlPanel::onCallButtonClicked() +{ + // *TODO: Implement +} + + +void LLPanelGroupControlPanel::setID(const LLUUID& id) +{ + mGroupID = id; +} diff --git a/indra/newview/llpanelimcontrolpanel.h b/indra/newview/llpanelimcontrolpanel.h new file mode 100644 index 0000000000..e82942a31d --- /dev/null +++ b/indra/newview/llpanelimcontrolpanel.h @@ -0,0 +1,87 @@ +/** + * @file llpanelimcontrolpanel.h + * @brief LLPanelIMControlPanel and related class definitions + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELIMCONTROLPANEL_H +#define LL_LLPANELIMCONTROLPANEL_H + +#include "llpanel.h" + + +class LLPanelChatControlPanel : public LLPanel +{ +public: + LLPanelChatControlPanel() {}; + ~LLPanelChatControlPanel() {}; + + // sets the group or avatar UUID + virtual void setID(const LLUUID& avatar_id)= 0; +}; + + +class LLPanelIMControlPanel : public LLPanelChatControlPanel +{ +public: + LLPanelIMControlPanel(); + ~LLPanelIMControlPanel(); + + BOOL postBuild(); + + void setID(const LLUUID& avatar_id); + +private: + void onViewProfileButtonClicked(); + void onAddFriendButtonClicked(); + void onCallButtonClicked(); + void onShareButtonClicked(); +}; + + +class LLPanelGroupControlPanel : public LLPanelChatControlPanel +{ +public: + LLPanelGroupControlPanel() {}; + ~LLPanelGroupControlPanel() {}; + + BOOL postBuild(); + + void setID(const LLUUID& id); + +private: + void onGroupInfoButtonClicked(); + void onCallButtonClicked(); + + LLUUID mGroupID; +}; + + + +#endif // LL_LLPANELIMCONTROLPANEL_H diff --git a/indra/newview/llpanelland.cpp b/indra/newview/llpanelland.cpp index 8bb100d335..bce5525a40 100644 --- a/indra/newview/llpanelland.cpp +++ b/indra/newview/llpanelland.cpp @@ -40,6 +40,7 @@ #include "llbutton.h" #include "llcheckboxctrl.h" #include "llfloaterland.h" +#include "llfloaterreg.h" #include "lltextbox.h" #include "llviewercontrol.h" #include "llviewerparcelmgr.h" @@ -79,8 +80,8 @@ BOOL LLPanelLandInfo::postBuild() // // Methods // -LLPanelLandInfo::LLPanelLandInfo(const std::string& name) -: LLPanel(name), +LLPanelLandInfo::LLPanelLandInfo() +: LLPanel(), mCheckShowOwners(NULL) { if (!sInstance) @@ -262,7 +263,7 @@ void LLPanelLandInfo::onClickAbout(void*) LLViewerParcelMgr::getInstance()->selectParcelInRectangle(); } - LLFloaterLand::showInstance(); + LLFloaterReg::showInstance("about_land"); } void LLPanelLandInfo::onShowOwnersHelp(void* user_data) diff --git a/indra/newview/llpanelland.h b/indra/newview/llpanelland.h index 9a7e977711..92fe313405 100644 --- a/indra/newview/llpanelland.h +++ b/indra/newview/llpanelland.h @@ -46,7 +46,7 @@ class LLPanelLandInfo : public LLPanel { public: - LLPanelLandInfo(const std::string& name); + LLPanelLandInfo(); virtual ~LLPanelLandInfo(); void refresh(); diff --git a/indra/newview/llpanellandaudio.cpp b/indra/newview/llpanellandaudio.cpp new file mode 100644 index 0000000000..920fca66f2 --- /dev/null +++ b/indra/newview/llpanellandaudio.cpp @@ -0,0 +1,192 @@ +/** + * @file llpanellandaudio.cpp + * @brief Allows configuration of "media" for a land parcel, + * for example movies, web pages, and audio. + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanellandaudio.h" + +// viewer includes +#include "llmimetypes.h" +#include "llviewerparcelmgr.h" +#include "lluictrlfactory.h" + +// library includes +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfloaterurlentry.h" +#include "llfocusmgr.h" +#include "lllineeditor.h" +#include "llparcel.h" +#include "lltextbox.h" +#include "llradiogroup.h" +#include "llspinctrl.h" +#include "llsdutil.h" +#include "lltexturectrl.h" +#include "roles_constants.h" +#include "llscrolllistctrl.h" + +// Values for the parcel voice settings radio group +enum +{ + kRadioVoiceChatEstate = 0, + kRadioVoiceChatPrivate = 1, + kRadioVoiceChatDisable = 2 +}; + +//--------------------------------------------------------------------------- +// LLPanelLandAudio +//--------------------------------------------------------------------------- + +LLPanelLandAudio::LLPanelLandAudio(LLParcelSelectionHandle& parcel) +: LLPanel(/*std::string("land_media_panel")*/), mParcel(parcel) +{ +} + + +// virtual +LLPanelLandAudio::~LLPanelLandAudio() +{ +} + + +BOOL LLPanelLandAudio::postBuild() +{ + mCheckSoundLocal = getChild("check sound local"); + childSetCommitCallback("check sound local", onCommitAny, this); + + mRadioVoiceChat = getChild("parcel_voice_channel"); + childSetCommitCallback("parcel_voice_channel", onCommitAny, this); + + mMusicURLEdit = getChild("music_url"); + childSetCommitCallback("music_url", onCommitAny, this); + + mMusicUrlCheck = getChild("hide_music_url"); + childSetCommitCallback("hide_music_url", onCommitAny, this); + + return TRUE; +} + + +// public +void LLPanelLandAudio::refresh() +{ + LLParcel *parcel = mParcel->getParcel(); + + if (!parcel) + { + clearCtrls(); + } + else + { + // something selected, hooray! + + // Display options + BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA); + + mCheckSoundLocal->set( parcel->getSoundLocal() ); + mCheckSoundLocal->setEnabled( can_change_media ); + + mMusicUrlCheck->set( parcel->getObscureMusic() ); + mMusicUrlCheck->setEnabled( can_change_media ); + + if(parcel->getParcelFlagAllowVoice()) + { + if(parcel->getParcelFlagUseEstateVoiceChannel()) + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatEstate); + else + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatPrivate); + } + else + { + mRadioVoiceChat->setSelectedIndex(kRadioVoiceChatDisable); + } + + mRadioVoiceChat->setEnabled( can_change_media ); + + mMusicURLEdit->setText(parcel->getMusicURL()); + mMusicURLEdit->setEnabled( can_change_media ); + } +} +// static +void LLPanelLandAudio::onCommitAny(LLUICtrl*, void *userdata) +{ + LLPanelLandAudio *self = (LLPanelLandAudio *)userdata; + + LLParcel* parcel = self->mParcel->getParcel(); + if (!parcel) + { + return; + } + + // Extract data from UI + BOOL sound_local = self->mCheckSoundLocal->get(); + int voice_setting = self->mRadioVoiceChat->getSelectedIndex(); + std::string music_url = self->mMusicURLEdit->getText(); + U8 obscure_music = self->mMusicUrlCheck->get(); + + + BOOL voice_enabled; + BOOL voice_estate_chan; + + switch(voice_setting) + { + default: + case kRadioVoiceChatEstate: + voice_enabled = TRUE; + voice_estate_chan = TRUE; + break; + case kRadioVoiceChatPrivate: + voice_enabled = TRUE; + voice_estate_chan = FALSE; + break; + case kRadioVoiceChatDisable: + voice_enabled = FALSE; + voice_estate_chan = FALSE; + break; + } + + // Remove leading/trailing whitespace (common when copying/pasting) + LLStringUtil::trim(music_url); + + // Push data into current parcel + parcel->setParcelFlag(PF_ALLOW_VOICE_CHAT, voice_enabled); + parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan); + parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local); + parcel->setMusicURL(music_url); + parcel->setObscureMusic(obscure_music); + + // Send current parcel data upstream to server + LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); + + // Might have changed properties, so let's redraw! + self->refresh(); +} diff --git a/indra/newview/llpanellandaudio.h b/indra/newview/llpanellandaudio.h new file mode 100644 index 0000000000..de5da95fa4 --- /dev/null +++ b/indra/newview/llpanellandaudio.h @@ -0,0 +1,62 @@ +/** + * @file llpanellandaudio.h + * @brief Allows configuration of "audio" for a land parcel. + * + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2008, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLPANELLANDAUDIO_H +#define LLPANELLANDAUDIO_H + +#include "lllineeditor.h" +#include "llpanel.h" +#include "llparcelselection.h" +#include "lluifwd.h" // widget pointer types + +class LLPanelLandAudio + : public LLPanel +{ +public: + LLPanelLandAudio(LLSafeHandle& parcelp); + /*virtual*/ ~LLPanelLandAudio(); + /*virtual*/ BOOL postBuild(); + void refresh(); + +private: + static void onCommitAny(LLUICtrl* ctrl, void *userdata); + +private: + LLCheckBoxCtrl* mCheckSoundLocal; + LLRadioGroup* mRadioVoiceChat; + LLLineEditor* mMusicURLEdit; + LLCheckBoxCtrl* mMusicUrlCheck; + + LLSafeHandle& mParcel; +}; + +#endif diff --git a/indra/newview/llpanellandmarks.cpp b/indra/newview/llpanellandmarks.cpp new file mode 100644 index 0000000000..1d79ea4a21 --- /dev/null +++ b/indra/newview/llpanellandmarks.cpp @@ -0,0 +1,280 @@ +/** + * @file llpanellandmarks.cpp + * @brief Landmarks tab for Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanellandmarks.h" + +#include "llbutton.h" +#include "llfloaterreg.h" +#include "lllandmark.h" + +#include "llfloaterworldmap.h" +#include "llfloaterinventory.h" +#include "llfoldervieweventlistener.h" +#include "lllandmarklist.h" +#include "llsidetray.h" +#include "lltabcontainer.h" +#include "llworldmap.h" + +// Not yet implemented; need to remove buildPanel() from constructor when we switch +//static LLRegisterPanelClassWrapper t_landmarks("panel_landmarks"); + +LLLandmarksPanel::LLLandmarksPanel() + : LLPanelPlacesTab(), + mInventoryPanel(NULL) +{ + mSavedFolderState = new LLSaveFolderState(); + mSavedFolderState->setApply(FALSE); + + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_landmarks.xml"); +} + +LLLandmarksPanel::~LLLandmarksPanel() +{ + delete mSavedFolderState; +} + +BOOL LLLandmarksPanel::postBuild() +{ + if (!gInventory.isInventoryUsable()) + return FALSE; + + mInventoryPanel = getChild("landmarks_list"); + mInventoryPanel->setFilterTypes(0x1 << LLInventoryType::IT_LANDMARK); + mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_LANDMARK); + mInventoryPanel->setSelectCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2)); + + LLFolderView* root_folder = mInventoryPanel->getRootFolder(); + root_folder->setReshapeCallback(boost::bind(&LLLandmarksPanel::onSelectionChange, this, _1, _2)); + + mActionBtn = getChild("selector"); + root_folder->addChild(mActionBtn); + mActionBtn->setEnabled(TRUE); + childSetAction("selector", boost::bind(&LLLandmarksPanel::onSelectorButtonClicked, this), this); + + return TRUE; +} + +// virtual +void LLLandmarksPanel::onSearchEdit(const std::string& string) +{ + if (string == "") + { + mInventoryPanel->setFilterSubString(LLStringUtil::null); + + // re-open folders that were initially open + mSavedFolderState->setApply(TRUE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + LLOpenFoldersWithSelection opener; + mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); + mInventoryPanel->getRootFolder()->scrollToShowSelection(); + } + + gInventory.startBackgroundFetch(); + + if (mInventoryPanel->getFilterSubString().empty() && string.empty()) + { + // current filter and new filter empty, do nothing + return; + } + + // save current folder open state if no filter currently applied + if (mInventoryPanel->getRootFolder()->getFilterSubString().empty()) + { + mSavedFolderState->setApply(FALSE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(*mSavedFolderState); + } + + // set new filter string + mInventoryPanel->setFilterSubString(string); +} + +// virtual +void LLLandmarksPanel::onShowOnMap() +{ + LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (!current_item) + return; + + LLFolderViewEventListener* listenerp = current_item->getListener(); + if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK) + return; + + LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID()); + if (!inventory_item) + return; + + LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID()); + if (!landmark) + return; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return; + + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if (!landmark_global_pos.isExactlyZero() && worldmap_instance) + { + worldmap_instance->trackLocation(landmark_global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } +} + +// virtual +void LLLandmarksPanel::onTeleport() +{ + LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (!current_item) + return; + + LLFolderViewEventListener* listenerp = current_item->getListener(); + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + listenerp->openItem(); + } +} + +/* +// virtual +void LLLandmarksPanel::onCopySLURL() +{ + LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (!current_item) + return; + + LLFolderViewEventListener* listenerp = current_item->getListener(); + if (listenerp->getInventoryType() != LLInventoryType::IT_LANDMARK) + return; + + LLInventoryItem* inventory_item = gInventory.getItem(listenerp->getUUID()); + if (!inventory_item) + return; + + LLLandmark* landmark = gLandmarkList.getAsset(inventory_item->getAssetUUID()); + if (!landmark) + return; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return; + + U64 new_region_handle = to_region_handle(landmark_global_pos); + + LLWorldMap::url_callback_t cb = boost::bind( + &LLPanelPlacesTab::onRegionResponse, this, + landmark_global_pos, _1, _2, _3, _4); + + LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, cb, std::string("unused"), false); +} +*/ + +// virtual +void LLLandmarksPanel::updateVerbs() +{ + if (!isTabVisible()) + return; + + BOOL enabled = FALSE; + + LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (current_item) + { + LLFolderViewEventListener* listenerp = current_item->getListener(); + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + enabled = TRUE; + } + } + + mTeleportBtn->setEnabled(enabled); + mShowOnMapBtn->setEnabled(enabled); +} + +void LLLandmarksPanel::onSelectionChange(const std::deque &items, BOOL user_action) +{ + LLFolderViewItem* current_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + if (!current_item) + return; + + LLFolderViewEventListener* listenerp = current_item->getListener(); + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + S32 bottom = 0; + LLFolderViewItem* folder = current_item->getParentFolder(); + + while ( folder->getParentFolder() != NULL ) + { + bottom += folder->getRect().mBottom; + folder = folder->getParentFolder(); + } + + LLRect rect = current_item->getRect(); + LLRect btn_rect( + rect.mRight - mActionBtn->getRect().getWidth(), + bottom + rect.mTop, + rect.mRight, + bottom + rect.mBottom); + + mActionBtn->setRect(btn_rect); + + if (!mActionBtn->getVisible()) + mActionBtn->setVisible(TRUE); + } + else + { + if (mActionBtn->getVisible()) + mActionBtn->setVisible(FALSE); + } + + updateVerbs(); +} + +void LLLandmarksPanel::onSelectorButtonClicked() +{ + LLFolderViewItem* cur_item = mInventoryPanel->getRootFolder()->getCurSelectedItem(); + + LLFolderViewEventListener* listenerp = cur_item->getListener(); + if (listenerp->getInventoryType() == LLInventoryType::IT_LANDMARK) + { + LLSD key; + key["type"] = "landmark"; + key["id"] = listenerp->getUUID(); + + LLSideTray::getInstance()->showPanel("panel_places", key); + } +} + +void LLLandmarksPanel::setSelectedItem(const LLUUID& obj_id) +{ + mInventoryPanel->setSelection(obj_id, FALSE); +} diff --git a/indra/newview/llpanellandmarks.h b/indra/newview/llpanellandmarks.h new file mode 100644 index 0000000000..14cbbd6123 --- /dev/null +++ b/indra/newview/llpanellandmarks.h @@ -0,0 +1,66 @@ +/** + * @file llpanellandmarks.h + * @brief Landmarks tab for Side Bar "Places" panel + * class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELLANDMARKS_H +#define LL_LLPANELLANDMARKS_H + +#include "llinventorymodel.h" +#include "llpanelplacestab.h" + +class LLFolderViewItem; +class LLInventoryPanel; +class LLSaveFolderState; + +class LLLandmarksPanel : public LLPanelPlacesTab +{ +public: + LLLandmarksPanel(); + virtual ~LLLandmarksPanel(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onSearchEdit(const std::string& string); + /*virtual*/ void onShowOnMap(); + /*virtual*/ void onTeleport(); + ///*virtual*/ void onCopySLURL(); + /*virtual*/ void updateVerbs(); + + void onSelectionChange(const std::deque &items, BOOL user_action); + void onSelectorButtonClicked(); + void setSelectedItem(const LLUUID& obj_id); + +private: + LLInventoryPanel* mInventoryPanel; + LLSaveFolderState* mSavedFolderState; + LLButton* mActionBtn; +}; + +#endif //LL_LLPANELLANDMARKS_H diff --git a/indra/newview/llpanellandmedia.cpp b/indra/newview/llpanellandmedia.cpp index b8886c9493..994bf7e3f9 100644 --- a/indra/newview/llpanellandmedia.cpp +++ b/indra/newview/llpanellandmedia.cpp @@ -39,6 +39,8 @@ #include "llmimetypes.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" +#include "llviewermedia.h" +#include "llviewerparcelmedia.h" #include "lluictrlfactory.h" // library includes @@ -54,21 +56,15 @@ #include "llsdutil.h" #include "lltexturectrl.h" #include "roles_constants.h" +#include "llscrolllistctrl.h" //--------------------------------------------------------------------------- // LLPanelLandMedia //--------------------------------------------------------------------------- LLPanelLandMedia::LLPanelLandMedia(LLParcelSelectionHandle& parcel) -: LLPanel(std::string("land_media_panel")), - +: LLPanel(), mParcel(parcel), - mCheckSoundLocal(NULL), - mSoundHelpButton(NULL), - mCheckEnableVoiceChat(NULL), - mCheckEnableVoiceChatIsEstateDisabled(NULL), - mCheckEnableVoiceChatParcel(NULL), - mMusicURLEdit(NULL), mMediaURLEdit(NULL), mMediaDescEdit(NULL), mMediaTypeCombo(NULL), @@ -79,8 +75,7 @@ LLPanelLandMedia::LLPanelLandMedia(LLParcelSelectionHandle& parcel) mMediaTextureCtrl(NULL), mMediaAutoScaleCheck(NULL), mMediaLoopCheck(NULL), - mMediaUrlCheck(NULL), - mMusicUrlCheck(NULL) + mMediaUrlCheck(NULL) { } @@ -88,38 +83,13 @@ LLPanelLandMedia::LLPanelLandMedia(LLParcelSelectionHandle& parcel) // virtual LLPanelLandMedia::~LLPanelLandMedia() { - // close LLFloaterURLEntry? } - -// static -void LLPanelLandMedia::onClickSoundHelp(void*) -{ - LLNotifications::instance().add("ClickSoundHelpLand"); -} - - BOOL LLPanelLandMedia::postBuild() { - mCheckSoundLocal = getChild("check sound local"); - childSetCommitCallback("check sound local", onCommitAny, this); - - mSoundHelpButton = getChild("?"); - mSoundHelpButton->setClickedCallback(onClickSoundHelp, this); - - mCheckEnableVoiceChat = getChild("parcel_enable_voice_channel"); - childSetCommitCallback("parcel_enable_voice_channel", onCommitAny, this); - mCheckEnableVoiceChatIsEstateDisabled = getChild("parcel_enable_voice_channel_is_estate_disabled"); - childSetCommitCallback("parcel_enable_voice_channel_is_estate_disabled", onCommitAny, this); - mCheckEnableVoiceChatParcel = getChild("parcel_enable_voice_channel_parcel"); - childSetCommitCallback("parcel_enable_voice_channel_parcel", onCommitAny, this); - - mMusicURLEdit = getChild("music_url"); - childSetCommitCallback("music_url", onCommitAny, this); mMediaTextureCtrl = getChild("media texture"); - mMediaTextureCtrl->setCommitCallback( onCommitAny ); - mMediaTextureCtrl->setCallbackUserData( this ); + mMediaTextureCtrl->setCommitCallback( onCommitAny, this ); mMediaTextureCtrl->setAllowNoTexture ( TRUE ); mMediaTextureCtrl->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); mMediaTextureCtrl->setNonImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); @@ -128,16 +98,13 @@ BOOL LLPanelLandMedia::postBuild() childSetCommitCallback("media_auto_scale", onCommitAny, this); mMediaLoopCheck = getChild("media_loop"); - childSetCommitCallback("media_loop", onCommitAny, this); + childSetCommitCallback("media_loop", onCommitAny, this ); mMediaUrlCheck = getChild("hide_media_url"); - childSetCommitCallback("hide_media_url", onCommitAny, this); - - mMusicUrlCheck = getChild("hide_music_url"); - childSetCommitCallback("hide_music_url", onCommitAny, this); + childSetCommitCallback("hide_media_url", onCommitAny, this ); mMediaURLEdit = getChild("media_url"); - childSetCommitCallback("media_url", onCommitAny, this); + childSetCommitCallback("media_url", onCommitAny, this ); mMediaDescEdit = getChild("url_description"); childSetCommitCallback("url_description", onCommitAny, this); @@ -155,6 +122,9 @@ BOOL LLPanelLandMedia::postBuild() mSetURLButton = getChild("set_media_url"); childSetAction("set_media_url", onSetBtn, this); + mResetURLButton = getChild("reset_media_url"); + childSetAction("reset_media_url", onResetBtn, this); + return TRUE; } @@ -175,46 +145,11 @@ void LLPanelLandMedia::refresh() // Display options BOOL can_change_media = LLViewerParcelMgr::isParcelModifiableByAgent(parcel, GP_LAND_CHANGE_MEDIA); - mCheckSoundLocal->set( parcel->getSoundLocal() ); - mCheckSoundLocal->setEnabled( can_change_media ); - - LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); - if (!region) - { - // never seen this happen, but log it - llwarns << "Couldn't get selected region." << llendl; - } - - if (region && region->isVoiceEnabled()) // estate-wide voice-disable overrides all - { - bool allow_voice = parcel->getParcelFlagAllowVoice(); - - mCheckEnableVoiceChatIsEstateDisabled->setVisible(false); - - mCheckEnableVoiceChat->setVisible(true); - mCheckEnableVoiceChat->setEnabled( can_change_media ); - mCheckEnableVoiceChat->set(allow_voice); - - mCheckEnableVoiceChatParcel->setEnabled( can_change_media && allow_voice ); - } - else // disabled at region level - { - mCheckEnableVoiceChatIsEstateDisabled->setVisible(true); // always disabled - mCheckEnableVoiceChat->setVisible(false); - mCheckEnableVoiceChat->setEnabled(false); - mCheckEnableVoiceChat->set(false); - - mCheckEnableVoiceChatParcel->setEnabled(false); - } - - mCheckEnableVoiceChatParcel->set(!parcel->getParcelFlagUseEstateVoiceChannel()); - - mMusicURLEdit->setText(parcel->getMusicURL()); - mMusicURLEdit->setEnabled( can_change_media ); - mMediaURLEdit->setText(parcel->getMediaURL()); mMediaURLEdit->setEnabled( FALSE ); + childSetText("current_url", parcel->getMediaCurrentURL()); + mMediaDescEdit->setText(parcel->getMediaDesc()); mMediaDescEdit->setEnabled( can_change_media ); @@ -230,15 +165,11 @@ void LLPanelLandMedia::refresh() mMediaUrlCheck->set( parcel->getObscureMedia() ); mMediaUrlCheck->setEnabled( can_change_media ); - mMusicUrlCheck->set( parcel->getObscureMusic() ); - mMusicUrlCheck->setEnabled( can_change_media ); - // don't display urls if you're not able to change it // much requested change in forums so people can't 'steal' urls // NOTE: bug#2009 means this is still vunerable - however, bug // should be closed since this bug opens up major security issues elsewhere. bool obscure_media = ! can_change_media && parcel->getObscureMedia(); - bool obscure_music = ! can_change_media && parcel->getObscureMusic(); // Special code to disable asterixes for html type if(mime_type == "text/html") @@ -248,7 +179,6 @@ void LLPanelLandMedia::refresh() mMediaUrlCheck->setEnabled( false ); } - mMusicURLEdit->setDrawAsterixes( obscure_music ); mMediaURLEdit->setDrawAsterixes( obscure_media ); mMediaAutoScaleCheck->set( parcel->getMediaAutoScale () ); @@ -262,7 +192,7 @@ void LLPanelLandMedia::refresh() else mMediaLoopCheck->set( false ); mMediaLoopCheck->setEnabled ( can_change_media && allow_looping ); - + // disallow media size change for mime types that don't allow it bool allow_resize = LLMIMETypes::findAllowResize( mime_type ); if ( allow_resize ) @@ -285,22 +215,7 @@ void LLPanelLandMedia::refresh() mMediaTextureCtrl->setEnabled( can_change_media ); mSetURLButton->setEnabled( can_change_media ); - - #if 0 - // there is a media url and a media texture selected - if ( ( ! ( std::string ( parcel->getMediaURL() ).empty () ) ) && ( ! ( parcel->getMediaID ().isNull () ) ) ) - { - // turn on transport controls if allowed for this parcel - mMediaStopButton->setEnabled ( editable ); - mMediaStartButton->setEnabled ( editable ); - } - else - { - // no media url or no media texture - mMediaStopButton->setEnabled ( FALSE ); - mMediaStartButton->setEnabled ( FALSE ); - }; - #endif + mResetURLButton->setEnabled( can_change_media ); LLFloaterURLEntry* floater_url_entry = (LLFloaterURLEntry*)mURLEntryFloater.get(); if (floater_url_entry) @@ -348,12 +263,19 @@ void LLPanelLandMedia::setMediaType(const std::string& mime_type) void LLPanelLandMedia::setMediaURL(const std::string& media_url) { mMediaURLEdit->setText(media_url); - mMediaURLEdit->onCommit(); -} + LLParcel *parcel = mParcel->getParcel(); + if(parcel) + parcel->setMediaCurrentURL(media_url); + // LLViewerMedia::navigateHome(); + + mMediaURLEdit->onCommit(); + // LLViewerParcelMedia::sendMediaNavigateMessage(media_url); + childSetText("current_url", media_url); +} std::string LLPanelLandMedia::getMediaURL() { - return mMediaURLEdit->getText(); + return mMediaURLEdit->getText(); } // static @@ -382,33 +304,23 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) } // Extract data from UI - BOOL sound_local = self->mCheckSoundLocal->get(); - std::string music_url = self->mMusicURLEdit->getText(); std::string media_url = self->mMediaURLEdit->getText(); std::string media_desc = self->mMediaDescEdit->getText(); std::string mime_type = self->childGetText("mime_type"); U8 media_auto_scale = self->mMediaAutoScaleCheck->get(); U8 media_loop = self->mMediaLoopCheck->get(); U8 obscure_media = self->mMediaUrlCheck->get(); - U8 obscure_music = self->mMusicUrlCheck->get(); S32 media_width = (S32)self->mMediaWidthCtrl->get(); S32 media_height = (S32)self->mMediaHeightCtrl->get(); LLUUID media_id = self->mMediaTextureCtrl->getImageAssetID(); - BOOL voice_enabled = self->mCheckEnableVoiceChat->get(); - BOOL voice_estate_chan = ! self->mCheckEnableVoiceChatParcel->get(); self->childSetText("mime_type", mime_type); // Remove leading/trailing whitespace (common when copying/pasting) - LLStringUtil::trim(music_url); LLStringUtil::trim(media_url); // Push data into current parcel - parcel->setParcelFlag(PF_ALLOW_VOICE_CHAT, voice_enabled); - parcel->setParcelFlag(PF_USE_ESTATE_VOICE_CHAN, voice_estate_chan); - parcel->setParcelFlag(PF_SOUND_LOCAL, sound_local); - parcel->setMusicURL(music_url); parcel->setMediaURL(media_url); parcel->setMediaType(mime_type); parcel->setMediaDesc(media_desc); @@ -418,7 +330,6 @@ void LLPanelLandMedia::onCommitAny(LLUICtrl*, void *userdata) parcel->setMediaAutoScale ( media_auto_scale ); parcel->setMediaLoop ( media_loop ); parcel->setObscureMedia( obscure_media ); - parcel->setObscureMusic( obscure_music ); // Send current parcel data upstream to server LLViewerParcelMgr::getInstance()->sendParcelPropertiesUpdate( parcel ); @@ -437,3 +348,16 @@ void LLPanelLandMedia::onSetBtn(void *userdata) parent_floater->addDependentFloater(self->mURLEntryFloater.get()); } } + +// static +void LLPanelLandMedia::onResetBtn(void *userdata) +{ + LLPanelLandMedia *self = (LLPanelLandMedia *)userdata; + LLParcel* parcel = self->mParcel->getParcel(); + // LLViewerMedia::navigateHome(); + self->refresh(); + self->childSetText("current_url", parcel->getMediaURL()); + // LLViewerParcelMedia::sendMediaNavigateMessage(parcel->getMediaURL()); + +} + diff --git a/indra/newview/llpanellandmedia.h b/indra/newview/llpanellandmedia.h index 6a53dd42a5..5ad1f9758d 100644 --- a/indra/newview/llpanellandmedia.h +++ b/indra/newview/llpanellandmedia.h @@ -56,29 +56,34 @@ private: static void onCommitAny(LLUICtrl* ctrl, void *userdata); static void onCommitType(LLUICtrl* ctrl, void *userdata); static void onSetBtn(void* userdata); - static void onClickSoundHelp(void*); - + static void onResetBtn(void* userdata); + private: - LLCheckBoxCtrl* mCheckSoundLocal; - LLButton* mSoundHelpButton; - LLCheckBoxCtrl* mCheckEnableVoiceChat; - LLCheckBoxCtrl* mCheckEnableVoiceChatIsEstateDisabled; - LLCheckBoxCtrl* mCheckEnableVoiceChatParcel; - LLLineEditor* mMusicURLEdit; LLLineEditor* mMediaURLEdit; LLLineEditor* mMediaDescEdit; LLComboBox* mMediaTypeCombo; LLButton* mSetURLButton; + LLButton* mResetURLButton; + LLSpinCtrl* mMediaResetCtrl; LLSpinCtrl* mMediaHeightCtrl; LLSpinCtrl* mMediaWidthCtrl; + LLTextBox* mMediaResetCtrlLabel; LLTextBox* mMediaSizeCtrlLabel; LLTextureCtrl* mMediaTextureCtrl; LLCheckBoxCtrl* mMediaAutoScaleCheck; LLCheckBoxCtrl* mMediaLoopCheck; LLCheckBoxCtrl* mMediaUrlCheck; - LLCheckBoxCtrl* mMusicUrlCheck; LLHandle mURLEntryFloater; + LLCheckBoxCtrl* mMediaNavigateAllowCheck; + LLCheckBoxCtrl* mMediaURLFilterCheck; + LLLineEditor* mMediaURLFilterDomainEdit; + LLButton* mMediaURLFilterAddButton; + LLButton* mMediaURLFilterRemoveButton; + LLScrollListCtrl* mURLFilterList; + LLRadioGroup* mRadioNavigateControl; + + LLSafeHandle& mParcel; }; diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp index bc5e8f2482..ef830d5f03 100644 --- a/indra/newview/llpanellogin.cpp +++ b/indra/newview/llpanellogin.cpp @@ -34,9 +34,8 @@ #include "llpanellogin.h" -#include "llpanelgeneral.h" - #include "indra_constants.h" // for key and mask constants +#include "llfloaterreg.h" #include "llfontgl.h" #include "llmd5.h" #include "llsecondlifeurls.h" @@ -49,8 +48,6 @@ #include "llcombobox.h" #include "llcurl.h" #include "llviewercontrol.h" -#include "llfloaterabout.h" -#include "llfloatertest.h" #include "llfloaterpreference.h" #include "llfocusmgr.h" #include "lllineeditor.h" @@ -60,7 +57,7 @@ #include "lluiconstants.h" #include "llurlsimstring.h" #include "llviewerbuild.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewermenu.h" // for handle_preferences() #include "llviewernetwork.h" #include "llviewerwindow.h" // to link into child list @@ -69,13 +66,12 @@ #include "lluictrlfactory.h" #include "llhttpclient.h" #include "llweb.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" +#include "llrootview.h" -#include "llfloaterhtml.h" - -#include "llfloaterhtmlhelp.h" +#include "llfloatermediabrowser.h" #include "llfloatertos.h" - +#include "lltrans.h" #include "llglheaders.h" #define USE_VIEWER_AUTH 0 @@ -92,7 +88,7 @@ class LLLoginRefreshHandler : public LLCommandHandler public: // don't allow from external browsers LLLoginRefreshHandler() : LLCommandHandler("login_refresh", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP) { @@ -166,7 +162,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, BOOL show_server, void (*callback)(S32 option, void* user_data), void *cb_data) -: LLPanel(std::string("panel_login"), LLRect(0,600,800,0), FALSE), // not bordered +: LLPanel(), mLogoImage(), mCallback(callback), mCallbackData(cb_data), @@ -190,7 +186,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLPanelLogin::sInstance = this; // add to front so we are the bottom-most child - gViewerWindow->getRootView()->addChildAtEnd(this); + gViewerWindow->getRootView()->addChildInBack(this); // Logo mLogoImage = LLUI::getUIImage("startup_logo.j2c"); @@ -207,9 +203,8 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, childSetPrevalidate("first_name_edit", LLLineEditor::prevalidatePrintableNoSpace); childSetPrevalidate("last_name_edit", LLLineEditor::prevalidatePrintableNoSpace); - childSetCommitCallback("password_edit", mungePassword); - childSetKeystrokeCallback("password_edit", onPassKey, this); - childSetUserData("password_edit", this); + childSetCommitCallback("password_edit", mungePassword, this); + getChild("password_edit")->setKeystrokeCallback(onPassKey, this); // change z sort of clickable text to be behind buttons sendChildToBack(getChildView("channel_text")); @@ -219,14 +214,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, if (edit) edit->setDrawAsterixes(TRUE); LLComboBox* combo = getChild("start_location_combo"); - combo->setAllowTextEntry(TRUE, 128, FALSE); - // The XML file loads the combo with the following labels: - // 0 - "My Home" - // 1 - "My Last Location" - // 2 - "" - - BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation"); std::string sim_string = LLURLSimString::sInstance.mSimString; if (!sim_string.empty()) { @@ -236,19 +224,11 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, combo->setTextEntry(sim_string); combo->setCurrentByIndex( 2 ); } - else if (login_last) - { - combo->setCurrentByIndex( 1 ); - } - else - { - combo->setCurrentByIndex( 0 ); - } - combo->setCommitCallback( &set_start_location ); + combo->setCommitCallback( &set_start_location, NULL ); LLComboBox* server_choice_combo = sInstance->getChild("server_combo"); - server_choice_combo->setCommitCallback(onSelectServer); + server_choice_combo->setCommitCallback(onSelectServer, NULL); server_choice_combo->setFocusLostCallback(onServerComboLostFocus); childSetAction("connect_btn", onClickConnect, this); @@ -266,27 +246,25 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, LLTextBox* channel_text = getChild("channel_text"); channel_text->setTextArg("[CHANNEL]", channel); // though not displayed channel_text->setTextArg("[VERSION]", version); - channel_text->setClickedCallback(onClickVersion); - channel_text->setCallbackUserData(this); + channel_text->setClickedCallback(onClickVersion, this); LLTextBox* forgot_password_text = getChild("forgot_password_text"); - forgot_password_text->setClickedCallback(onClickForgotPassword); + forgot_password_text->setClickedCallback(onClickForgotPassword, NULL); LLTextBox* create_new_account_text = getChild("create_new_account_text"); - create_new_account_text->setClickedCallback(onClickNewAccount); + create_new_account_text->setClickedCallback(onClickNewAccount, NULL); #endif // get the web browser control - LLWebBrowserCtrl* web_browser = getChild("login_html"); + LLMediaCtrl* web_browser = getChild("login_html"); + web_browser->addObserver(this); + // Need to handle login secondlife:///app/ URLs web_browser->setTrusted( true ); - // observe browser events - web_browser->addObserver( this ); - // don't make it a tab stop until SL-27594 is fixed web_browser->setTabStop(FALSE); - web_browser->navigateToLocalPage( "loading", "loading.html" ); + // web_browser->navigateToLocalPage( "loading", "loading.html" ); // make links open in external browser web_browser->setOpenInExternalBrowser( true ); @@ -320,7 +298,7 @@ LLPanelLogin::LLPanelLogin(const LLRect &rect, void LLPanelLogin::setSiteIsAlive( bool alive ) { - LLWebBrowserCtrl* web_browser = getChild("login_html"); + LLMediaCtrl* web_browser = getChild("login_html"); // if the contents of the site was retrieved if ( alive ) { @@ -382,7 +360,7 @@ LLPanelLogin::~LLPanelLogin() gResponsePtr->setParent( 0 ); //// We know we're done with the image, so be rid of it. - //gImageList.deleteImage( mLogoImage ); + //gTextureList.deleteImage( mLogoImage ); } // virtual @@ -432,18 +410,6 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) return TRUE; } - if (('P' == key) && (MASK_CONTROL == mask)) - { - LLFloaterPreference::show(NULL); - return TRUE; - } - - if (('T' == key) && (MASK_CONTROL == mask)) - { - new LLFloaterSimple("floater_test.xml"); - return TRUE; - } - if ( KEY_F1 == key ) { llinfos << "Spawning HTML help window" << llendl; @@ -451,16 +417,6 @@ BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask) return TRUE; } -# if !LL_RELEASE_FOR_DOWNLOAD - if ( KEY_F2 == key ) - { - llinfos << "Spawning floater TOS window" << llendl; - LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS,""); - tos_dialog->startModal(); - return TRUE; - } -#endif - if (KEY_RETURN == key && MASK_NONE == mask) { // let the panel handle UICtrl processing: calls onClickConnect() @@ -656,23 +612,15 @@ void LLPanelLogin::refreshLocation( bool force_visible ) #if USE_VIEWER_AUTH loadLoginPage(); #else - LLComboBox* combo = sInstance->getChild("start_location_combo"); - - if (LLURLSimString::parse()) - { - combo->setCurrentByIndex( 3 ); // BUG? Maybe 2? - combo->setTextEntry(LLURLSimString::sInstance.mSimString); - } - else - { - BOOL login_last = gSavedSettings.getBOOL("LoginLastLocation"); - combo->setCurrentByIndex( login_last ? 1 : 0 ); - } - BOOL show_start = TRUE; if ( ! force_visible ) - show_start = gSavedSettings.getBOOL("ShowStartLocation"); + { + // Don't show on first run after install + // Otherwise ShowStartLocation defaults to true. + show_start = gSavedSettings.getBOOL("ShowStartLocation") + && !gSavedSettings.getBOOL("FirstRunThisInstall"); + } sInstance->childSetVisible("start_location_combo", show_start); sInstance->childSetVisible("start_location_text", show_start); @@ -688,7 +636,7 @@ void LLPanelLogin::refreshLocation( bool force_visible ) } // static -void LLPanelLogin::close() +void LLPanelLogin::closePanel() { if (sInstance) { @@ -706,7 +654,7 @@ void LLPanelLogin::setAlwaysRefresh(bool refresh) { if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return; - LLWebBrowserCtrl* web_browser = sInstance->getChild("login_html"); + LLMediaCtrl* web_browser = sInstance->getChild("login_html"); if (web_browser) { @@ -787,14 +735,7 @@ void LLPanelLogin::loadLoginPage() } else { - if (gSavedSettings.getBOOL("LoginLastLocation")) - { - location = "last"; - } - else - { - location = "home"; - } + location = gSavedSettings.getString("LoginLocation"); } std::string firstname, lastname; @@ -836,7 +777,8 @@ void LLPanelLogin::loadLoginPage() { oStr << "&auto_login=TRUE"; } - if (gSavedSettings.getBOOL("ShowStartLocation")) + if (gSavedSettings.getBOOL("ShowStartLocation") + && !gSavedSettings.getBOOL("FirstRunThisInstall")) { oStr << "&show_start_location=TRUE"; } @@ -852,25 +794,28 @@ void LLPanelLogin::loadLoginPage() #endif #endif - LLWebBrowserCtrl* web_browser = sInstance->getChild("login_html"); + LLMediaCtrl* web_browser = sInstance->getChild("login_html"); // navigate to the "real" page - web_browser->navigateTo( oStr.str() ); + web_browser->navigateTo( oStr.str(), "text/html" ); } -void LLPanelLogin::onNavigateComplete( const EventType& eventIn ) +void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event) { - LLWebBrowserCtrl* web_browser = sInstance->getChild("login_html"); - if (web_browser) + if(event == MEDIA_EVENT_NAVIGATE_COMPLETE) { - // *HACK HACK HACK HACK! - /* Stuff a Tab key into the browser now so that the first field will - ** get the focus! The embedded javascript on the page that properly - ** sets the initial focus in a real web browser is not working inside - ** the viewer, so this is an UGLY HACK WORKAROUND for now. - */ - // Commented out as it's not reliable - //web_browser->handleKey(KEY_TAB, MASK_NONE, false); + LLMediaCtrl* web_browser = sInstance->getChild("login_html"); + if (web_browser) + { + // *HACK HACK HACK HACK! + /* Stuff a Tab key into the browser now so that the first field will + ** get the focus! The embedded javascript on the page that properly + ** sets the initial focus in a real web browser is not working inside + ** the viewer, so this is an UGLY HACK WORKAROUND for now. + */ + // Commented out as it's not reliable + //web_browser->handleKey(KEY_TAB, MASK_NONE, false); + } } } @@ -899,13 +844,12 @@ void LLPanelLogin::onClickConnect(void *) } else { - LLNotifications::instance().add("MustHaveAccountToLogIn", LLSD(), LLSD(), - LLPanelLogin::newAccountAlertCallback); + LLNotifications::instance().add("MustHaveAccountToLogIn"); } } } - +/* // static bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response) { @@ -913,7 +857,7 @@ bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& if (0 == option) { llinfos << "Going to account creation URL" << llendl; - LLWeb::loadURLExternal( CREATE_ACCOUNT_URL ); + LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL")); } else { @@ -921,12 +865,12 @@ bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& } return false; } - +*/ // static void LLPanelLogin::onClickNewAccount(void*) { - LLWeb::loadURLExternal( CREATE_ACCOUNT_URL ); + LLWeb::loadURLExternal(sInstance->getString("create_account_url")); } @@ -949,7 +893,7 @@ void LLPanelLogin::onClickQuit(void*) // static void LLPanelLogin::onClickVersion(void*) { - LLFloaterAbout::show(NULL); + LLFloaterReg::showInstance("sl_about"); } //static @@ -1023,6 +967,8 @@ void LLPanelLogin::onSelectServer(LLUICtrl*, void*) void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*) { + if (!sInstance) return; + LLComboBox* combo = sInstance->getChild("server_combo"); if(fe == combo) { diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h index 47d42da7f1..ffcf6a9b70 100644 --- a/indra/newview/llpanellogin.h +++ b/indra/newview/llpanellogin.h @@ -34,15 +34,16 @@ #define LL_LLPANELLOGIN_H #include "llpanel.h" -#include "llmemory.h" // LLPointer<> -#include "llwebbrowserctrl.h" // LLWebBrowserCtrlObserver +#include "llpointer.h" // LLPointer<> +#include "llmediactrl.h" // LLMediaCtrlObserver +class LLLineEditor; class LLUIImage; class LLPanelLogin: public LLPanel, - public LLWebBrowserCtrlObserver + public LLViewerMediaObserver { LOG_CLASS(LLPanelLogin); public: @@ -72,7 +73,7 @@ public: static BOOL isGridComboDirty(); static void getLocation(std::string &location); - static void close(); + static void closePanel(); void setSiteIsAlive( bool alive ); @@ -81,13 +82,15 @@ public: static void setAlwaysRefresh(bool refresh); static void mungePassword(LLUICtrl* caller, void* user_data); + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + private: static void onClickConnect(void*); static void onClickNewAccount(void*); - static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); +// static bool newAccountAlertCallback(const LLSD& notification, const LLSD& response); static void onClickQuit(void*); static void onClickVersion(void*); - virtual void onNavigateComplete( const EventType& eventIn ); static void onClickForgotPassword(void*); static void onPassKey(LLLineEditor* caller, void* user_data); static void onSelectServer(LLUICtrl*, void*); diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp index 75f479c16f..9ec9874384 100644 --- a/indra/newview/llpanelobject.cpp +++ b/indra/newview/llpanelobject.cpp @@ -52,7 +52,6 @@ #include "llcombobox.h" #include "llfocusmgr.h" #include "llmanipscale.h" -#include "llpanelinventory.h" #include "llpreviewscript.h" #include "llresmgr.h" #include "llselectmgr.h" @@ -62,6 +61,7 @@ #include "lltool.h" #include "lltoolcomp.h" #include "lltoolmgr.h" +#include "lltrans.h" #include "llui.h" #include "llviewerobject.h" #include "llviewerregion.h" @@ -99,13 +99,23 @@ enum { MI_HOLE_COUNT }; -//*TODO:translate (depricated, so very low priority) -static const std::string LEGACY_FULLBRIGHT_DESC("Fullbright (Legacy)"); +//static const std::string LEGACY_FULLBRIGHT_DESC =LLTrans::getString("Fullbright"); BOOL LLPanelObject::postBuild() { setMouseOpaque(FALSE); - + + std::map material_name_map; + material_name_map["Stone"]= LLTrans::getString("Stone"); + material_name_map["Metal"]= LLTrans::getString("Metal"); + material_name_map["Glass"]= LLTrans::getString("Glass"); + material_name_map["Wood"]= LLTrans::getString("Wood"); + material_name_map["Flesh"]= LLTrans::getString("Flesh"); + material_name_map["Plastic"]= LLTrans::getString("Plastic"); + material_name_map["Rubber"]= LLTrans::getString("Rubber"); + material_name_map["Light"]= LLTrans::getString("Light"); + + LLMaterialTable::basic.initTableTransNames(material_name_map); //-------------------------------------------------------- // Top //-------------------------------------------------------- @@ -164,14 +174,14 @@ BOOL LLPanelObject::postBuild() mComboMaterial = getChild("material"); childSetCommitCallback("material",onCommitMaterial,this); mComboMaterial->removeall(); - // *TODO:translate + for (LLMaterialTable::info_list_t::iterator iter = LLMaterialTable::basic.mMaterialInfoList.begin(); iter != LLMaterialTable::basic.mMaterialInfoList.end(); ++iter) { LLMaterialInfo* minfop = *iter; if (minfop->mMCode != LL_MCODE_LIGHT) { - mComboMaterial->add(minfop->mName); + mComboMaterial->add(minfop->mName); } } mComboMaterialItemCount = mComboMaterial->getItemCount(); @@ -263,11 +273,10 @@ BOOL LLPanelObject::postBuild() if (mCtrlSculptTexture) { mCtrlSculptTexture->setDefaultImageAssetID(LLUUID(SCULPT_DEFAULT_TEXTURE)); - mCtrlSculptTexture->setCommitCallback( LLPanelObject::onCommitSculpt ); - mCtrlSculptTexture->setOnCancelCallback( LLPanelObject::onCancelSculpt ); - mCtrlSculptTexture->setOnSelectCallback( LLPanelObject::onSelectSculpt ); - mCtrlSculptTexture->setDropCallback(LLPanelObject::onDropSculpt); - mCtrlSculptTexture->setCallbackUserData( this ); + mCtrlSculptTexture->setCommitCallback( boost::bind(&LLPanelObject::onCommitSculpt, this, _2 )); + mCtrlSculptTexture->setOnCancelCallback( boost::bind(&LLPanelObject::onCancelSculpt, this, _2 )); + mCtrlSculptTexture->setOnSelectCallback( boost::bind(&LLPanelObject::onSelectSculpt, this, _2 )); + mCtrlSculptTexture->setDropCallback( boost::bind(&LLPanelObject::onDropSculpt, this, _2 )); // Don't allow (no copy) or (no transfer) textures to be selected during immediate mode mCtrlSculptTexture->setImmediateFilterPermMask(PERM_COPY | PERM_TRANSFER); // Allow any texture to be used during non-immediate mode. @@ -303,8 +312,8 @@ BOOL LLPanelObject::postBuild() return TRUE; } -LLPanelObject::LLPanelObject(const std::string& name) -: LLPanel(name), +LLPanelObject::LLPanelObject() +: LLPanel(), mIsPhysical(FALSE), mIsTemporary(FALSE), mIsPhantom(FALSE), @@ -530,7 +539,7 @@ void LLPanelObject::getState( ) } } func; bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); - + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); if (editable && single_volume && material_same) { mComboMaterial->setEnabled( TRUE ); @@ -549,7 +558,7 @@ void LLPanelObject::getState( ) { mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); } - // *TODO:Translate + mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); } } @@ -1163,7 +1172,7 @@ void LLPanelObject::getState( ) } // static -BOOL LLPanelObject::precommitValidate( LLUICtrl* ctrl, void* userdata ) +bool LLPanelObject::precommitValidate( const LLSD& data ) { // TODO: Richard will fill this in later. return TRUE; // FALSE means that validation failed and new value should not be commited. @@ -1244,6 +1253,7 @@ void LLPanelObject::onCommitMaterial( LLUICtrl* ctrl, void* userdata ) { // apply the currently selected material to the object const std::string& material_name = box->getSimple(); + std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); if (material_name != LEGACY_FULLBRIGHT_DESC) { U8 material_code = LLMaterialTable::basic.getMCode(material_name); @@ -1992,60 +2002,49 @@ void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata ) } -// static -void LLPanelObject::onSelectSculpt(LLUICtrl* ctrl, void* userdata) +void LLPanelObject::onSelectSculpt(const LLSD& data) { - LLPanelObject* self = (LLPanelObject*) userdata; - - LLTextureCtrl* mTextureCtrl = self->getChild("sculpt texture control"); + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); if (mTextureCtrl) { - self->mSculptTextureRevert = mTextureCtrl->getImageAssetID(); + mSculptTextureRevert = mTextureCtrl->getImageAssetID(); } - self->sendSculpt(); + sendSculpt(); } -void LLPanelObject::onCommitSculpt( LLUICtrl* ctrl, void* userdata ) +void LLPanelObject::onCommitSculpt( const LLSD& data ) { - LLPanelObject* self = (LLPanelObject*) userdata; - - self->sendSculpt(); + sendSculpt(); } -// static -BOOL LLPanelObject::onDropSculpt(LLUICtrl*, LLInventoryItem* item, void* userdata) +BOOL LLPanelObject::onDropSculpt(LLInventoryItem* item) { - LLPanelObject* self = (LLPanelObject*) userdata; - - LLTextureCtrl* mTextureCtrl = self->getChild("sculpt texture control"); + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); if (mTextureCtrl) { LLUUID asset = item->getAssetUUID(); mTextureCtrl->setImageAssetID(asset); - self->mSculptTextureRevert = asset; + mSculptTextureRevert = asset; } return TRUE; } -// static -void LLPanelObject::onCancelSculpt(LLUICtrl* ctrl, void* userdata) +void LLPanelObject::onCancelSculpt(const LLSD& data) { - LLPanelObject* self = (LLPanelObject*) userdata; - - LLTextureCtrl* mTextureCtrl = self->getChild("sculpt texture control"); + LLTextureCtrl* mTextureCtrl = getChild("sculpt texture control"); if(!mTextureCtrl) return; - mTextureCtrl->setImageAssetID(self->mSculptTextureRevert); + mTextureCtrl->setImageAssetID(mSculptTextureRevert); - self->sendSculpt(); + sendSculpt(); } // static diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h index 9ed091ed5f..1ab4ff581e 100644 --- a/indra/newview/llpanelobject.h +++ b/indra/newview/llpanelobject.h @@ -35,7 +35,7 @@ #include "v3math.h" #include "llpanel.h" -#include "llmemory.h" +#include "llpointer.h" #include "llvolume.h" class LLSpinCtrl; @@ -54,7 +54,7 @@ class LLUUID; class LLPanelObject : public LLPanel { public: - LLPanelObject(const std::string& name); + LLPanelObject(); virtual ~LLPanelObject(); virtual BOOL postBuild(); @@ -63,7 +63,7 @@ public: void refresh(); - static BOOL precommitValidate(LLUICtrl* ctrl,void* userdata); + static bool precommitValidate(const LLSD& data); static void onCommitLock(LLUICtrl *ctrl, void *data); static void onCommitPosition( LLUICtrl* ctrl, void* userdata); @@ -78,10 +78,10 @@ public: static void onCommitMaterial( LLUICtrl* ctrl, void* userdata); - static void onCommitSculpt( LLUICtrl* ctrl, void* userdata); - static void onCancelSculpt( LLUICtrl* ctrl, void* userdata); - static void onSelectSculpt( LLUICtrl* ctrl, void* userdata); - static BOOL onDropSculpt( LLUICtrl* ctrl, LLInventoryItem* item, void* ud); + void onCommitSculpt(const LLSD& data); + void onCancelSculpt(const LLSD& data); + void onSelectSculpt(const LLSD& data); + BOOL onDropSculpt(LLInventoryItem* item); static void onCommitSculptType( LLUICtrl *ctrl, void* userdata); diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp new file mode 100644 index 0000000000..697182c8fc --- /dev/null +++ b/indra/newview/llpanelpeople.cpp @@ -0,0 +1,952 @@ +/** + * @file llpanelpeople.cpp + * @brief Side tray "People" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +// libs +#include "llfloaterreg.h" +#include "llmenugl.h" +#include "llfiltereditor.h" +#include "lltabcontainer.h" +#include "lluictrlfactory.h" + +#include "llpanelpeople.h" + +// newview +#include "llagent.h" +#include "llavatarlist.h" +#include "llcallingcard.h" // for LLAvatarTracker +#include "llfloateravatarpicker.h" +//#include "llfloaterminiinspector.h" +#include "llfriendcard.h" +#include "llavataractions.h" +#include "llgroupactions.h" +#include "llgrouplist.h" +#include "llrecentpeople.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewermenu.h" // for gMenuHolder +#include "llvoiceclient.h" +#include "llworld.h" + +using namespace LLOldEvents; + +#define FRIEND_LIST_UPDATE_TIMEOUT 0.5 +#define NEARBY_LIST_UPDATE_INTERVAL 1 +#define RECENT_LIST_UPDATE_DELAY 1 + +static const std::string NEARBY_TAB_NAME = "nearby_panel"; +static const std::string FRIENDS_TAB_NAME = "friends_panel"; +static const std::string GROUP_TAB_NAME = "groups_panel"; +static const std::string RECENT_TAB_NAME = "recent_panel"; + +static LLRegisterPanelClassWrapper t_people("panel_people"); + +//============================================================================= + +/** + * Updates given list either on regular basis or on external events (up to implementation). + */ +class LLPanelPeople::Updater +{ +public: + typedef boost::function callback_t; + Updater(callback_t cb) + : mCallback(cb) + { + } + + virtual ~Updater() + { + } + + /** + * Force the list updates. + * + * This may start repeated updates until all names are complete. + */ + virtual void forceUpdate() + { + updateList(); + } + + /** + * Activate/deactivate updater. + * + * This may start/stop regular updates. + */ + virtual void setActive(bool) {} + +protected: + bool updateList(U32 mask = 0) + { + return mCallback(mask); + } + + callback_t mCallback; +}; + +class LLAvatarListUpdater : public LLPanelPeople::Updater, public LLEventTimer +{ +public: + LLAvatarListUpdater(callback_t cb, F32 period) + : LLEventTimer(period), + LLPanelPeople::Updater(cb) + { + mEventTimer.stop(); + } +}; + +/** + * Updates the friends list. + * + * Updates the list on external events which trigger the changed() method. + */ +class LLFriendListUpdater : public LLAvatarListUpdater, public LLFriendObserver +{ + LOG_CLASS(LLFriendListUpdater); + +public: + LLFriendListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, FRIEND_LIST_UPDATE_TIMEOUT) + { + LLAvatarTracker::instance().addObserver(this); + // For notification when SIP online status changes. + LLVoiceClient::getInstance()->addObserver(this); + } + + ~LLFriendListUpdater() + { + LLVoiceClient::getInstance()->removeObserver(this); + LLAvatarTracker::instance().removeObserver(this); + } + + /*virtual*/ void forceUpdate() + { + // Perform updates until all names are loaded. + if (!updateList(LLFriendObserver::ADD)) + changed(LLFriendObserver::ADD); + } + + /*virtual*/ void changed(U32 mask) + { + // events can arrive quickly in bulk - we need not process EVERY one of them - + // so we wait a short while to let others pile-in, and process them in aggregate. + mEventTimer.start(); + + // save-up all the mask-bits which have come-in + mMask |= mask; + } + + /*virtual*/ BOOL tick() + { + if (updateList(mMask)) + { + // Got all names, stop updates. + mEventTimer.stop(); + mMask = 0; + } + + return FALSE; + } + +private: + U32 mMask; +}; + +/** + * Periodically updates the nearby people list while the Nearby tab is active. + * + * The period is defined by NEARBY_LIST_UPDATE_INTERVAL constant. + */ +class LLNearbyListUpdater : public LLAvatarListUpdater +{ + LOG_CLASS(LLNearbyListUpdater); + +public: + LLNearbyListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, NEARBY_LIST_UPDATE_INTERVAL) + { + setActive(false); + } + + /*virtual*/ void setActive(bool val) + { + if (val) + { + // update immediately and start regular updates + updateList(); + mEventTimer.start(); + } + else + { + // stop regular updates + mEventTimer.stop(); + } + } + + /*virtual*/ BOOL tick() + { + updateList(); + return FALSE; + } +private: +}; + +/** + * Updates the recent people list (those the agent has recently interacted with). + */ +class LLRecentListUpdater : public LLAvatarListUpdater +{ + LOG_CLASS(LLRecentListUpdater); + +public: + LLRecentListUpdater(callback_t cb) + : LLAvatarListUpdater(cb, RECENT_LIST_UPDATE_DELAY) + { + LLRecentPeople::instance().setChangedCallback(boost::bind(&LLRecentListUpdater::onRecentPeopleChanged, this)); + } + +private: + /*virtual*/ void forceUpdate() + { + onRecentPeopleChanged(); + } + + /*virtual*/ BOOL tick() + { + // Update the list until we get all the names. + if (updateList()) + { + // Got all names, stop updates. + mEventTimer.stop(); + } + + return FALSE; + } + + void onRecentPeopleChanged() + { + if (!updateList()) + { + // Some names are incomplete, schedule another update. + mEventTimer.start(); + } + } +}; + +/** + * Updates the group list on events from LLAgent. + */ +class LLGroupListUpdater : public LLPanelPeople::Updater, public LLSimpleListener +{ + LOG_CLASS(LLGroupListUpdater); + +public: + LLGroupListUpdater(callback_t cb) + : LLPanelPeople::Updater(cb) + { + gAgent.addListener(this, "new group"); + } + + ~LLGroupListUpdater() + { + gAgent.removeListener(this); + } + + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata) + { + // Why is "new group" sufficient? + if (event->desc() == "new group") + { + updateList(); + return true; + } + + return false; + } +}; + +//============================================================================= + +LLPanelPeople::LLPanelPeople() + : LLPanel(), + mFilterSubString(LLStringUtil::null), + mFilterEditor(NULL), + mTabContainer(NULL), + mOnlineFriendList(NULL), + mAllFriendList(NULL), + mNearbyList(NULL), + mRecentList(NULL) +{ + mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::onFriendListUpdate,this, _1)); + mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList, this)); + mRecentListUpdater = new LLRecentListUpdater(boost::bind(&LLPanelPeople::updateRecentList, this)); + mGroupListUpdater = new LLGroupListUpdater (boost::bind(&LLPanelPeople::updateGroupList, this)); +} + +LLPanelPeople::~LLPanelPeople() +{ + delete mNearbyListUpdater; + delete mFriendListUpdater; + delete mRecentListUpdater; + delete mGroupListUpdater; + + LLView::deleteViewByHandle(mGroupPlusMenuHandle); + LLView::deleteViewByHandle(mNearbyViewSortMenuHandle); + LLView::deleteViewByHandle(mFriendsViewSortMenuHandle); + LLView::deleteViewByHandle(mRecentViewSortMenuHandle); + +} + +BOOL LLPanelPeople::postBuild() +{ + mVisibleSignal.connect(boost::bind(&LLPanelPeople::onVisibilityChange, this, _2)); + + mFilterEditor = getChild("filter_input"); + mFilterEditor->setCommitCallback(boost::bind(&LLPanelPeople::onFilterEdit, this, _2)); + + mTabContainer = getChild("tabs"); + mTabContainer->setCommitCallback(boost::bind(&LLPanelPeople::onTabSelected, this, _2)); + + mOnlineFriendList = getChild(FRIENDS_TAB_NAME)->getChild("avatars_online"); + mAllFriendList = getChild(FRIENDS_TAB_NAME)->getChild("avatars_all"); + + mNearbyList = getChild(NEARBY_TAB_NAME)->getChild("avatar_list"); + + mRecentList = getChild(RECENT_TAB_NAME)->getChild("avatar_list"); + mGroupList = getChild("group_list"); + + LLPanel* groups_panel = getChild(GROUP_TAB_NAME); + groups_panel->childSetAction("activate_btn", boost::bind(&LLPanelPeople::onActivateButtonClicked, this)); + groups_panel->childSetAction("plus_btn", boost::bind(&LLPanelPeople::onGroupPlusButtonClicked, this)); + groups_panel->childSetAction("minus_btn", boost::bind(&LLPanelPeople::onGroupMinusButtonClicked, this)); + + LLPanel* friends_panel = getChild(FRIENDS_TAB_NAME); + friends_panel->childSetAction("add_btn", boost::bind(&LLPanelPeople::onAddFriendWizButtonClicked, this)); + friends_panel->childSetAction("del_btn", boost::bind(&LLPanelPeople::onDeleteFriendButtonClicked, this)); + + mOnlineFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mOnlineFriendList)); + mAllFriendList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mAllFriendList)); + mNearbyList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mNearbyList)); + mRecentList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, mRecentList)); + mOnlineFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mOnlineFriendList)); + mAllFriendList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mAllFriendList)); + mNearbyList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mNearbyList)); + mRecentList->setCommitCallback(boost::bind(&LLPanelPeople::onAvatarListCommitted, this, mRecentList)); + + mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this)); + mGroupList->setCommitCallback(boost::bind(&LLPanelPeople::updateButtons, this)); + + buttonSetAction("view_profile_btn", boost::bind(&LLPanelPeople::onViewProfileButtonClicked, this)); + buttonSetAction("add_friend_btn", boost::bind(&LLPanelPeople::onAddFriendButtonClicked, this)); + buttonSetAction("group_info_btn", boost::bind(&LLPanelPeople::onGroupInfoButtonClicked, this)); + buttonSetAction("chat_btn", boost::bind(&LLPanelPeople::onChatButtonClicked, this)); + buttonSetAction("im_btn", boost::bind(&LLPanelPeople::onImButtonClicked, this)); + buttonSetAction("call_btn", boost::bind(&LLPanelPeople::onCallButtonClicked, this)); + buttonSetAction("teleport_btn", boost::bind(&LLPanelPeople::onTeleportButtonClicked, this)); + buttonSetAction("share_btn", boost::bind(&LLPanelPeople::onShareButtonClicked, this)); + + getChild(NEARBY_TAB_NAME)->childSetAction("nearby_view_sort_btn",boost::bind(&LLPanelPeople::onNearbyViewSortButtonClicked, this)); + getChild(RECENT_TAB_NAME)->childSetAction("recent_viewsort_btn",boost::bind(&LLPanelPeople::onRecentViewSortButtonClicked, this)); + getChild(FRIENDS_TAB_NAME)->childSetAction("friends_viewsort_btn",boost::bind(&LLPanelPeople::onFriendsViewSortButtonClicked, this)); + + // Must go after setting commit callback and initializing all pointers to children. + mTabContainer->selectTabByName(FRIENDS_TAB_NAME); + + // Create menus. + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + + registrar.add("People.Group.Plus.Action", boost::bind(&LLPanelPeople::onGroupPlusMenuItemClicked, this, _2)); + registrar.add("People.Friends.ViewSort.Action", boost::bind(&LLPanelPeople::onFriendsViewSortMenuItemClicked, this, _2)); + registrar.add("People.Nearby.ViewSort.Action", boost::bind(&LLPanelPeople::onNearbyViewSortMenuItemClicked, this, _2)); + registrar.add("People.Recent.ViewSort.Action", boost::bind(&LLPanelPeople::onRecentViewSortMenuItemClicked, this, _2)); + + LLMenuGL* plus_menu = LLUICtrlFactory::getInstance()->createFromFile("menu_group_plus.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + mGroupPlusMenuHandle = plus_menu->getHandle(); + + LLMenuGL* nearby_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_nearby_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(nearby_view_sort) + mNearbyViewSortMenuHandle = nearby_view_sort->getHandle(); + + LLMenuGL* friend_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_friends_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(friend_view_sort) + mFriendsViewSortMenuHandle = friend_view_sort->getHandle(); + + LLMenuGL* recent_view_sort = LLUICtrlFactory::getInstance()->createFromFile("menu_people_recent_view_sort.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if(recent_view_sort) + mRecentViewSortMenuHandle = recent_view_sort->getHandle(); + + + + // Perform initial update. + mFriendListUpdater->forceUpdate(); + mRecentListUpdater->forceUpdate(); + mGroupListUpdater->forceUpdate(); + mRecentListUpdater->forceUpdate(); + + return TRUE; +} + +bool LLPanelPeople::updateFriendList(U32 changed_mask) +{ + // Refresh names. + if (changed_mask & (LLFriendObserver::ADD | LLFriendObserver::REMOVE | LLFriendObserver::ONLINE)) + { + // get all buddies we know about + const LLAvatarTracker& av_tracker = LLAvatarTracker::instance(); + LLAvatarTracker::buddy_map_t all_buddies; + av_tracker.copyBuddyList(all_buddies); + + // *TODO: it's suboptimal to rebuild the whole lists on online status change. + + // save them to the online and all friends vectors + mOnlineFriendVec.clear(); + mAllFriendVec.clear(); + + LLFriendCardsManager::folderid_buddies_map_t listMap; + + // *NOTE: For now collectFriendsLists returns data only for Friends/All folder. EXT-694. + LLFriendCardsManager::instance().collectFriendsLists(listMap); + if (listMap.size() > 0) + { + mAllFriendVec = listMap.begin()->second; + } + + LLAvatarTracker::buddy_map_t::const_iterator buddy_it = all_buddies.begin(); + for (; buddy_it != all_buddies.end(); ++buddy_it) + { + LLUUID buddy_id = buddy_it->first; + if (av_tracker.isBuddyOnline(buddy_id)) + mOnlineFriendVec.push_back(buddy_id); + } + + return filterFriendList(); + } + + return true; +} + +bool LLPanelPeople::updateNearbyList() +{ + LLWorld::getInstance()->getAvatars(&mNearbyVec, NULL, gAgent.getPositionGlobal(), gSavedSettings.getF32("NearMeRange")); + filterNearbyList(); + + return true; +} + +bool LLPanelPeople::updateRecentList() +{ + LLRecentPeople::instance().get(mRecentVec); + filterRecentList(); + + return true; +} + +bool LLPanelPeople::updateGroupList() +{ + if (!mGroupList) + return true; // there's no point in further updates + + bool have_names = mGroupList->update(mFilterSubString); + + if (mGroupList->isEmpty()) + mGroupList->setCommentText(getString("no_groups")); + + return have_names; +} + +bool LLPanelPeople::filterFriendList() +{ + if (!mOnlineFriendList || !mAllFriendList) + return true; // there's no point in further updates + + // We must always update Friends list to clear the latest removed friend. + bool have_names = + mOnlineFriendList->update(mOnlineFriendVec, mFilterSubString) & + mAllFriendList->update(mAllFriendVec, mFilterSubString); + + if (mOnlineFriendVec.size() == 0) + mOnlineFriendList->setCommentText(getString("no_friends_online")); + + if (mAllFriendVec.size() == 0) + mAllFriendList->setCommentText(getString("no_friends")); + + return have_names; +} + +bool LLPanelPeople::filterNearbyList() +{ + bool have_names = mNearbyList->update(mNearbyVec, mFilterSubString); + + if (mNearbyVec.size() == 0) + mNearbyList->setCommentText(getString("no_one_near")); + + return have_names; +} + +bool LLPanelPeople::filterRecentList() +{ + if (!mRecentList) + return true; + + if (mRecentVec.size() > 0) + return mRecentList->update(mRecentVec, mFilterSubString); + + mRecentList->setCommentText(getString("no_people")); + + return true; +} + +void LLPanelPeople::buttonSetVisible(std::string btn_name, BOOL visible) +{ + // Currently all bottom buttons are wrapped with layout panels. + // Hiding a button has no effect: the panel still occupies its space. + // So we have to hide the whole panel (along with its button) + // to free some space up. + LLButton* btn = getChild("button_bar")->getChild(btn_name); + LLPanel* btn_parent = dynamic_cast(btn->getParent()); + if (btn_parent) + btn_parent->setVisible(visible); +} + +void LLPanelPeople::buttonSetEnabled(const std::string& btn_name, bool enabled) +{ + // To make sure we're referencing the right widget (a child of the button bar). + LLButton* button = getChild("button_bar")->getChild(btn_name); + button->setEnabled(enabled); +} + +void LLPanelPeople::buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb) +{ + // To make sure we're referencing the right widget (a child of the button bar). + LLButton* button = getChild("button_bar")->getChild(btn_name); + button->setClickedCallback(cb); +} + +void LLPanelPeople::updateButtons() +{ + std::string cur_tab = getActiveTabName(); + bool nearby_tab_active = (cur_tab == NEARBY_TAB_NAME); + bool friends_tab_active = (cur_tab == FRIENDS_TAB_NAME); + bool group_tab_active = (cur_tab == GROUP_TAB_NAME); + bool recent_tab_active = (cur_tab == RECENT_TAB_NAME); + LLUUID selected_id; + + buttonSetVisible("group_info_btn", group_tab_active); + buttonSetVisible("chat_btn", group_tab_active); + buttonSetVisible("add_friend_btn", nearby_tab_active || recent_tab_active); + buttonSetVisible("view_profile_btn", !group_tab_active); + buttonSetVisible("im_btn", !group_tab_active); + buttonSetVisible("teleport_btn", friends_tab_active); + buttonSetVisible("share_btn", !recent_tab_active && false); // not implemented yet + + if (group_tab_active) + { + bool item_selected = mGroupList->getFirstSelected() != NULL; + bool cur_group_active = true; + + if (item_selected) + { + selected_id = mGroupList->getCurrentID(); + cur_group_active = (gAgent.getGroupID() == selected_id); + } + + LLPanel* groups_panel = mTabContainer->getCurrentPanel(); + groups_panel->childSetEnabled("activate_btn", item_selected && !cur_group_active); // "none" or a non-active group selected + groups_panel->childSetEnabled("plus_btn", item_selected); + groups_panel->childSetEnabled("minus_btn", item_selected && selected_id.notNull()); + } + else + { + bool is_friend = true; + + // Check whether selected avatar is our friend. + if ((selected_id = getCurrentItemID()).notNull()) + { + is_friend = LLAvatarTracker::instance().getBuddyInfo(selected_id) != NULL; + } + + childSetEnabled("add_friend_btn", !is_friend); + } + + bool item_selected = selected_id.notNull(); + buttonSetEnabled("teleport_btn", friends_tab_active && item_selected); + buttonSetEnabled("view_profile_btn", item_selected); + buttonSetEnabled("im_btn", item_selected); + buttonSetEnabled("call_btn", item_selected && false); // not implemented yet + buttonSetEnabled("share_btn", item_selected && false); // not implemented yet + buttonSetEnabled("group_info_btn", item_selected); + buttonSetEnabled("chat_btn", item_selected); +} + +const std::string& LLPanelPeople::getActiveTabName() const +{ + return mTabContainer->getCurrentPanel()->getName(); +} + +LLUUID LLPanelPeople::getCurrentItemID() const +{ + std::string cur_tab = getActiveTabName(); + + if (cur_tab == FRIENDS_TAB_NAME) // this tab has two lists + { + LLUUID cur_online_friend; + + if ((cur_online_friend = mOnlineFriendList->getCurrentID()).notNull()) + return cur_online_friend; + + return mAllFriendList->getCurrentID(); + } + + if (cur_tab == NEARBY_TAB_NAME) + return mNearbyList->getCurrentID(); + + if (cur_tab == RECENT_TAB_NAME) + return mRecentList->getCurrentID(); + + if (cur_tab == GROUP_TAB_NAME) + return mGroupList->getCurrentID(); + + llassert(0 && "unknown tab selected"); + return LLUUID::null; +} + +void LLPanelPeople::showGroupMenu(LLMenuGL* menu) +{ + // Shows the menu at the top of the button bar. + + // Calculate its coordinates. + // (assumes that groups panel is the current tab) + LLPanel* bottom_panel = mTabContainer->getCurrentPanel()->getChild("bottom_panel"); + LLPanel* parent_panel = mTabContainer->getCurrentPanel(); + menu->arrangeAndClear(); + S32 menu_height = menu->getRect().getHeight(); + S32 menu_x = -2; // *HACK: compensates HPAD in showPopup() + S32 menu_y = bottom_panel->getRect().mTop + menu_height; + + // Actually show the menu. + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(parent_panel, menu, menu_x, menu_y); +} + +void LLPanelPeople::onVisibilityChange(const LLSD& new_visibility) +{ + if (new_visibility.asBoolean() == FALSE) + { + // Don't update anything while we're invisible. + mNearbyListUpdater->setActive(FALSE); + } + else + { + reSelectedCurrentTab(); + } +} + +// Make the tab-container re-select current tab +// for onTabSelected() callback to get called. +// (currently this is needed to reactivate nearby list updates +// when we get visible) +void LLPanelPeople::reSelectedCurrentTab() +{ + mTabContainer->selectTab(mTabContainer->getCurrentPanelIndex()); +} + +void LLPanelPeople::onFilterEdit(const std::string& search_string) +{ + if (mFilterSubString == search_string) + return; + + mFilterSubString = search_string; + + // Searches are case-insensitive + LLStringUtil::toUpper(mFilterSubString); + LLStringUtil::trimHead(mFilterSubString); + + // Apply new filter to all tabs. + filterNearbyList(); + filterFriendList(); + filterRecentList(); + updateGroupList(); + + updateButtons(); +} + +void LLPanelPeople::onTabSelected(const LLSD& param) +{ + std::string tab_name = getChild(param.asString())->getName(); + mNearbyListUpdater->setActive(tab_name == NEARBY_TAB_NAME); + updateButtons(); + + if (GROUP_TAB_NAME == tab_name) + mFilterEditor->setLabel(getString("groups_filter_label")); + else + mFilterEditor->setLabel(getString("people_filter_label")); +} + +void LLPanelPeople::onAvatarListDoubleClicked(LLAvatarList* list) +{ + LLUUID clicked_id = list->getCurrentID(); + + if (clicked_id.isNull()) + return; + +#if 0 // SJB: Useful for testing, but not currently functional or to spec + LLAvatarActions::showProfile(clicked_id); +#else // spec says open IM window + LLAvatarActions::startIM(clicked_id); +#endif +} + +void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list) +{ + // Make sure only one of the friends lists (online/all) has selection. + if (getActiveTabName() == FRIENDS_TAB_NAME) + { + if (list == mOnlineFriendList) + mAllFriendList->deselectAllItems(TRUE); + else if (list == mAllFriendList) + mOnlineFriendList->deselectAllItems(TRUE); + else + llassert(0 && "commit on unknown friends list"); + } + + updateButtons(); +} + +void LLPanelPeople::onViewProfileButtonClicked() +{ + LLUUID id = getCurrentItemID(); + LLAvatarActions::showProfile(id); +} + +void LLPanelPeople::onAddFriendButtonClicked() +{ + LLUUID id = getCurrentItemID(); + if (id.notNull()) + { + LLAvatarActions::requestFriendshipDialog(id); + } +} + +void LLPanelPeople::onAddFriendWizButtonClicked() +{ + // Show add friend wizard. + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show(onAvatarPicked, NULL, FALSE, TRUE); + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) + { + root_floater->addDependentFloater(picker); + } +} + +void LLPanelPeople::onDeleteFriendButtonClicked() +{ + LLAvatarActions::removeFriendDialog(getCurrentItemID()); +} + +void LLPanelPeople::onGroupInfoButtonClicked() +{ + LLGroupActions::show(getCurrentItemID()); +} + +void LLPanelPeople::onChatButtonClicked() +{ + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::startChat(group_id); +} + +void LLPanelPeople::onImButtonClicked() +{ + LLUUID id = getCurrentItemID(); + if (id.notNull()) + { + LLAvatarActions::startIM(id); + } +} + +void LLPanelPeople::onActivateButtonClicked() +{ + LLGroupActions::activate(mGroupList->getCurrentID()); +} + +// static +void LLPanelPeople::onAvatarPicked( + const std::vector& names, + const std::vector& ids, + void*) +{ + if (!names.empty() && !ids.empty()) + LLAvatarActions::requestFriendshipDialog(ids[0], names[0]); +} + +bool LLPanelPeople::onFriendListUpdate(U32 changed_mask) +{ + bool have_names = updateFriendList(changed_mask); + + // Update online status in the Recent tab. + // *TODO: isn't it too much to update the whole list? + updateRecentList(); + + return have_names; +} + +void LLPanelPeople::onGroupPlusButtonClicked() +{ + LLMenuGL* plus_menu = (LLMenuGL*)mGroupPlusMenuHandle.get(); + if (!plus_menu) + return; + + showGroupMenu(plus_menu); +} + +void LLPanelPeople::onGroupMinusButtonClicked() +{ + LLUUID group_id = getCurrentItemID(); + if (group_id.notNull()) + LLGroupActions::leave(group_id); +} + +void LLPanelPeople::onGroupPlusMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if (chosen_item == "join_group") + LLGroupActions::search(); + else if (chosen_item == "new_group") + LLGroupActions::createGroup(); +} + +void LLPanelPeople::onFriendsViewSortMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_name") + { + } + else if (chosen_item == "sort_status") + { + } + else if (chosen_item == "view_icons") + { + } + else if (chosen_item == "organize_offline") + { + } +} +void LLPanelPeople::onNearbyViewSortMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_recent") + { + } + else if (chosen_item == "sort_name") + { + } + else if (chosen_item == "view_icons") + { + } + else if (chosen_item == "sort_distance") + { + } +} +void LLPanelPeople::onRecentViewSortMenuItemClicked(const LLSD& userdata) +{ + std::string chosen_item = userdata.asString(); + + if (chosen_item == "sort_most") + { + } + else if (chosen_item == "sort_name") + { + } + else if (chosen_item == "view_icons") + { + } +} + + +void LLPanelPeople::onCallButtonClicked() +{ + // *TODO: not implemented yet +} + +void LLPanelPeople::onTeleportButtonClicked() +{ + LLAvatarActions::offerTeleport(getCurrentItemID()); +} + +void LLPanelPeople::onShareButtonClicked() +{ + // *TODO: not implemented yet +} + +void LLPanelPeople::onMoreButtonClicked() +{ + // *TODO: not implemented yet +} +void LLPanelPeople::onFriendsViewSortButtonClicked() +{ + LLMenuGL* menu = (LLMenuGL*)mFriendsViewSortMenuHandle.get(); + if (!menu) + return; + showGroupMenu(menu); +} +void LLPanelPeople::onRecentViewSortButtonClicked() +{ + LLMenuGL* menu = (LLMenuGL*)mRecentViewSortMenuHandle.get(); + if (!menu) + return; + showGroupMenu(menu); +} +void LLPanelPeople::onNearbyViewSortButtonClicked() +{ + LLMenuGL* menu = (LLMenuGL*)mNearbyViewSortMenuHandle.get(); + if (!menu) + return; + showGroupMenu(menu); +} + +void LLPanelPeople::onOpen(const LLSD& key) +{ + std::string tab_name = key["people_panel_tab_name"]; + mFilterEditor -> clear(); + onFilterEdit(""); + + if (!tab_name.empty()) + mTabContainer->selectTabByName(tab_name); + else + reSelectedCurrentTab(); +} + diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h new file mode 100644 index 0000000000..3358a70bac --- /dev/null +++ b/indra/newview/llpanelpeople.h @@ -0,0 +1,149 @@ +/** + * @file llpanelpeople.h + * @brief Side tray "People" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPEOPLE_H +#define LL_LLPANELPEOPLE_H + +#include + +#include "llcallingcard.h" // for avatar tracker + +class LLFilterEditor; +class LLTabContainer; +class LLAvatarList; +class LLGroupList; + +class LLPanelPeople : public LLPanel +{ + LOG_CLASS(LLPanelPeople); +public: + LLPanelPeople(); + virtual ~LLPanelPeople(); + + /*virtual*/ BOOL postBuild(); + + virtual void onOpen(const LLSD& key); + + // internals + class Updater; + +private: + // methods indirectly called by the updaters + bool updateFriendList(U32 changed_mask); + bool updateNearbyList(); + bool updateRecentList(); + bool updateGroupList(); + + bool filterFriendList(); + bool filterNearbyList(); + bool filterRecentList(); + void updateButtons(); + const std::string& getActiveTabName() const; + LLUUID getCurrentItemID() const; + void buttonSetVisible(std::string btn_name, BOOL visible); + void buttonSetEnabled(const std::string& btn_name, bool enabled); + void buttonSetAction(const std::string& btn_name, const commit_signal_t::slot_type& cb); + void showGroupMenu(LLMenuGL* menu); + + void onVisibilityChange( const LLSD& new_visibility); + + void reSelectedCurrentTab(); + + // UI callbacks + void onFilterEdit(const std::string& search_string); + void onTabSelected(const LLSD& param); + void onViewProfileButtonClicked(); + void onAddFriendButtonClicked(); + void onAddFriendWizButtonClicked(); + void onDeleteFriendButtonClicked(); + void onGroupInfoButtonClicked(); + void onChatButtonClicked(); + void onImButtonClicked(); + void onCallButtonClicked(); + void onTeleportButtonClicked(); + void onShareButtonClicked(); + void onMoreButtonClicked(); + void onActivateButtonClicked(); + void onRecentViewSortButtonClicked(); + void onNearbyViewSortButtonClicked(); + void onFriendsViewSortButtonClicked(); + void onAvatarListDoubleClicked(LLAvatarList* list); + void onAvatarListCommitted(LLAvatarList* list); + void onGroupPlusButtonClicked(); + void onGroupMinusButtonClicked(); + void onGroupPlusMenuItemClicked(const LLSD& userdata); + + void onFriendsViewSortMenuItemClicked(const LLSD& userdata); + void onNearbyViewSortMenuItemClicked(const LLSD& userdata); + void onRecentViewSortMenuItemClicked(const LLSD& userdata); + + // misc callbacks + bool onFriendListUpdate(U32 changed_mask); + static void onAvatarPicked( + const std::vector& names, + const std::vector& ids, + void*); + + LLFilterEditor* mFilterEditor; + LLTabContainer* mTabContainer; + LLAvatarList* mOnlineFriendList; + LLAvatarList* mAllFriendList; + LLAvatarList* mNearbyList; + LLAvatarList* mRecentList; + LLGroupList* mGroupList; + + LLHandle mGroupPlusMenuHandle; + LLHandle mNearbyViewSortMenuHandle; + LLHandle mFriendsViewSortMenuHandle; + LLHandle mRecentViewSortMenuHandle; + + Updater* mFriendListUpdater; + Updater* mNearbyListUpdater; + Updater* mRecentListUpdater; + Updater* mGroupListUpdater; + + std::string mFilterSubString; + + // The vectors below contain up-to date avatar lists + // for the corresponding tabs. + // When the user enters a filter, it gets applied + // to all the vectors and the result is shown in the tabs. + // We don't need to have such a vector for the groups tab + // since re-fetching the groups list is always fast. + typedef std::vector uuid_vector_t; + uuid_vector_t mNearbyVec; + uuid_vector_t mOnlineFriendVec; + uuid_vector_t mAllFriendVec; + uuid_vector_t mRecentVec; +}; + +#endif //LL_LLPANELPEOPLE_H diff --git a/indra/newview/llpanelpermissions.cpp b/indra/newview/llpanelpermissions.cpp index 389f06f355..42f9906409 100644 --- a/indra/newview/llpanelpermissions.cpp +++ b/indra/newview/llpanelpermissions.cpp @@ -53,73 +53,64 @@ #include "llagent.h" #include "llstatusbar.h" // for getBalance() #include "lllineeditor.h" -#include "llradiogroup.h" #include "llcombobox.h" -#include "llfloateravatarinfo.h" #include "lluiconstants.h" #include "lldbstrings.h" -#include "llfloatergroupinfo.h" #include "llfloatergroups.h" +#include "llfloaterreg.h" +#include "llavataractions.h" #include "llnamebox.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" +#include "llspinctrl.h" #include "roles_constants.h" +#include "llgroupactions.h" ///---------------------------------------------------------------------------- /// Class llpanelpermissions ///---------------------------------------------------------------------------- // Default constructor -LLPanelPermissions::LLPanelPermissions(const std::string& title) : - LLPanel(title) +LLPanelPermissions::LLPanelPermissions() : + LLPanel() { setMouseOpaque(FALSE); } BOOL LLPanelPermissions::postBuild() { - this->childSetCommitCallback("Object Name",LLPanelPermissions::onCommitName,this); - this->childSetPrevalidate("Object Name",LLLineEditor::prevalidatePrintableNotPipe); - this->childSetCommitCallback("Object Description",LLPanelPermissions::onCommitDesc,this); - this->childSetPrevalidate("Object Description",LLLineEditor::prevalidatePrintableNotPipe); + childSetCommitCallback("Object Name",LLPanelPermissions::onCommitName,this); + childSetPrevalidate("Object Name",LLLineEditor::prevalidatePrintableNotPipe); + childSetCommitCallback("Object Description",LLPanelPermissions::onCommitDesc,this); + childSetPrevalidate("Object Description",LLLineEditor::prevalidatePrintableNotPipe); - this->childSetAction("button owner profile",LLPanelPermissions::onClickOwner,this); - this->childSetAction("button creator profile",LLPanelPermissions::onClickCreator,this); + childSetAction("button owner profile",LLPanelPermissions::onClickOwner,this); + childSetAction("button creator profile",LLPanelPermissions::onClickCreator,this); - this->childSetAction("button set group",LLPanelPermissions::onClickGroup,this); + getChild("button set group")->setCommitCallback(boost::bind(&LLPanelPermissions::onClickGroup,this)); - this->childSetCommitCallback("checkbox share with group",LLPanelPermissions::onCommitGroupShare,this); + childSetCommitCallback("checkbox share with group",LLPanelPermissions::onCommitGroupShare,this); - this->childSetAction("button deed",LLPanelPermissions::onClickDeedToGroup,this); + childSetAction("button deed",LLPanelPermissions::onClickDeedToGroup,this); - this->childSetCommitCallback("checkbox allow everyone move",LLPanelPermissions::onCommitEveryoneMove,this); + childSetCommitCallback("checkbox allow everyone move",LLPanelPermissions::onCommitEveryoneMove,this); - this->childSetCommitCallback("checkbox allow everyone copy",LLPanelPermissions::onCommitEveryoneCopy,this); + childSetCommitCallback("checkbox allow everyone copy",LLPanelPermissions::onCommitEveryoneCopy,this); - this->childSetCommitCallback("checkbox for sale",LLPanelPermissions::onCommitSaleInfo,this); + childSetCommitCallback("checkbox for sale",LLPanelPermissions::onCommitSaleInfo,this); - this->childSetCommitCallback("Edit Cost",LLPanelPermissions::onCommitSaleInfo,this); - this->childSetPrevalidate("Edit Cost",LLLineEditor::prevalidateNonNegativeS32); + childSetCommitCallback("sale type",LLPanelPermissions::onCommitSaleType,this); - this->childSetCommitCallback("sale type",LLPanelPermissions::onCommitSaleType,this); + childSetCommitCallback("Edit Cost", LLPanelPermissions::onCommitSaleInfo, this); - this->childSetCommitCallback("checkbox next owner can modify",LLPanelPermissions::onCommitNextOwnerModify,this); - this->childSetCommitCallback("checkbox next owner can copy",LLPanelPermissions::onCommitNextOwnerCopy,this); - this->childSetCommitCallback("checkbox next owner can transfer",LLPanelPermissions::onCommitNextOwnerTransfer,this); - this->childSetCommitCallback("clickaction",LLPanelPermissions::onCommitClickAction,this); - this->childSetCommitCallback("search_check",LLPanelPermissions::onCommitIncludeInSearch,this); + childSetCommitCallback("checkbox next owner can modify",LLPanelPermissions::onCommitNextOwnerModify,this); + childSetCommitCallback("checkbox next owner can copy",LLPanelPermissions::onCommitNextOwnerCopy,this); + childSetCommitCallback("checkbox next owner can transfer",LLPanelPermissions::onCommitNextOwnerTransfer,this); + childSetCommitCallback("clickaction",LLPanelPermissions::onCommitClickAction,this); + childSetCommitCallback("search_check",LLPanelPermissions::onCommitIncludeInSearch,this); - LLTextBox* group_rect_proxy = getChild("Group Name Proxy"); - if(group_rect_proxy ) - { - mLabelGroupName = new LLNameBox("Group Name", group_rect_proxy->getRect()); - addChild(mLabelGroupName); - } - else - { - mLabelGroupName = NULL; - } + mLabelGroupName = getChild("Group Name Proxy"); return TRUE; } @@ -137,7 +128,7 @@ void LLPanelPermissions::refresh() if(BtnDeedToGroup) { std::string deedText; - if (gSavedSettings.getWarning("DeedObject")) + if (gWarningSettings.getBOOL("DeedObject")) { deedText = getString("text deed continued"); } @@ -220,12 +211,9 @@ void LLPanelPermissions::refresh() childSetValue("search_check", FALSE); childSetEnabled("search_check", false); - LLRadioGroup* RadioSaleType = getChild("sale type"); - if(RadioSaleType) - { - RadioSaleType->setSelectedIndex(-1); - RadioSaleType->setEnabled(FALSE); - } + LLComboBox* combo_sale_type = getChild("sale type"); + combo_sale_type->setValue(LLSaleInfo::FS_COPY); + combo_sale_type->setEnabled(FALSE); childSetEnabled("Cost",false); childSetText("Cost",getString("Cost Default")); @@ -256,7 +244,7 @@ void LLPanelPermissions::refresh() BOOL is_perm_modify = (LLSelectMgr::getInstance()->getSelection()->getFirstRootNode() && LLSelectMgr::getInstance()->selectGetRootsModify()) || LLSelectMgr::getInstance()->selectGetModify(); - const LLView* keyboard_focus_view = gFocusMgr.getKeyboardFocus(); + const LLFocusableElement* keyboard_focus_view = gFocusMgr.getKeyboardFocus(); S32 string_index = 0; std::string MODIFY_INFO_STRINGS[] = { @@ -429,22 +417,22 @@ void LLPanelPermissions::refresh() childSetText("Cost",getString("Cost Default")); } - LLLineEditor *editPrice = getChild("Edit Cost"); - if(keyboard_focus_view != editPrice) + LLSpinCtrl *edit_price = getChild("Edit Cost"); + if(!edit_price->hasFocus()) { // If the sale price is mixed then set the cost to MIXED, otherwise // set to the actual cost. if (num_for_sale > 0 && is_for_sale_mixed) { - childSetText("Edit Cost",getString("Sale Mixed")); + edit_price->setTentative(TRUE); } else if (num_for_sale > 0 && is_sale_price_mixed) { - childSetText("Edit Cost",getString("Cost Mixed")); + edit_price->setTentative(TRUE); } else { - childSetText("Edit Cost",llformat("%d",individual_sale_price)); + edit_price->setValue(individual_sale_price); } } // The edit fields are only enabled if you can sell this object @@ -754,20 +742,17 @@ void LLPanelPermissions::refresh() BOOL valid_sale_info = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info); LLSaleInfo::EForSale sale_type = sale_info.getSaleType(); - LLRadioGroup* RadioSaleType = getChild("sale type"); - if(RadioSaleType) + LLComboBox* combo_sale_type = getChild("sale type"); + if (valid_sale_info) { - if (valid_sale_info) - { - RadioSaleType->setSelectedIndex((S32)sale_type - 1); - RadioSaleType->setTentative(FALSE); // unfortunately this doesn't do anything at the moment. - } - else - { - // default option is sell copy, determined to be safest - RadioSaleType->setSelectedIndex((S32)LLSaleInfo::FS_COPY - 1); - RadioSaleType->setTentative(TRUE); // unfortunately this doesn't do anything at the moment. - } + combo_sale_type->setValue(sale_type == LLSaleInfo::FS_NOT ? LLSaleInfo::FS_COPY : sale_type); + combo_sale_type->setTentative(FALSE); // unfortunately this doesn't do anything at the moment. + } + else + { + // default option is sell copy, determined to be safest + combo_sale_type->setValue(LLSaleInfo::FS_COPY); + combo_sale_type->setTentative(TRUE); // unfortunately this doesn't do anything at the moment. } childSetValue("checkbox for sale", num_for_sale != 0); @@ -823,7 +808,7 @@ void LLPanelPermissions::onClickCreator(void *data) { LLPanelPermissions *self = (LLPanelPermissions *)data; - LLFloaterAvatarInfo::showFromObject(self->mCreatorID); + LLAvatarActions::showProfile(self->mCreatorID); } // static @@ -835,44 +820,43 @@ void LLPanelPermissions::onClickOwner(void *data) { LLUUID group_id; LLSelectMgr::getInstance()->selectGetGroup(group_id); - LLFloaterGroupInfo::showFromUUID(group_id); + LLGroupActions::show(group_id); } else { - LLFloaterAvatarInfo::showFromObject(self->mOwnerID); + LLAvatarActions::showProfile(self->mOwnerID); } } -void LLPanelPermissions::onClickGroup(void* data) +void LLPanelPermissions::onClickGroup() { - LLPanelPermissions* panelp = (LLPanelPermissions*)data; LLUUID owner_id; std::string name; BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, name); - LLFloater* parent_floater = gFloaterView->getParentFloater(panelp); + LLFloater* parent_floater = gFloaterView->getParentFloater(this); if(owners_identical && (owner_id == gAgent.getID())) { - LLFloaterGroupPicker* fg; - fg = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); - fg->setSelectCallback( cbGroupID, data ); - - if (parent_floater) + LLFloaterGroupPicker* fg = LLFloaterReg::showTypedInstance("group_picker", LLSD(gAgent.getID())); + if (fg) { - LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, fg); - fg->setOrigin(new_rect.mLeft, new_rect.mBottom); - parent_floater->addDependentFloater(fg); + fg->setSelectGroupCallback( boost::bind(&LLPanelPermissions::cbGroupID, this, _1) ); + + if (parent_floater) + { + LLRect new_rect = gFloaterView->findNeighboringPosition(parent_floater, fg); + fg->setOrigin(new_rect.mLeft, new_rect.mBottom); + parent_floater->addDependentFloater(fg); + } } } } -// static -void LLPanelPermissions::cbGroupID(LLUUID group_id, void* userdata) +void LLPanelPermissions::cbGroupID(LLUUID group_id) { - LLPanelPermissions* self = (LLPanelPermissions*)userdata; - if(self->mLabelGroupName) + if(mLabelGroupName) { - self->mLabelGroupName->setNameID(group_id, TRUE); + mLabelGroupName->setNameID(group_id, TRUE); } LLSelectMgr::getInstance()->sendGroup(group_id); } @@ -1006,44 +990,14 @@ void LLPanelPermissions::setAllSaleInfo() // Set the sale type if the object(s) are for sale. if(checkPurchase && checkPurchase->get()) { - LLRadioGroup* RadioSaleType = getChild("sale type"); - if(RadioSaleType) - { - switch(RadioSaleType->getSelectedIndex()) - { - case 0: - sale_type = LLSaleInfo::FS_ORIGINAL; - break; - case 1: - sale_type = LLSaleInfo::FS_COPY; - break; - case 2: - sale_type = LLSaleInfo::FS_CONTENTS; - break; - default: - sale_type = LLSaleInfo::FS_COPY; - break; - } - } + sale_type = static_cast(getChild("sale type")->getValue().asInteger()); } S32 price = -1; - LLLineEditor *editPrice = getChild("Edit Cost"); - if (editPrice) - { - // Don't extract the price if it's labeled as MIXED or is empty. - const std::string& editPriceString = editPrice->getText(); - if (editPriceString != getString("Cost Mixed") && editPriceString != getString("Sale Mixed") && - !editPriceString.empty()) - { - price = atoi(editPriceString.c_str()); - } - else - { - price = DEFAULT_PRICE; - } - } + LLSpinCtrl *edit_price = getChild("Edit Cost"); + price = (edit_price->getTentative()) ? DEFAULT_PRICE : edit_price->getValue().asInteger(); + // If somehow an invalid price, turn the sale off. if (price < 0) sale_type = LLSaleInfo::FS_NOT; diff --git a/indra/newview/llpanelpermissions.h b/indra/newview/llpanelpermissions.h index bb816acd07..481efe178e 100644 --- a/indra/newview/llpanelpermissions.h +++ b/indra/newview/llpanelpermissions.h @@ -53,24 +53,22 @@ class LLNameBox; class LLPanelPermissions : public LLPanel { public: - LLPanelPermissions(const std::string& title); + LLPanelPermissions(); virtual ~LLPanelPermissions(); virtual BOOL postBuild(); // MANIPULATORS void refresh(); // refresh all labels as needed -// void setPermCheckboxes(U32 mask_on, U32 mask_off, -// LLCheckBoxCtrl* move, LLCheckboxCtrl* edit, -// LLCheckBoxCtrl* copy); + protected: // statics static void onClickClaim(void*); static void onClickRelease(void*); static void onClickCreator(void*); static void onClickOwner(void*); - static void onClickGroup(void*); - static void cbGroupID(LLUUID group_id, void* userdata); + void onClickGroup(); + void cbGroupID(LLUUID group_id); static void onClickDeedToGroup(void*); static void onCommitPerm(LLUICtrl *ctrl, void *data, U8 field, U32 perm); @@ -101,10 +99,6 @@ protected: protected: LLNameBox* mLabelGroupName; // group name - //LLTextBox* mBuyerLabel; - //LLCheckBoxCtrl* mCheckBuyerModify; - //LLCheckBoxCtrl* mCheckBuyerCopy; - LLUUID mCreatorID; LLUUID mOwnerID; LLUUID mLastOwnerID; diff --git a/indra/newview/llpanelpick.cpp b/indra/newview/llpanelpick.cpp index 43ecd273c2..f7ca54c732 100644 --- a/indra/newview/llpanelpick.cpp +++ b/indra/newview/llpanelpick.cpp @@ -35,481 +35,447 @@ // profile. #include "llviewerprecompiledheaders.h" - -#include "llpanelpick.h" - -#include "lldir.h" -#include "llparcel.h" +#include "llpanel.h" #include "message.h" - #include "llagent.h" #include "llbutton.h" -#include "llcheckboxctrl.h" -#include "llviewercontrol.h" -#include "lllineeditor.h" -#include "lltabcontainervertical.h" -#include "lltextbox.h" -#include "llviewertexteditor.h" +#include "llparcel.h" +#include "llviewerparcelmgr.h" #include "lltexturectrl.h" #include "lluiconstants.h" -#include "llviewergenericmessage.h" -#include "lluictrlfactory.h" -#include "llviewerparcelmgr.h" #include "llworldmap.h" #include "llfloaterworldmap.h" -#include "llviewerregion.h" -#include "llviewerwindow.h" +#include "llfloaterreg.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelpick.h" -//static -std::list LLPanelPick::sAllPanels; -LLPanelPick::LLPanelPick(BOOL top_pick) -: LLPanel(std::string("Top Picks Panel")), - mTopPick(top_pick), - mPickID(), - mCreatorID(), - mParcelID(), - mDataRequested(FALSE), - mDataReceived(FALSE), - mPosGlobal(), - mSnapshotCtrl(NULL), - mNameEditor(NULL), - mDescEditor(NULL), - mLocationEditor(NULL), - mTeleportBtn(NULL), - mMapBtn(NULL), - //mLandmarkBtn(NULL), - mSortOrderText(NULL), - mSortOrderEditor(NULL), - mEnabledCheck(NULL), - mSetBtn(NULL) +#define XML_PANEL_EDIT_PICK "panel_edit_pick.xml" +#define XML_PANEL_PICK_INFO "panel_pick_info.xml" + +#define XML_NAME "pick_name" +#define XML_DESC "pick_desc" +#define XML_SNAPSHOT "pick_snapshot" +#define XML_LOCATION "pick_location" + +#define XML_BTN_SAVE "save_changes_btn" + +#define SAVE_BTN_LABEL "[WHAT]" +#define LABEL_PICK = "Pick" +#define LABEL_CHANGES = "Changes" + + +LLPanelPick::LLPanelPick(BOOL edit_mode/* = FALSE */) +: LLPanel(), LLAvatarPropertiesObserver(), LLRemoteParcelInfoObserver(), + mEditMode(edit_mode), + mSnapshotCtrl(NULL), + mPickId(LLUUID::null), + mCreatorId(LLUUID::null), + mDataReceived(FALSE) { - sAllPanels.push_back(this); - - std::string pick_def_file; - if (top_pick) + if (edit_mode) { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_top_pick.xml"); + LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_EDIT_PICK); + LLAvatarPropertiesProcessor::instance().addObserver(gAgentID, this); } else { - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_avatar_pick.xml"); - } -} + LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_PICK_INFO); + } +} LLPanelPick::~LLPanelPick() { - sAllPanels.remove(this); + if (mCreatorId.notNull()) LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorId, this); } - void LLPanelPick::reset() { - mPickID.setNull(); - mCreatorID.setNull(); - mParcelID.setNull(); + setEditMode(FALSE); + + mPickId.setNull(); + mCreatorId.setNull(); + mParcelId.setNull(); + + setPickName(""); + setPickDesc(""); + setPickLocation(""); + mSnapshotCtrl->setImageAssetID(LLUUID::null); + + //*HACK just setting asset id to NULL not enough to clear + //the texture controls, w/o setValid(FALSE) it continues to + //draw the previously set image + mSnapshotCtrl->setValid(FALSE); - // Don't request data, this isn't valid - mDataRequested = TRUE; mDataReceived = FALSE; mPosGlobal.clearVec(); - clearCtrls(); + childSetValue("maturity", ""); } - BOOL LLPanelPick::postBuild() { - mSnapshotCtrl = getChild("snapshot_ctrl"); - mSnapshotCtrl->setCommitCallback(onCommitAny); - mSnapshotCtrl->setCallbackUserData(this); + mSnapshotCtrl = getChild(XML_SNAPSHOT); - mNameEditor = getChild("given_name_editor"); - mNameEditor->setCommitOnFocusLost(TRUE); - mNameEditor->setCommitCallback(onCommitAny); - mNameEditor->setCallbackUserData(this); + if (mEditMode) + { + childSetAction("cancel_btn", boost::bind(&LLPanelPick::onClickCancel, this)); + childSetAction("set_to_curr_location_btn", boost::bind(&LLPanelPick::onClickSet, this)); + childSetAction(XML_BTN_SAVE, boost::bind(&LLPanelPick::onClickSave, this)); - mDescEditor = getChild("desc_editor"); - mDescEditor->setCommitOnFocusLost(TRUE); - mDescEditor->setCommitCallback(onCommitAny); - mDescEditor->setCallbackUserData(this); - mDescEditor->setTabsToNextField(TRUE); + mSnapshotCtrl->setMouseEnterCallback(boost::bind(&LLPanelPick::childSetVisible, this, "edit_icon", true)); + mSnapshotCtrl->setMouseLeaveCallback(boost::bind(&LLPanelPick::childSetVisible, this, "edit_icon", false)); + } + else + { + childSetAction("edit_btn", boost::bind(&LLPanelPick::onClickEdit, this)); + childSetAction("teleport_btn", boost::bind(&LLPanelPick::onClickTeleport, this)); + childSetAction("show_on_map_btn", boost::bind(&LLPanelPick::onClickMap, this)); - mLocationEditor = getChild("location_editor"); + if (!mBackCb.empty()) + { + LLButton* button = findChild("back_btn"); + if (button) button->setClickedCallback(mBackCb); + } + } - mSetBtn = getChild( "set_location_btn"); - mSetBtn->setClickedCallback(onClickSet); - mSetBtn->setCallbackUserData(this); - - mTeleportBtn = getChild( "pick_teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); - - mMapBtn = getChild( "pick_map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); - - mSortOrderText = getChild("sort_order_text"); - - mSortOrderEditor = getChild("sort_order_editor"); - mSortOrderEditor->setPrevalidate(LLLineEditor::prevalidateInt); - mSortOrderEditor->setCommitOnFocusLost(TRUE); - mSortOrderEditor->setCommitCallback(onCommitAny); - mSortOrderEditor->setCallbackUserData(this); - - mEnabledCheck = getChild( "enabled_check"); - mEnabledCheck->setCommitCallback(onCommitAny); - mEnabledCheck->setCallbackUserData(this); - - return TRUE; + return TRUE; } +void LLPanelPick::init(LLUUID creator_id, LLUUID pick_id) +{ + mCreatorId = creator_id; + mPickId = pick_id; + + //*TODO consider removing this, already called by setEditMode() + updateButtons(); + + requestData(); +} + +void LLPanelPick::requestData() +{ + mDataReceived = FALSE; + LLAvatarPropertiesProcessor::instance().addObserver(mCreatorId, this); + LLAvatarPropertiesProcessor::instance().sendDataRequest(mCreatorId, APT_PICK_INFO, &mPickId); +} + +void LLPanelPick::init(LLPickData *pick_data) +{ + mPickId = pick_data->pick_id; + mCreatorId = pick_data->creator_id; + + setPickName(pick_data->name); + setPickDesc(pick_data->desc); + setPickLocation(pick_data->location_text); + mSnapshotCtrl->setImageAssetID(pick_data->snapshot_id); + + //*HACK see reset() where the texture control was set to FALSE + mSnapshotCtrl->setValid(TRUE); + + mPosGlobal = pick_data->pos_global; + mSimName = pick_data->sim_name; + mParcelId = pick_data->parcel_id; +} // Fill in some reasonable defaults for a new pick. -void LLPanelPick::initNewPick() +void LLPanelPick::createNewPick() { - mPickID.generate(); - - mCreatorID = gAgent.getID(); - + mPickId.generate(); + mCreatorId = gAgent.getID(); mPosGlobal = gAgent.getPositionGlobal(); // Try to fill in the current parcel LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (parcel) { - mNameEditor->setText(parcel->getName()); - mDescEditor->setText(parcel->getDesc()); + setPickName(parcel->getName()); + setPickDesc(parcel->getDesc()); mSnapshotCtrl->setImageAssetID(parcel->getSnapshotID()); } - // Commit to the database, since we've got "new" values. - sendPickInfoUpdate(); + sendUpdate(); + + childSetLabelArg(XML_BTN_SAVE, SAVE_BTN_LABEL, std::string("Pick")); } - -void LLPanelPick::setPickID(const LLUUID& pick_id, const LLUUID& creator_id) +/*virtual*/ void LLPanelPick::processProperties(void* data, EAvatarProcessorType type) { - mPickID = pick_id; - mCreatorID = creator_id; + if (APT_PICK_INFO != type) return; + if (!data) return; + + LLPickData* pick_data = static_cast(data); + if (!pick_data) return; + if (mPickId != pick_data->pick_id) return; + + init(pick_data); + mDataReceived = TRUE; + LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorId, this); + + if (!mEditMode) + { + LLRemoteParcelInfoProcessor::getInstance()->addObserver(pick_data->parcel_id, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(pick_data->parcel_id); + } } -// Schedules the panel to request data -// from the server next time it is drawn. -void LLPanelPick::markForServerRequest() +void LLPanelPick::setEditMode( BOOL edit_mode ) { - mDataRequested = FALSE; - mDataReceived = FALSE; + if (mEditMode == edit_mode) return; + mEditMode = edit_mode; + + // preserve data before killing controls + LLUUID snapshot_id = mSnapshotCtrl->getImageAssetID(); + LLRect old_rect = getRect(); + + deleteAllChildren(); + + if (edit_mode) + { + LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_EDIT_PICK); + } + else + { + LLUICtrlFactory::getInstance()->buildPanel(this, XML_PANEL_PICK_INFO); + } + + //*NOTE this code is from LLPanelMeProfile.togglePanel()... doubt this is a right way to do things + reshape(old_rect.getWidth(), old_rect.getHeight()); + old_rect.setLeftTopAndSize(0, old_rect.getHeight(), old_rect.getWidth(), old_rect.getHeight()); + setRect(old_rect); + + // time to restore data + setPickName(mName); + setPickDesc(mDesc); + setPickLocation(mLocation); + mSnapshotCtrl->setImageAssetID(snapshot_id); + + updateButtons(); } +void LLPanelPick::setPickName(std::string name) +{ + if (mEditMode) + { + childSetValue(XML_NAME, name); + } + else + { + childSetWrappedText(XML_NAME, name); + } + + //preserving non-wrapped text for info/edit modes switching + mName = name; +} + +void LLPanelPick::setPickDesc(std::string desc) +{ + if (mEditMode) + { + childSetValue(XML_DESC, desc); + } + else + { + childSetWrappedText(XML_DESC, desc); + } + + //preserving non-wrapped text for info/edit modes switching + mDesc = desc; +} + +void LLPanelPick::setPickLocation(std::string location) +{ + childSetWrappedText(XML_LOCATION, location); + + //preserving non-wrapped text for info/edit modes switching + mLocation = location; +} std::string LLPanelPick::getPickName() { - return mNameEditor->getText(); + return childGetValue(XML_NAME).asString(); } - -void LLPanelPick::sendPickInfoRequest() +std::string LLPanelPick::getPickDesc() { - // Must ask for a pick based on the creator id because - // the pick database is distributed to the inventory cluster. JC - std::vector strings; - strings.push_back( mCreatorID.asString() ); - strings.push_back( mPickID.asString() ); - send_generic_message("pickinforequest", strings); - - mDataRequested = TRUE; + return childGetValue(XML_DESC).asString(); } - -void LLPanelPick::sendPickInfoUpdate() +std::string LLPanelPick::getPickLocation() { + return childGetValue(XML_LOCATION).asString(); +} + +void LLPanelPick::sendUpdate() +{ + LLPickData pick_data; + // If we don't have a pick id yet, we'll need to generate one, // otherwise we'll keep overwriting pick_id 00000 in the database. - if (mPickID.isNull()) - { - mPickID.generate(); - } + if (mPickId.isNull()) mPickId.generate(); - LLMessageSystem* msg = gMessageSystem; + pick_data.agent_id = gAgent.getID(); + pick_data.session_id = gAgent.getSessionID(); + pick_data.pick_id = mPickId; + pick_data.creator_id = gAgentID; - msg->newMessage("PickInfoUpdate"); - msg->nextBlock("AgentData"); - msg->addUUID("AgentID", gAgent.getID()); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("PickID", mPickID); - msg->addUUID("CreatorID", mCreatorID); - msg->addBOOL("TopPick", mTopPick); - // fills in on simulator if null - msg->addUUID("ParcelID", mParcelID); - msg->addString("Name", mNameEditor->getText()); - msg->addString("Desc", mDescEditor->getText()); - msg->addUUID("SnapshotID", mSnapshotCtrl->getImageAssetID()); - msg->addVector3d("PosGlobal", mPosGlobal); - - // Only top picks have a sort order - S32 sort_order; - if (mTopPick) - { - sort_order = atoi(mSortOrderEditor->getText().c_str()); - } - else - { - sort_order = 0; - } - msg->addS32("SortOrder", sort_order); - msg->addBOOL("Enabled", mEnabledCheck->get()); - gAgent.sendReliableMessage(); + //legacy var need to be deleted + pick_data.top_pick = FALSE; + pick_data.parcel_id = mParcelId; + pick_data.name = getPickName(); + pick_data.desc = getPickDesc(); + pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + pick_data.pos_global = mPosGlobal; + pick_data.sort_order = 0; + pick_data.enabled = TRUE; + + mDataReceived = FALSE; + LLAvatarPropertiesProcessor::instance().addObserver(gAgentID, this); + + LLAvatarPropertiesProcessor::instance().sendDataUpdate(&pick_data, APT_PICK_INFO); } +//----------------------------------------- +// "PICK INFO" (VIEW MODE) BUTTON HANDLERS +//----------------------------------------- + //static -void LLPanelPick::processPickInfoReply(LLMessageSystem *msg, void **) +void LLPanelPick::onClickEdit() { - // Extract the agent id and verify the message is for this - // client. - LLUUID agent_id; - msg->getUUID("AgentData", "AgentID", agent_id ); - if (agent_id != gAgent.getID()) - { - llwarns << "Agent ID mismatch in processPickInfoReply" - << llendl; - return; - } - - LLUUID pick_id; - msg->getUUID("Data", "PickID", pick_id); - - LLUUID creator_id; - msg->getUUID("Data", "CreatorID", creator_id); - - BOOL top_pick; - msg->getBOOL("Data", "TopPick", top_pick); - - LLUUID parcel_id; - msg->getUUID("Data", "ParcelID", parcel_id); - - std::string name; - msg->getString("Data", "Name", name); - - std::string desc; - msg->getString("Data", "Desc", desc); - - LLUUID snapshot_id; - msg->getUUID("Data", "SnapshotID", snapshot_id); - - // "Location text" is actually the owner name, the original - // name that owner gave the parcel, and the location. - std::string location_text; - msg->getString("Data", "User", location_text); - location_text.append(", "); - - std::string original_name; - msg->getString("Data", "OriginalName", original_name); - if (!original_name.empty()) - { - location_text.append(original_name); - location_text.append(", "); - } - - std::string sim_name; - msg->getString("Data", "SimName", sim_name); - location_text.append(sim_name); - location_text.append(" "); - - LLVector3d pos_global; - msg->getVector3d("Data", "PosGlobal", pos_global); - - S32 region_x = llround((F32)pos_global.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)pos_global.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)pos_global.mdV[VZ]); - - location_text.append(llformat("(%d, %d, %d)", region_x, region_y, region_z)); - - S32 sort_order; - msg->getS32("Data", "SortOrder", sort_order); - - BOOL enabled; - msg->getBOOL("Data", "Enabled", enabled); - - // Look up the panel to fill in - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) - { - LLPanelPick* self = *iter; - // For top picks, must match pick id - if (self->mPickID != pick_id) - { - continue; - } - - self->mDataReceived = TRUE; - - // Found the panel, now fill in the information - self->mPickID = pick_id; - self->mCreatorID = creator_id; - self->mParcelID = parcel_id; - self->mSimName.assign(sim_name); - self->mPosGlobal = pos_global; - - // Update UI controls - self->mNameEditor->setText(std::string(name)); - self->mDescEditor->setText(std::string(desc)); - self->mSnapshotCtrl->setImageAssetID(snapshot_id); - self->mLocationEditor->setText(location_text); - self->mEnabledCheck->set(enabled); - - self->mSortOrderEditor->setText(llformat("%d", sort_order)); - } + if (mEditMode) return; + if (!mDataReceived) return; + setEditMode(TRUE); } -void LLPanelPick::draw() +//static +void LLPanelPick::onClickTeleport() { - refresh(); + teleport(mPosGlobal); +} - LLPanel::draw(); +//static +void LLPanelPick::onClickMap() +{ + showOnMap(mPosGlobal); } -void LLPanelPick::refresh() +//----------------------------------------- +// "EDIT PICK" (EDIT MODE) BUTTON HANDLERS +//----------------------------------------- + +//static +void LLPanelPick::onClickCancel() { - if (!mDataRequested) - { - sendPickInfoRequest(); - } - - // Check for god mode - BOOL godlike = gAgent.isGodlike(); - BOOL is_self = (gAgent.getID() == mCreatorID); - - // Set button visibility/enablement appropriately - if (mTopPick) - { - mSnapshotCtrl->setEnabled(godlike); - mNameEditor->setEnabled(godlike); - mDescEditor->setEnabled(godlike); - - mSortOrderText->setVisible(godlike); - - mSortOrderEditor->setVisible(godlike); - mSortOrderEditor->setEnabled(godlike); - - mEnabledCheck->setVisible(godlike); - mEnabledCheck->setEnabled(godlike); - - mSetBtn->setVisible(godlike); - mSetBtn->setEnabled(godlike); - } - else - { - mSnapshotCtrl->setEnabled(is_self); - mNameEditor->setEnabled(is_self); - mDescEditor->setEnabled(is_self); - - mSortOrderText->setVisible(FALSE); - - mSortOrderEditor->setVisible(FALSE); - mSortOrderEditor->setEnabled(FALSE); - - mEnabledCheck->setVisible(FALSE); - mEnabledCheck->setEnabled(FALSE); - - mSetBtn->setVisible(is_self); - mSetBtn->setEnabled(is_self); - } -} - - -// static -void LLPanelPick::onClickTeleport(void* data) -{ - LLPanelPick* self = (LLPanelPick*)data; - - if (!self->mPosGlobal.isExactlyZero()) - { - gAgent.teleportViaLocation(self->mPosGlobal); - gFloaterWorldMap->trackLocation(self->mPosGlobal); - } -} - - -// static -void LLPanelPick::onClickMap(void* data) -{ - LLPanelPick* self = (LLPanelPick*)data; - gFloaterWorldMap->trackLocation(self->mPosGlobal); - LLFloaterWorldMap::show(NULL, TRUE); + if (!mEditMode) return; + + LLUUID pick_id = mPickId; + LLUUID creator_id = mCreatorId; + reset(); + init(creator_id, pick_id); } // static -/* -void LLPanelPick::onClickLandmark(void* data) +void LLPanelPick::onClickSet() { - LLPanelPick* self = (LLPanelPick*)data; - create_landmark(self->mNameEditor->getText(), "", self->mPosGlobal); -} -*/ - -// static -void LLPanelPick::onClickSet(void* data) -{ - LLPanelPick* self = (LLPanelPick*)data; + if (!mEditMode) return; + if (!mDataReceived) return; // Save location for later. - self->mPosGlobal = gAgent.getPositionGlobal(); + mPosGlobal = gAgent.getPositionGlobal(); - std::string location_text; - location_text.assign("(will update after save)"); - location_text.append(", "); + S32 region_x = llround((F32)mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; + S32 region_y = llround((F32)mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; + S32 region_z = llround((F32)mPosGlobal.mdV[VZ]); - S32 region_x = llround((F32)self->mPosGlobal.mdV[VX]) % REGION_WIDTH_UNITS; - S32 region_y = llround((F32)self->mPosGlobal.mdV[VY]) % REGION_WIDTH_UNITS; - S32 region_z = llround((F32)self->mPosGlobal.mdV[VZ]); + std::string location_text = "(will update after save), "; + location_text.append(mSimName); + location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - location_text.append(self->mSimName); - location_text.append(llformat(" (%d, %d, %d)", region_x, region_y, region_z)); - - // if sim name in pick is different from current sim name - // make sure it's clear that all that's being changed - // is the location and nothing else - if ( gAgent.getRegion ()->getName () != self->mSimName ) - { - LLNotifications::instance().add("SetPickLocation"); - }; - - self->mLocationEditor->setText(location_text); - - onCommitAny(NULL, data); + setPickLocation(location_text); } - // static -void LLPanelPick::onCommitAny(LLUICtrl* ctrl, void* data) +void LLPanelPick::onClickSave() { - LLPanelPick* self = (LLPanelPick*)data; + if (!mEditMode) return; + if (!mDataReceived) return; - // have we received up to date data for this pick? - if (self->mDataReceived) + sendUpdate(); + setEditMode(FALSE); +} + +void LLPanelPick::updateButtons() +{ + + // on Pick Info panel (for non-Agent picks) edit_btn should be invisible + if (mEditMode) { - self->sendPickInfoUpdate(); - - // Big hack - assume that top picks are always in a browser, - // and non-top-picks are always in a tab container. - /*if (self->mTopPick) + childSetLabelArg(XML_BTN_SAVE, SAVE_BTN_LABEL, std::string("Changes")); + } + else + { + if (mCreatorId != gAgentID) { - LLPanelDirPicks* panel = (LLPanelDirPicks*)self->getParent(); - panel->renamePick(self->mPickID, self->mNameEditor->getText()); + childSetEnabled("edit_btn", FALSE); + childSetVisible("edit_btn", FALSE); } - else - {*/ - LLTabContainer* tab = (LLTabContainer*)self->getParent(); - if (tab) + else { - if(tab) tab->setCurrentTabName(self->mNameEditor->getText()); + childSetEnabled("edit_btn", TRUE); + childSetVisible("edit_btn", TRUE); } - //} } } + +void LLPanelPick::setExitCallback(commit_callback_t cb) +{ + mBackCb = cb; + if (!mEditMode) + { + LLButton* button = findChild("back_btn"); + if (button) button->setClickedCallback(mBackCb); + } +} + +//static +void LLPanelPick::teleport(const LLVector3d& position) +{ + if (!position.isExactlyZero()) + { + gAgent.teleportViaLocation(position); + LLFloaterWorldMap::getInstance()->trackLocation(position); + } +} + +//static +void LLPanelPick::showOnMap(const LLVector3d& position) +{ + LLFloaterWorldMap::getInstance()->trackLocation(position); + LLFloaterReg::showInstance("world_map", "center"); +} + +void LLPanelPick::processParcelInfo(const LLParcelData& parcel_data) +{ + if (mEditMode) return; + + // HACK: Flag 0x2 == adult region, + // Flag 0x1 == mature region, otherwise assume PG + std::string rating_icon = "icon_event.tga"; + if (parcel_data.flags & 0x2) + { + rating_icon = "icon_event_adult.tga"; + } + else if (parcel_data.flags & 0x1) + { + rating_icon = "icon_event_mature.tga"; + } + + childSetValue("maturity", rating_icon); + + //*NOTE we don't removeObserver(...) ourselves cause LLRemoveParcelProcessor does it for us +} diff --git a/indra/newview/llpanelpick.h b/indra/newview/llpanelpick.h index 450fa78801..2cd4706dfe 100644 --- a/indra/newview/llpanelpick.h +++ b/indra/newview/llpanelpick.h @@ -38,90 +38,101 @@ #define LL_LLPANELPICK_H #include "llpanel.h" -#include "v3dmath.h" -#include "lluuid.h" +#include "llremoteparcelrequest.h" -class LLButton; -class LLCheckBoxCtrl; -class LLIconCtrl; -class LLLineEditor; -class LLTextBox; -class LLTextEditor; class LLTextureCtrl; -class LLUICtrl; class LLMessageSystem; +class LLAvatarPropertiesObserver; -class LLPanelPick : public LLPanel +class LLPanelPick : public LLPanel, public LLAvatarPropertiesObserver, LLRemoteParcelInfoObserver { + LOG_CLASS(LLPanelPick); public: - LLPanelPick(BOOL top_pick); - /*virtual*/ ~LLPanelPick(); + LLPanelPick(BOOL edit_mode = FALSE); + /*virtual*/ ~LLPanelPick(); + // switches the panel to the VIEW mode and resets controls void reset(); - /*virtual*/ BOOL postBuild(); + /*virtual*/ BOOL postBuild(); - /*virtual*/ void draw(); - - /*virtual*/ void refresh(); - - // Setup a new pick, including creating an id, giving a sane + // Create a new pick, including creating an id, giving a sane // initial position, etc. - void initNewPick(); + void createNewPick(); - // We need to know the creator id so the database knows which partition - // to query for the pick data. - void setPickID(const LLUUID& pick_id, const LLUUID& creator_id); + //initializes the panel with data of the pick with id = pick_id + //owned by the avatar with id = creator_id + void init(LLUUID creator_id, LLUUID pick_id); - // Schedules the panel to request data - // from the server next time it is drawn. - void markForServerRequest(); + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + // switches the panel to either View or Edit mode + void setEditMode(BOOL edit_mode); + + // because this panel works in two modes (edit/view) we are + // free from managing two panel for editing and viewing picks and so + // are free from controlling switching between them in the parent panel (e.g. Me Profile) + // but that causes such a complication that we cannot set a callback for a "Back" button + // from the parent panel only once, so we have to preserve that callback + // in the pick panel and set it for the back button everytime postBuild() is called. + void setExitCallback(commit_callback_t cb); + + static void teleport(const LLVector3d& position); + static void showOnMap(const LLVector3d& position); + + //This stuff we got from LLRemoteParcelObserver, in the last two we intentionally do nothing + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); + /*virtual*/ void setParcelID(const LLUUID& parcel_id) {}; + /*virtual*/ void setErrorStatus(U32 status, const std::string& reason) {}; + +protected: + + void setPickName(std::string name); + void setPickDesc(std::string desc); + void setPickLocation(std::string location); std::string getPickName(); - const LLUUID& getPickID() const { return mPickID; } - const LLUUID& getPickCreatorID() const { return mCreatorID; } + std::string getPickDesc(); + std::string getPickLocation(); - void sendPickInfoRequest(); - void sendPickInfoUpdate(); + void sendUpdate(); + void requestData(); - static void processPickInfoReply(LLMessageSystem* msg, void**); + void init(LLPickData *pick_data); + + void updateButtons(); + + //----------------------------------------- + // "PICK INFO" (VIEW MODE) BUTTON HANDLERS + //----------------------------------------- + void onClickEdit(); + void onClickTeleport(); + void onClickMap(); + + //----------------------------------------- + // "EDIT PICK" (EDIT MODE) BUTTON HANDLERS + //----------------------------------------- + void onClickSet(); + void onClickSave(); + void onClickCancel(); protected: - static void onClickTeleport(void* data); - static void onClickMap(void* data); - //static void onClickLandmark(void* data); - static void onClickSet(void* data); - - static void onCommitAny(LLUICtrl* ctrl, void* data); - -protected: - BOOL mTopPick; - LLUUID mPickID; - LLUUID mCreatorID; - LLUUID mParcelID; - - // Data will be requested on first draw - BOOL mDataRequested; + BOOL mEditMode; + LLTextureCtrl* mSnapshotCtrl; BOOL mDataReceived; + LLUUID mPickId; + LLUUID mCreatorId; + LLVector3d mPosGlobal; + LLUUID mParcelId; std::string mSimName; - LLVector3d mPosGlobal; - LLTextureCtrl* mSnapshotCtrl; - LLLineEditor* mNameEditor; - LLTextEditor* mDescEditor; - LLLineEditor* mLocationEditor; + //These strings are used to keep non-wrapped text + std::string mName; + std::string mDesc; + std::string mLocation; - LLButton* mTeleportBtn; - LLButton* mMapBtn; - - LLTextBox* mSortOrderText; - LLLineEditor* mSortOrderEditor; - LLCheckBoxCtrl* mEnabledCheck; - LLButton* mSetBtn; - - typedef std::list panel_list_t; - static panel_list_t sAllPanels; + commit_callback_t mBackCb; }; #endif // LL_LLPANELPICK_H diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp new file mode 100644 index 0000000000..973afae73b --- /dev/null +++ b/indra/newview/llpanelpicks.cpp @@ -0,0 +1,603 @@ +/** + * @file llpanelpicks.cpp + * @brief LLPanelPicks and related class implementations + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llagent.h" +#include "llavatarconstants.h" +#include "lltexturectrl.h" +#include "llviewergenericmessage.h" // send_generic_message +#include "llmenugl.h" +#include "llviewermenu.h" +#include "llregistry.h" + +#include "llpanelpicks.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelavatar.h" +#include "llpanelprofile.h" +#include "llpanelpick.h" +#include "llscrollcontainer.h" + +static const std::string XML_BTN_NEW = "new_btn"; +static const std::string XML_BTN_DELETE = "trash_btn"; +static const std::string XML_BTN_INFO = "info_btn"; +static const std::string XML_BTN_TELEPORT = "teleport_btn"; +static const std::string XML_BTN_SHOW_ON_MAP = "show_on_map_btn"; + +static const std::string XML_PICKS_LIST = "back_panel"; + +#define PICK_ITEMS_BETWEEN 5 + +static LLRegisterPanelClassWrapper t_panel_picks("panel_picks"); + +//----------------------------------------------------------------------------- +// LLPanelPicks +//----------------------------------------------------------------------------- +LLPanelPicks::LLPanelPicks() +: LLPanelProfileTab(), + mPopupMenu(NULL), + mSelectedPickItem(NULL), + mProfilePanel(NULL), + mPickPanel(NULL) +{ +} + +LLPanelPicks::~LLPanelPicks() +{ + if(getAvatarId().notNull()) + { + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + } +} + +void* LLPanelPicks::create(void* data /* = NULL */) +{ + return new LLPanelPicks(); +} + +void LLPanelPicks::updateData() +{ + LLAvatarPropertiesProcessor::getInstance()->sendDataRequest(getAvatarId(),APT_PICKS); +} + +void LLPanelPicks::processProperties(void* data, EAvatarProcessorType type) +{ + if(APT_PICKS == type) + { + LLAvatarPicks* avatar_picks = static_cast(data); + if(avatar_picks && getAvatarId() == avatar_picks->target_id) + { + std::string name, second_name; + gCacheName->getName(getAvatarId(),name,second_name); + childSetTextArg("pick_title", "[NAME]",name); + + LLView* picks_list = getPicksList(); + + // to restore selection of the same item later + LLUUID pick_id_selected(LLUUID::null); + if (mSelectedPickItem) pick_id_selected = mSelectedPickItem->getPickId(); + + clear(); + + //*TODO move it somewhere else? + picks_list->setEnabled(FALSE); + childSetEnabled(XML_BTN_NEW, false); + childSetEnabled(XML_BTN_DELETE, false); + childSetEnabled(XML_BTN_INFO, false); + childSetEnabled(XML_BTN_TELEPORT,!avatar_picks->picks_list.empty()); + childSetEnabled(XML_BTN_SHOW_ON_MAP,!avatar_picks->picks_list.empty()); + + LLAvatarPicks::picks_list_t::const_iterator it = avatar_picks->picks_list.begin(); + for(; avatar_picks->picks_list.end() != it; ++it) + { + LLUUID pick_id = it->first; + std::string pick_name = it->second; + + LLPickItem* picture = LLPickItem::create(); + picture->childSetAction("info_chevron", boost::bind(&LLPanelPicks::onClickInfo, this)); + + picks_list->addChild(picture); + + picture->setPickName(pick_name); + picture->setPickId(pick_id); + picture->setCreatorId(getAvatarId()); + + LLAvatarPropertiesProcessor::instance().addObserver(getAvatarId(), picture); + picture->update(); + mPickItemList.push_back(picture); + if (pick_id_selected != LLUUID::null && + pick_id == pick_id_selected) setSelectedPickItem(picture); + } + + reshapePicksList(); + LLAvatarPropertiesProcessor::getInstance()->removeObserver(getAvatarId(),this); + + updateButtons(); + if (!mSelectedPickItem && mPickItemList.size()) setSelectedPickItem(mPickItemList.back()); + picks_list->setEnabled(TRUE); + + } + } +} + +void LLPanelPicks::clear() +{ + LLView* scroll = getPicksList(); + picture_list_t::const_iterator it = mPickItemList.begin(); + for(; mPickItemList.end() != it; ++it) + { + scroll->removeChild(*it); + delete *it; + } + mPickItemList.clear(); + mSelectedPickItem = NULL; +} + + +LLPickItem* LLPanelPicks::getSelectedPickItem() +{ + return mSelectedPickItem; +} + + +void LLPanelPicks::removePickItem( LLPickItem* pick_item ) +{ + LLView* scroll = getPicksList(); + scroll->removeChild(pick_item); + mPickItemList.remove(pick_item); + if (mPickItemList.size() == 0) + { + mSelectedPickItem = NULL; + } + else + { + setSelectedPickItem(mPickItemList.back()); + } + + reshapePicksList(); +} + +void LLPanelPicks::reshapePicksList() +{ + if (!mPickItemList.size()) return; + LLView* pickList = getPicksList(); + + //We don't need to update size of the 'pick list' before reshaping pick items. Don't need to reshape the pick list + S32 height = mPickItemList.size() * (mPickItemList.front()->getRect().getHeight() + PICK_ITEMS_BETWEEN); + LLRect rc = pickList->getRect(); + rc.setLeftTopAndSize(rc.mLeft, rc.mTop, rc.getWidth(), height); + pickList->setRect(rc); + + S32 last_bottom = pickList->getRect().getHeight(); + std::list::const_iterator pick_it, pick_first_it = mPickItemList.begin(); + for ( pick_it = pick_first_it; pick_it != mPickItemList.end(); ++pick_it) + { + LLView* const pick = *pick_it; + if(pick_it != pick_first_it) + { + last_bottom -= pick->getRect().getHeight(); + last_bottom -= PICK_ITEMS_BETWEEN; + } + reshapePickItem(pick, last_bottom,pickList->getRect().getWidth()); + } +} + +void LLPanelPicks::reshapePickItem(LLView* const pick_item, const S32 last_bottom, const S32 newWidth) +{ + LLRect rc = pick_item->getRect(); + rc.mBottom = last_bottom - rc.getHeight(); + rc.mTop = last_bottom; + pick_item->setRect(rc); + pick_item->reshape(newWidth, rc.getHeight()); +} + +LLView* LLPanelPicks::getPicksList() const +{ + return getChild(XML_PICKS_LIST); +} + +BOOL LLPanelPicks::postBuild() +{ + childSetAction(XML_BTN_DELETE, boost::bind(&LLPanelPicks::onClickDelete, this)); + + childSetAction("teleport_btn", boost::bind(&LLPanelPicks::onClickTeleport, this)); + childSetAction("show_on_map_btn", boost::bind(&LLPanelPicks::onClickMap, this)); + + childSetAction("info_btn", boost::bind(&LLPanelPicks::onClickInfo, this)); + childSetAction("new_btn", boost::bind(&LLPanelPicks::onClickNew, this)); + + CommitCallbackRegistry::ScopedRegistrar registar; + registar.add("Pick.Info", boost::bind(&LLPanelPicks::onClickInfo, this)); + registar.add("Pick.Edit", boost::bind(&LLPanelPicks::onClickMenuEdit, this)); + registar.add("Pick.Teleport", boost::bind(&LLPanelPicks::onClickTeleport, this)); + registar.add("Pick.Map", boost::bind(&LLPanelPicks::onClickMap, this)); + registar.add("Pick.Delete", boost::bind(&LLPanelPicks::onClickDelete, this)); + mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_picks.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + + return TRUE; +} + +void LLPanelPicks::onOpen(const LLSD& key) +{ + const LLUUID id(key.asUUID()); + BOOL self = (gAgent.getID() == id); + + // only agent can edit her picks + childSetEnabled("edit_panel", self); + childSetVisible("edit_panel", self); + + // Disable buttons when viewing profile for first time + if(getAvatarId() != id) + { + clear(); + + childSetEnabled(XML_BTN_INFO,FALSE); + childSetEnabled(XML_BTN_TELEPORT,FALSE); + childSetEnabled(XML_BTN_SHOW_ON_MAP,FALSE); + } + + // and see a special title - set as invisible by default in xml file + if (self) + { + childSetVisible("pick_title", !self); + childSetVisible("pick_title_agent", self); + } + + LLPanelProfileTab::onOpen(key); +} + +//static +void LLPanelPicks::onClickDelete() +{ + LLPickItem* pick_item = getSelectedPickItem(); + if (!pick_item) return; + + LLSD args; + args["PICK"] = pick_item->getPickName(); + LLNotifications::instance().add("DeleteAvatarPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackDelete, this, _1, _2)); +} + +bool LLPanelPicks::callbackDelete(const LLSD& notification, const LLSD& response) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + LLPickItem* pick_item = getSelectedPickItem(); + + if (0 == option) + { + LLAvatarPropertiesProcessor::instance().sendPickDelete(pick_item->getPickId()); + removePickItem(pick_item); + } + updateButtons(); + return false; +} + +bool LLPanelPicks::callbackTeleport( const LLSD& notification, const LLSD& response ) +{ + S32 option = LLNotification::getSelectedOption(notification, response); + + if (0 == option) + { + onClickTeleport(); + } + return false; +} + +//static +void LLPanelPicks::onClickTeleport() +{ + LLPickItem* pick_item = getSelectedPickItem(); + if (!pick_item) return; + LLPanelPick::teleport(pick_item->getPosGlobal()); +} + +//static +void LLPanelPicks::onClickMap() +{ + LLPickItem* pick_item = getSelectedPickItem(); + if (!pick_item) return; + LLPanelPick::showOnMap(pick_item->getPosGlobal()); +} + + +BOOL LLPanelPicks::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (isMouseInPick(x, y)) + { + if (mPopupMenu) + { + mPopupMenu->buildDrawLabels(); + mPopupMenu->updateParent(LLMenuGL::sMenuContainer); + ((LLContextMenu*)mPopupMenu)->show(x, y); + LLMenuGL::showPopup(this, mPopupMenu, x, y); + } + return TRUE; + } + return LLPanel::handleRightMouseDown(x, y, mask); +} + +BOOL LLPanelPicks::handleMouseDown( S32 x, S32 y, MASK mask ) +{ + isMouseInPick(x, y); + return LLPanel::handleMouseDown(x, y, mask); +} + +BOOL LLPanelPicks::handleDoubleClick(S32 x, S32 y, MASK mask) +{ + if (isMouseInPick(x, y)) + { + LLPickItem* pick_item = getSelectedPickItem(); + if (pick_item) + { + LLSD args; + args["PICK"] = pick_item->getPickName(); + LLNotifications::instance().add("TeleportToPick", args, LLSD(), boost::bind(&LLPanelPicks::callbackTeleport, this, _1, _2)); + } + return TRUE; + } + return LLPanel::handleDoubleClick(x, y, mask); +} + +void LLPanelPicks::updateButtons() +{ + int picks_num = mPickItemList.size(); + childSetEnabled(XML_BTN_INFO, picks_num > 0); + + if (getAvatarId() == gAgentID) + { + childSetEnabled(XML_BTN_NEW, picks_num < MAX_AVATAR_PICKS); + childSetEnabled(XML_BTN_DELETE, picks_num > 0); + + //*TODO move somewhere this calls + // we'd better set them up earlier when a panel was being constructed + mPopupMenu->setItemVisible("pick_delete", TRUE); + mPopupMenu->setItemVisible("pick_edit", TRUE); + mPopupMenu->setItemVisible("pick_separator", TRUE); + } + + //*TODO update buttons like Show on Map, Teleport etc. + +} + +void LLPanelPicks::setSelectedPickItem(LLPickItem* item) +{ + if (!item) return; + if (mSelectedPickItem == item) return; + if (mSelectedPickItem && mSelectedPickItem->isBackgroundVisible()) + { + mSelectedPickItem->setBackgroundVisible(FALSE); + } + item->setBackgroundVisible(TRUE); + mSelectedPickItem = item; +} + +BOOL LLPanelPicks::isMouseInPick( S32 x, S32 y ) +{ + S32 x_l = x; + S32 y_l = y; + + if(!getChild("profile_scroll")->getRect().pointInRect(x, y)) + { + return FALSE; + } + + picture_list_t::const_iterator it = mPickItemList.begin(); + for(; mPickItemList.end() != it; ++it) + { + localPointToOtherView(x, y, &x_l, &y_l, (*it)); + if ((*it)->pointInView(x_l, y_l)) + { + setSelectedPickItem(*it); + return TRUE; + } + } + return FALSE; +} + + +void LLPanelPicks::setProfilePanel(LLPanelProfile* profile_panel) +{ + mProfilePanel = profile_panel; +} + + +void LLPanelPicks::buildPickPanel() +{ + if (mPickPanel == NULL) + { + mPickPanel = new LLPanelPick(); + mPickPanel->setExitCallback(boost::bind(&LLPanelPicks::onClickBack, this)); + } +} + +void LLPanelPicks::onClickNew() +{ + buildPickPanel(); + mPickPanel->setEditMode(TRUE); + mPickPanel->createNewPick(); + getProfilePanel()->togglePanel(mPickPanel); +} + +void LLPanelPicks::onClickInfo() +{ + LLPickItem* pick = getSelectedPickItem(); + if (!pick) return; + + buildPickPanel(); + mPickPanel->reset(); + mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + getProfilePanel()->togglePanel(mPickPanel); +} + +void LLPanelPicks::onClickBack() +{ + getProfilePanel()->togglePanel(mPickPanel); +} + +void LLPanelPicks::onClickMenuEdit() +{ + //*TODO, refactor - most of that is similar to onClickInfo + LLPickItem* pick = getSelectedPickItem(); + if (!pick) return; + + buildPickPanel(); + mPickPanel->reset(); + mPickPanel->init(pick->getCreatorId(), pick->getPickId()); + mPickPanel->setEditMode(TRUE); + getProfilePanel()->togglePanel(mPickPanel); +} + +inline LLPanelProfile* LLPanelPicks::getProfilePanel() +{ + llassert_always(NULL != mProfilePanel); + return mProfilePanel; +} + +//----------------------------------------------------------------------------- +// LLPanelPicks +//----------------------------------------------------------------------------- +LLPickItem::LLPickItem() +: LLPanel() +, mPickID(LLUUID::null) +, mCreatorID(LLUUID::null) +, mParcelID(LLUUID::null) +, mSnapshotID(LLUUID::null) +, mNeedData(true) +{ + LLUICtrlFactory::getInstance()->buildPanel(this,"panel_pick_list_item.xml"); +} + +LLPickItem::~LLPickItem() +{ + if (mCreatorID.notNull()) + { + LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); + } + +} + +LLPickItem* LLPickItem::create() +{ + return new LLPickItem(); +} + +void LLPickItem::init(LLPickData* pick_data) +{ + setPickDesc(pick_data->desc); + setSnapshotId(pick_data->snapshot_id); + mPosGlobal = pick_data->pos_global; + mLocation = pick_data->location_text; + + LLTextureCtrl* picture = getChild("picture"); + picture->setImageAssetID(pick_data->snapshot_id); +} + +void LLPickItem::setPickName(const std::string& name) +{ + mPickName = name; + childSetValue("picture_name",name); + +} + +const std::string& LLPickItem::getPickName() +{ + return mPickName; +} + +const LLUUID& LLPickItem::getCreatorId() +{ + return mCreatorID; +} + +const LLUUID& LLPickItem::getSnapshotId() +{ + return mSnapshotID; +} + +void LLPickItem::setPickDesc(const std::string& descr) +{ + childSetValue("picture_descr",descr); +} + +void LLPickItem::setPickId(const LLUUID& id) +{ + mPickID = id; +} + +const LLUUID& LLPickItem::getPickId() +{ + return mPickID; +} + +const LLVector3d& LLPickItem::getPosGlobal() +{ + return mPosGlobal; +} + +const std::string& LLPickItem::getLocation() +{ + return mLocation; +} + +const std::string LLPickItem::getDescription() +{ + return childGetValue("picture_descr").asString(); +} + +void LLPickItem::update() +{ + mNeedData = true; + LLAvatarPropertiesProcessor::instance().sendDataRequest(mCreatorID, APT_PICK_INFO, &mPickID); + mNeedData = false; +} + +void LLPickItem::processProperties(void *data, EAvatarProcessorType type) +{ + if (APT_PICK_INFO != type) return; + if (!data) return; + + LLPickData* pick_data = static_cast(data); + if (!pick_data) return; + if (mPickID != pick_data->pick_id) return; + + init(pick_data); + LLAvatarPropertiesProcessor::instance().removeObserver(mCreatorID, this); +} + +void LLPanelPicks::onClose() +{ + // Toggle off Pick Info panel if it is visible. + if(mPickPanel && mPickPanel->getVisible()) + { + getProfilePanel()->togglePanel(mPickPanel); + } +} diff --git a/indra/newview/llpanelpicks.h b/indra/newview/llpanelpicks.h new file mode 100644 index 0000000000..da7bc32ab1 --- /dev/null +++ b/indra/newview/llpanelpicks.h @@ -0,0 +1,185 @@ +/** + * @file llpanelpicks.h + * @brief LLPanelPicks and related class definitions + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPICKS_H +#define LL_LLPANELPICKS_H + +#include "llpanel.h" +#include "v3dmath.h" +#include "lluuid.h" +#include "llavatarpropertiesprocessor.h" +#include "llpanelavatar.h" +#include "llregistry.h" + +class LLPanelProfile; +class LLMessageSystem; +class LLVector3d; +class LLPanelProfileTab; +class LLPanelPick; +class LLAgent; +class LLMenuGL; +class LLPickItem; + + +class LLPanelPicks + : public LLPanelProfileTab +{ +public: + LLPanelPicks(); + ~LLPanelPicks(); + + static void* create(void* data); + + /*virtual*/ BOOL postBuild(void); + + /*virtual*/ void onOpen(const LLSD& key); + + void processProperties(void* data, EAvatarProcessorType type); + + void updateData(); + + void clear(); + + // returns the selected pick item + LLPickItem* getSelectedPickItem(); + + // removes the specified pick item + void removePickItem(LLPickItem* pick_item); + + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + + //*NOTE top down approch when panel toggling is done only by + // parent panels failed to work (picks related code was in me profile panel) + void setProfilePanel(LLPanelProfile* profile_panel); + + /** + * Closes LLPanelPick if it is visible. + */ + /*virtual*/ void onClose(); + +private: + void onClickDelete(); + void onClickTeleport(); + void onClickMap(); + + //------------------------------------------------ + // Callbacks which require panel toggling + //------------------------------------------------ + void onClickNew(); + void onClickInfo(); + void onClickBack(); + void onClickMenuEdit(); + + void buildPickPanel(); + + bool callbackDelete(const LLSD& notification, const LLSD& response); + bool callbackTeleport(const LLSD& notification, const LLSD& response); + + void reshapePicksList(); + void reshapePickItem(LLView* const pick_item, const S32 last_bottom, const S32 newWidth); + LLView* getPicksList() const; + void updateButtons(); + + void setSelectedPickItem(LLPickItem* item); + + BOOL isMouseInPick(S32 x, S32 y); + + LLPanelProfile* getProfilePanel(); + + + typedef std::list picture_list_t; + picture_list_t mPickItemList; + + LLMenuGL* mPopupMenu; + LLPickItem* mSelectedPickItem; + LLPanelProfile* mProfilePanel; + LLPanelPick* mPickPanel; +}; + +class LLPickItem : public LLPanel, public LLAvatarPropertiesObserver +{ +public: + + LLPickItem(); + + static LLPickItem* create(); + + void init(LLPickData* pick_data); + + void setPickName(const std::string& name); + + void setPickDesc(const std::string& descr); + + void setPickId(const LLUUID& id); + + void setCreatorId(const LLUUID& id) {mCreatorID = id;}; + + void setSnapshotId(const LLUUID& id) {mSnapshotID = id;}; + + void setNeedData(bool need){mNeedData = need;}; + + const LLUUID& getPickId(); + + const std::string& getPickName(); + + const LLUUID& getCreatorId(); + + const LLUUID& getSnapshotId(); + + const LLVector3d& getPosGlobal(); + + const std::string& getLocation(); + + const std::string getDescription(); + + /*virtual*/ void processProperties(void* data, EAvatarProcessorType type); + + void update(); + + ~LLPickItem(); + +protected: + + LLUUID mPickID; + LLUUID mCreatorID; + LLUUID mParcelID; + LLUUID mSnapshotID; + LLVector3d mPosGlobal; + bool mNeedData; + + std::string mPickName; + std::string mLocation; +}; + +#endif // LL_LLPANELPICKS_H diff --git a/indra/newview/llpanelplace.cpp b/indra/newview/llpanelplace.cpp index 7ca3622634..c6840721a3 100644 --- a/indra/newview/llpanelplace.cpp +++ b/indra/newview/llpanelplace.cpp @@ -36,11 +36,10 @@ #include "llviewercontrol.h" #include "llqueryflags.h" -#include "message.h" #include "llui.h" #include "llsecondlifeurls.h" -#include "llremoteparcelrequest.h" #include "llfloater.h" +#include "llfloaterreg.h" #include "llagent.h" #include "llviewerwindow.h" @@ -49,20 +48,19 @@ #include "lllineeditor.h" #include "lluiconstants.h" #include "lltextbox.h" -#include "llviewertexteditor.h" +#include "lltexteditor.h" #include "lltexturectrl.h" +#include "lltrans.h" #include "llworldmap.h" #include "llviewerregion.h" +#include "llvoavatarself.h" #include "lluictrlfactory.h" //#include "llviewermenu.h" // create_landmark() #include "llweb.h" #include "llsdutil.h" -//static -std::list LLPanelPlace::sAllPanels; - LLPanelPlace::LLPanelPlace() -: LLPanel(std::string("Places Panel")), +: LLPanel(), mParcelID(), mRequestedID(), mRegionID(), @@ -70,17 +68,16 @@ LLPanelPlace::LLPanelPlace() mPosRegion(), mAuctionID(0), mLandmarkAssetID() -{ - sAllPanels.push_back(this); -} - +{} LLPanelPlace::~LLPanelPlace() { - sAllPanels.remove(this); + if (mParcelID.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelID, this); + } } - BOOL LLPanelPlace::postBuild() { // Since this is only used in the directory browser, always @@ -102,20 +99,16 @@ BOOL LLPanelPlace::postBuild() mLocationDisplay = getChild("location_editor"); mTeleportBtn = getChild( "teleport_btn"); - mTeleportBtn->setClickedCallback(onClickTeleport); - mTeleportBtn->setCallbackUserData(this); + mTeleportBtn->setClickedCallback(onClickTeleport, this); mMapBtn = getChild( "map_btn"); - mMapBtn->setClickedCallback(onClickMap); - mMapBtn->setCallbackUserData(this); + mMapBtn->setClickedCallback(onClickMap, this); //mLandmarkBtn = getChild( "landmark_btn"); - //mLandmarkBtn->setClickedCallback(onClickLandmark); - //mLandmarkBtn->setCallbackUserData(this); + //mLandmarkBtn->setClickedCallback(onClickLandmark, this); mAuctionBtn = getChild( "auction_btn"); - mAuctionBtn->setClickedCallback(onClickAuction); - mAuctionBtn->setCallbackUserData(this); + mAuctionBtn->setClickedCallback(onClickAuction, this); // Default to no auction button. We'll show it if we get an auction id mAuctionBtn->setVisible(FALSE); @@ -128,8 +121,11 @@ BOOL LLPanelPlace::postBuild() void LLPanelPlace::displayItemInfo(const LLInventoryItem* pItem) { - mNameEditor->setText(pItem->getName()); - mDescEditor->setText(pItem->getDescription()); + if (pItem) + { + mNameEditor->setText(pItem->getName()); + mDescEditor->setText(pItem->getDescription()); + } } // Use this for search directory clicks, because we are totally @@ -177,6 +173,7 @@ void LLPanelPlace::resetName(const std::string& name) } } +//virtual void LLPanelPlace::setParcelID(const LLUUID& parcel_id) { mParcelID = parcel_id; @@ -188,7 +185,6 @@ void LLPanelPlace::setSnapshot(const LLUUID& snapshot_id) mSnapshotCtrl->setImageAssetID(snapshot_id); } - void LLPanelPlace::setLocationString(const std::string& location) { mLocationDisplay->setText(location); @@ -201,27 +197,22 @@ void LLPanelPlace::setLandTypeString(const std::string& land_type) void LLPanelPlace::sendParcelInfoRequest() { - LLMessageSystem *msg = gMessageSystem; - if (mParcelID != mRequestedID) { - msg->newMessage("ParcelInfoRequest"); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); - msg->addUUID("SessionID", gAgent.getSessionID()); - msg->nextBlock("Data"); - msg->addUUID("ParcelID", mParcelID); - gAgent.sendReliableMessage(); + LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelID, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelID); + mRequestedID = mParcelID; } } +//virtual void LLPanelPlace::setErrorStatus(U32 status, const std::string& reason) { // We only really handle 404 and 499 errors std::string error_text; if(status == 404) - { + { error_text = getString("server_error_text"); } else if(status == 499) @@ -231,140 +222,91 @@ void LLPanelPlace::setErrorStatus(U32 status, const std::string& reason) mDescEditor->setText(error_text); } -//static -void LLPanelPlace::processParcelInfoReply(LLMessageSystem *msg, void **) +//virtual +void LLPanelPlace::processParcelInfo(const LLParcelData& parcel_data) { - LLUUID agent_id; - LLUUID parcel_id; - LLUUID owner_id; - std::string name; - std::string desc; - S32 actual_area; - S32 billable_area; - U8 flags; - F32 global_x; - F32 global_y; - F32 global_z; - std::string sim_name; - LLUUID snapshot_id; - F32 dwell; - S32 sale_price; - S32 auction_id; + mAuctionID = parcel_data.auction_id; - msg->getUUID("AgentData", "AgentID", agent_id ); - msg->getUUID("Data", "ParcelID", parcel_id); - - // look up all panels which have this avatar - for (panel_list_t::iterator iter = sAllPanels.begin(); iter != sAllPanels.end(); ++iter) + if(parcel_data.snapshot_id.notNull()) { - LLPanelPlace* self = *iter; - if (self->mParcelID != parcel_id) - { - continue; - } - - msg->getUUID ("Data", "OwnerID", owner_id); - msg->getString ("Data", "Name", name); - msg->getString ("Data", "Desc", desc); - msg->getS32 ("Data", "ActualArea", actual_area); - msg->getS32 ("Data", "BillableArea", billable_area); - msg->getU8 ("Data", "Flags", flags); - msg->getF32 ("Data", "GlobalX", global_x); - msg->getF32 ("Data", "GlobalY", global_y); - msg->getF32 ("Data", "GlobalZ", global_z); - msg->getString ("Data", "SimName", sim_name); - msg->getUUID ("Data", "SnapshotID", snapshot_id); - msg->getF32 ("Data", "Dwell", dwell); - msg->getS32 ("Data", "SalePrice", sale_price); - msg->getS32 ("Data", "AuctionID", auction_id); - - - self->mAuctionID = auction_id; - - if(snapshot_id.notNull()) - { - self->mSnapshotCtrl->setImageAssetID(snapshot_id); - } - - // Only assign the name and description if they are not empty and there is not a - // value present (passed in from a landmark, e.g.) - - if( !name.empty() - && self->mNameEditor && self->mNameEditor->getText().empty()) - { - self->mNameEditor->setText(name); - } - - if( !desc.empty() - && self->mDescEditor && self->mDescEditor->getText().empty()) - { - self->mDescEditor->setText(desc); - } - - std::string info_text; - LLUIString traffic = self->getString("traffic_text"); - traffic.setArg("[TRAFFIC]", llformat("%d ", (int)dwell)); - info_text = traffic; - LLUIString area = self->getString("area_text"); - area.setArg("[AREA]", llformat("%d", actual_area)); - info_text += area; - if (flags & DFQ_FOR_SALE) - { - LLUIString forsale = self->getString("forsale_text"); - forsale.setArg("[PRICE]", llformat("%d", sale_price)); - info_text += forsale; - } - if (auction_id != 0) - { - LLUIString auction = self->getString("auction_text"); - auction.setArg("[ID]", llformat("%010d ", auction_id)); - info_text += auction; - } - if (self->mInfoEditor) - { - self->mInfoEditor->setText(info_text); - } - - // HACK: Flag 0x2 == adult region, - // Flag 0x1 == mature region, otherwise assume PG - std::string rating = LLViewerRegion::accessToString(SIM_ACCESS_PG); - if (flags & 0x2) - { - rating = LLViewerRegion::accessToString(SIM_ACCESS_ADULT); - } - else if (flags & 0x1) - { - rating = LLViewerRegion::accessToString(SIM_ACCESS_MATURE); - } - - // Just use given region position for display - S32 region_x = llround(self->mPosRegion.mV[0]); - S32 region_y = llround(self->mPosRegion.mV[1]); - S32 region_z = llround(self->mPosRegion.mV[2]); - - // If the region position is zero, grab position from the global - if(self->mPosRegion.isExactlyZero()) - { - region_x = llround(global_x) % REGION_WIDTH_UNITS; - region_y = llround(global_y) % REGION_WIDTH_UNITS; - region_z = llround(global_z); - } - - if(self->mPosGlobal.isExactlyZero()) - { - self->mPosGlobal.setVec(global_x, global_y, global_z); - } - - std::string location = llformat("%s %d, %d, %d (%s)", - sim_name.c_str(), region_x, region_y, region_z, rating.c_str()); - if (self->mLocationDisplay) - { - self->mLocationDisplay->setText(location); - } - - BOOL show_auction = (auction_id > 0); - self->mAuctionBtn->setVisible(show_auction); + mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id); } + + if( !parcel_data.name.empty() + && mNameEditor && mNameEditor->getText().empty()) + { + mNameEditor->setText(parcel_data.name); + } + + if( !parcel_data.desc.empty() + && mDescEditor && mDescEditor->getText().empty()) + { + mDescEditor->setText(parcel_data.desc); + } + + std::string info_text; + LLUIString traffic = getString("traffic_text"); + traffic.setArg("[TRAFFIC]", llformat("%d ", (int)parcel_data.dwell)); + info_text = traffic; + LLUIString area = getString("area_text"); + area.setArg("[AREA]", llformat("%d", parcel_data.actual_area)); + info_text += area; + if (parcel_data.flags & DFQ_FOR_SALE) + { + LLUIString forsale = getString("forsale_text"); + forsale.setArg("[PRICE]", llformat("%d", parcel_data.sale_price)); + info_text += forsale; + } + if (parcel_data.auction_id != 0) + { + LLUIString auction = getString("auction_text"); + auction.setArg("[ID]", llformat("%010d ", parcel_data.auction_id)); + info_text += auction; + } + if (mInfoEditor) + { + mInfoEditor->setText(info_text); + } + + // HACK: Flag 0x2 == adult region, + // Flag 0x1 == mature region, otherwise assume PG + std::string rating = LLViewerRegion::accessToString(SIM_ACCESS_PG); + if (parcel_data.flags & 0x2) + { + rating = LLViewerRegion::accessToString(SIM_ACCESS_ADULT); + } + else if (parcel_data.flags & 0x1) + { + rating = LLViewerRegion::accessToString(SIM_ACCESS_MATURE); + } + + // Just use given region position for display + S32 region_x = llround(mPosRegion.mV[0]); + S32 region_y = llround(mPosRegion.mV[1]); + S32 region_z = llround(mPosRegion.mV[2]); + + // If the region position is zero, grab position from the global + if(mPosRegion.isExactlyZero()) + { + region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; + region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; + region_z = llround(parcel_data.global_z); + } + + if(mPosGlobal.isExactlyZero()) + { + mPosGlobal.setVec(parcel_data.global_x, parcel_data.global_y, parcel_data.global_z); + } + + std::string location = llformat("%s %d, %d, %d (%s)", + parcel_data.sim_name.c_str(), region_x, region_y, region_z, rating.c_str()); + if (mLocationDisplay) + { + mLocationDisplay->setText(location); + } + + BOOL show_auction = (parcel_data.auction_id > 0); + mAuctionBtn->setVisible(show_auction); } @@ -390,7 +332,7 @@ void LLPanelPlace::displayParcelInfo(const LLVector3& pos_region, U64 region_handle = to_region_handle(pos_global); body["region_handle"] = ll_sd_from_U64(region_handle); } - LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(this->getHandle())); + LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); } else { @@ -400,7 +342,6 @@ void LLPanelPlace::displayParcelInfo(const LLVector3& pos_region, mSnapshotCtrl->setFallbackImageName("default_land_picture.j2c"); } - // static void LLPanelPlace::onClickTeleport(void* data) { @@ -410,20 +351,21 @@ void LLPanelPlace::onClickTeleport(void* data) LLFloater* parent_floaterp = dynamic_cast(parent_viewp); if (parent_floaterp) { - parent_floaterp->close(); + parent_floaterp->closeFloater(); } // LLFloater* parent_floaterp = (LLFloater*)self->getParent(); parent_viewp->setVisible(false); - if(self->mLandmarkAssetID.notNull()) + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if(self->mLandmarkAssetID.notNull() && worldmap_instance) { gAgent.teleportViaLandmark(self->mLandmarkAssetID); - gFloaterWorldMap->trackLandmark(self->mLandmarkAssetID); + worldmap_instance->trackLandmark(self->mLandmarkAssetID); } - else if (!self->mPosGlobal.isExactlyZero()) + else if (!self->mPosGlobal.isExactlyZero() && worldmap_instance) { gAgent.teleportViaLocation(self->mPosGlobal); - gFloaterWorldMap->trackLocation(self->mPosGlobal); + worldmap_instance->trackLocation(self->mPosGlobal); } } @@ -431,10 +373,12 @@ void LLPanelPlace::onClickTeleport(void* data) void LLPanelPlace::onClickMap(void* data) { LLPanelPlace* self = (LLPanelPlace*)data; - if (!self->mPosGlobal.isExactlyZero()) + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + + if (!self->mPosGlobal.isExactlyZero() && worldmap_instance) { - gFloaterWorldMap->trackLocation(self->mPosGlobal); - LLFloaterWorldMap::show(NULL, TRUE); + worldmap_instance->trackLocation(self->mPosGlobal); + LLFloaterReg::showInstance("world_map", "center"); } } @@ -453,12 +397,12 @@ void LLPanelPlace::onClickLandmark(void* data) void LLPanelPlace::onClickAuction(void* data) { LLPanelPlace* self = (LLPanelPlace*)data; - LLSD payload; - payload["auction_id"] = self->mAuctionID; + LLSD args; + args["AUCTION_ID"] = self->mAuctionID; - LLNotifications::instance().add("GoToAuctionPage", LLSD(), payload, callbackAuctionWebPage); + LLNotifications::instance().add("GoToAuctionPage", args); } - +/* // static bool LLPanelPlace::callbackAuctionWebPage(const LLSD& notification, const LLSD& response) { @@ -466,8 +410,7 @@ bool LLPanelPlace::callbackAuctionWebPage(const LLSD& notification, const LLSD& if (0 == option) { std::string url; - S32 auction_id = notification["payload"]["auction_id"].asInteger(); - url = AUCTION_URL + llformat("%010d", auction_id ); + url = LLNotifications::instance().getGlobalString("AUCTION_URL") + llformat("%010d", response["auction_id"].asInteger()); llinfos << "Loading auction page " << url << llendl; @@ -475,3 +418,5 @@ bool LLPanelPlace::callbackAuctionWebPage(const LLSD& notification, const LLSD& } return false; } +*/ + diff --git a/indra/newview/llpanelplace.h b/indra/newview/llpanelplace.h index b11290493a..f90a1b0567 100644 --- a/indra/newview/llpanelplace.h +++ b/indra/newview/llpanelplace.h @@ -38,6 +38,8 @@ #include "v3dmath.h" #include "lluuid.h" +#include "llremoteparcelrequest.h" + class LLButton; class LLTextBox; class LLLineEditor; @@ -46,7 +48,7 @@ class LLTextureCtrl; class LLMessageSystem; class LLInventoryItem; -class LLPanelPlace : public LLPanel +class LLPanelPlace : public LLPanel, LLRemoteParcelInfoObserver { public: LLPanelPlace(); @@ -58,7 +60,7 @@ public: // Ignore all old location information, useful if you are // recycling an existing dialog and need to clear it. - void setParcelID(const LLUUID& parcel_id); + /*virtual*/ void setParcelID(const LLUUID& parcel_id); // Sends a request for data about the given parcel, which will // only update the location if there is none already available. @@ -67,7 +69,7 @@ public: void setSnapshot(const LLUUID& snapshot_id); void setLocationString(const std::string& location); void setLandTypeString(const std::string& land_type); - void setErrorStatus(U32 status, const std::string& reason); + /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); void resetName(const std::string& name); void sendParcelInfoRequest(); @@ -75,7 +77,7 @@ public: const LLUUID& landmark_asset_id, const LLUUID& region_id, const LLVector3d& pos_global); - static void processParcelInfoReply(LLMessageSystem* msg, void**); + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); LLTextureCtrl *getSnapshotCtrl() const { return mSnapshotCtrl; } @@ -113,9 +115,6 @@ protected: LLButton* mMapBtn; //LLButton* mLandmarkBtn; LLButton* mAuctionBtn; - - typedef std::list panel_list_t; - static panel_list_t sAllPanels; }; #endif // LL_LLPANELPLACE_H diff --git a/indra/newview/llpanelplaceinfo.cpp b/indra/newview/llpanelplaceinfo.cpp new file mode 100644 index 0000000000..a01977c9b5 --- /dev/null +++ b/indra/newview/llpanelplaceinfo.cpp @@ -0,0 +1,584 @@ +/** + * @file llpanelplaceinfo.cpp + * @brief Displays place information in Side Tray. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelplaceinfo.h" + +#include "roles_constants.h" +#include "llsdutil.h" +#include "llsecondlifeurls.h" + +#include "llinventory.h" +#include "llparcel.h" + +#include "llqueryflags.h" + +#include "llbutton.h" +#include "lllineeditor.h" +#include "llscrollcontainer.h" +#include "lltextbox.h" + +#include "llagent.h" +#include "llavatarpropertiesprocessor.h" +#include "llfloaterworldmap.h" +#include "llinventorymodel.h" +#include "lllandmarkactions.h" +#include "lltexturectrl.h" +#include "llviewerinventory.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llviewertexteditor.h" +#include "llworldmap.h" + +static LLRegisterPanelClassWrapper t_place_info("panel_place_info"); + +LLPanelPlaceInfo::LLPanelPlaceInfo() +: LLPanel(), + mParcelID(), + mRequestedID(), + mPosRegion(), + mLandmarkID(), + mMinHeight(0), + mScrollingPanel(NULL), + mInfoPanel(NULL), + mMediaPanel(NULL) +{} + +LLPanelPlaceInfo::~LLPanelPlaceInfo() +{ + if (mParcelID.notNull()) + { + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelID, this); + } +} + +BOOL LLPanelPlaceInfo::postBuild() +{ + mTitle = getChild("panel_title"); + mCurrentTitle = mTitle->getText(); + + // Since this is only used in the directory browser, always + // disable the snapshot control. Otherwise clicking on it will + // open a texture picker. + mSnapshotCtrl = getChild("logo"); + mSnapshotCtrl->setEnabled(FALSE); + + mRegionName = getChild("region_name"); + mParcelName = getChild("parcel_name"); + mDescEditor = getChild("description"); + mRating = getChild("maturity"); + + mRegionInfoDrillIn = getChild("region_info_drill_in"); + mMediaDrillIn = getChild("media_drill_in"); + mMediaDrillIn->setClickedCallback(boost::bind(&LLPanelPlaceInfo::toggleMediaPanel, this, TRUE)); + + mOwner = getChild("owner"); + mCreator = getChild("creator"); + mCreated = getChild("created"); + + mTitleEditor = getChild("title_editor"); + mTitleEditor->setCommitCallback(boost::bind(&LLPanelPlaceInfo::onCommitTitleOrNote, this, TITLE)); + + mNotesEditor = getChild("notes_editor"); + mNotesEditor->setCommitCallback(boost::bind(&LLPanelPlaceInfo::onCommitTitleOrNote, this, NOTE)); + mNotesEditor->setCommitOnFocusLost(true); + + LLScrollContainer* scroll_container = getChild("scroll_container"); + scroll_container->setBorderVisible(FALSE); + mMinHeight = scroll_container->getScrolledViewRect().getHeight(); + + mScrollingPanel = getChild("scrolling_panel"); + mInfoPanel = getChild("info_panel"); + mMediaPanel = getChild("media_panel"); + if (!mMediaPanel) + return FALSE; + + return TRUE; +} + +void LLPanelPlaceInfo::displayItemInfo(const LLInventoryItem* pItem) +{ + if (!pItem) + return; + + mLandmarkID = pItem->getUUID(); + + if(!gCacheName) + return; + + const LLPermissions& perm = pItem->getPermissions(); + + ////////////////// + // CREATOR NAME // + ////////////////// + if (pItem->getCreatorUUID().notNull()) + { + std::string name; + LLUUID creator_id = pItem->getCreatorUUID(); + if (!gCacheName->getFullName(creator_id, name)) + { + gCacheName->get(creator_id, FALSE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mCreator, _2, _3)); + } + mCreator->setText(name); + } + else + { + mCreator->setText(getString("unknown")); + } + + //////////////// + // OWNER NAME // + //////////////// + if(perm.isOwned()) + { + std::string name; + if (perm.isGroupOwned()) + { + LLUUID group_id = perm.getGroup(); + if (!gCacheName->getGroupName(group_id, name)) + { + gCacheName->get(group_id, TRUE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mOwner, _2, _3)); + } + } + else + { + LLUUID owner_id = perm.getOwner(); + if (!gCacheName->getFullName(owner_id, name)) + { + gCacheName->get(owner_id, FALSE, + boost::bind(&LLPanelPlaceInfo::nameUpdatedCallback, this, mOwner, _2, _3)); + } + } + mOwner->setText(name); + } + else + { + mOwner->setText(getString("public")); + } + + ////////////////// + // ACQUIRE DATE // + ////////////////// + time_t time_utc = pItem->getCreationDate(); + if (0 == time_utc) + { + mCreated->setText(getString("unknown")); + } + else + { + std::string timeStr = getString("acquired_date"); + LLSD substitution; + substitution["datetime"] = (S32) time_utc; + LLStringUtil::format (timeStr, substitution); + mCreated->setText(timeStr); + } + + mTitleEditor->setText(pItem->getName()); + mNotesEditor->setText(pItem->getDescription()); +} + +void LLPanelPlaceInfo::nameUpdatedCallback( + LLTextBox* text, + const std::string& first, + const std::string& last) +{ + text->setText(first + " " + last); +} + +void LLPanelPlaceInfo::resetLocation() +{ + mParcelID.setNull(); + mRequestedID.setNull(); + mLandmarkID.setNull(); + mPosRegion.clearVec(); + std::string not_available = getString("not_available"); + mRating->setValue(not_available); + mRegionName->setText(not_available); + mParcelName->setText(not_available); + mDescEditor->setText(not_available); + mCreator->setText(not_available); + mOwner->setText(not_available); + mCreated->setText(not_available); + mTitleEditor->setText(LLStringUtil::null); + mNotesEditor->setText(LLStringUtil::null); + mSnapshotCtrl->setImageAssetID(LLUUID::null); + mSnapshotCtrl->setFallbackImageName("default_land_picture.j2c"); +} + +//virtual +void LLPanelPlaceInfo::setParcelID(const LLUUID& parcel_id) +{ + mParcelID = parcel_id; + sendParcelInfoRequest(); +} + +void LLPanelPlaceInfo::setInfoType(INFO_TYPE type) +{ + LLPanel* landmark_info_panel = getChild("landmark_info_panel"); + LLPanel* landmark_edit_panel = getChild("landmark_edit_panel"); + + bool is_info_type_agent = type == AGENT; + bool is_info_type_landmark = type == LANDMARK; + + landmark_info_panel->setVisible(is_info_type_landmark); + landmark_edit_panel->setVisible(is_info_type_landmark || type == CREATE_LANDMARK); + + mRegionInfoDrillIn->setVisible(is_info_type_agent); + mMediaDrillIn->setVisible(is_info_type_agent); + + switch(type) + { + case CREATE_LANDMARK: + mCurrentTitle = getString("title_create_landmark"); + break; + + case AGENT: + case PLACE: + mCurrentTitle = getString("title_place"); + + if (!isMediaPanelVisible()) + { + mTitle->setText(mCurrentTitle); + } + break; + + // Hide Media Panel if showing information about + // a landmark or a teleport history item + case LANDMARK: + mCurrentTitle = getString("title_landmark"); + break; + + case TELEPORT_HISTORY: + mCurrentTitle = getString("title_place"); + break; + } + + if (type != PLACE) + toggleMediaPanel(FALSE); +} + +BOOL LLPanelPlaceInfo::isMediaPanelVisible() +{ + if (!mMediaPanel) + return FALSE; + + return mMediaPanel->getVisible(); +} + +void LLPanelPlaceInfo::toggleMediaPanel(BOOL visible) +{ + if (!mMediaPanel) + return; + + if (visible) + { + mTitle->setText(getString("title_media")); + } + else + { + mTitle->setText(mCurrentTitle); + } + + mInfoPanel->setVisible(!visible); + mMediaPanel->setVisible(visible); +} + +void LLPanelPlaceInfo::sendParcelInfoRequest() +{ + if (mParcelID != mRequestedID) + { + LLRemoteParcelInfoProcessor::getInstance()->addObserver(mParcelID, this); + LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(mParcelID); + + mRequestedID = mParcelID; + } +} + +// virtual +void LLPanelPlaceInfo::setErrorStatus(U32 status, const std::string& reason) +{ + // We only really handle 404 and 499 errors + std::string error_text; + if(status == 404) + { + error_text = getString("server_error_text"); + } + else if(status == 499) + { + error_text = getString("server_forbidden_text"); + } + mDescEditor->setText(error_text); +} + +// virtual +void LLPanelPlaceInfo::processParcelInfo(const LLParcelData& parcel_data) +{ + if(parcel_data.snapshot_id.notNull()) + { + mSnapshotCtrl->setImageAssetID(parcel_data.snapshot_id); + } + + if( !parcel_data.name.empty()) + { + mParcelName->setText(parcel_data.name); + } + + if( !parcel_data.desc.empty()) + { + mDescEditor->setText(parcel_data.desc); + } + + // HACK: Flag 0x2 == adult region, + // Flag 0x1 == mature region, otherwise assume PG + std::string rating = LLViewerRegion::accessToString(SIM_ACCESS_PG); + std::string rating_icon = "icon_event.tga"; + if (parcel_data.flags & 0x2) + { + rating = LLViewerRegion::accessToString(SIM_ACCESS_ADULT); + rating_icon = "icon_event_adult.tga"; + } + else if (parcel_data.flags & 0x1) + { + rating = LLViewerRegion::accessToString(SIM_ACCESS_MATURE); + rating_icon = "icon_event_mature.tga"; + } + mRating->setValue(rating_icon); + + //update for_sale banner, here we should use DFQ_FOR_SALE instead of PF_FOR_SALE + //because we deal with remote parcel response format + bool isForSale = (parcel_data.flags & DFQ_FOR_SALE)? TRUE : FALSE; + getChild("icon_for_sale")->setVisible(isForSale); + + // Just use given region position for display + S32 region_x = llround(mPosRegion.mV[0]); + S32 region_y = llround(mPosRegion.mV[1]); + S32 region_z = llround(mPosRegion.mV[2]); + + // If the region position is zero, grab position from the global + if(mPosRegion.isExactlyZero()) + { + region_x = llround(parcel_data.global_x) % REGION_WIDTH_UNITS; + region_y = llround(parcel_data.global_y) % REGION_WIDTH_UNITS; + region_z = llround(parcel_data.global_z); + } + + std::string name; + if (!parcel_data.sim_name.empty()) + { + name = llformat("%s (%d, %d, %d)", + parcel_data.sim_name.c_str(), region_x, region_y, region_z); + mRegionName->setText(name); + } + + if (mCurrentTitle != getString("title_landmark")) + { + mTitleEditor->setText(parcel_data.name); + mNotesEditor->setText(LLStringUtil::null); + } +} + +void LLPanelPlaceInfo::displayParcelInfo(const LLVector3& pos_region, + const LLUUID& region_id, + const LLVector3d& pos_global) +{ + mPosRegion = pos_region; + + LLViewerRegion* region = gAgent.getRegion(); + if (!region) + return; + + LLSD body; + std::string url = region->getCapability("RemoteParcelRequest"); + if (!url.empty()) + { + body["location"] = ll_sd_from_vector3(pos_region); + if (!region_id.isNull()) + { + body["region_id"] = region_id; + } + if (!pos_global.isExactlyZero()) + { + U64 region_handle = to_region_handle(pos_global); + body["region_handle"] = ll_sd_from_U64(region_handle); + } + LLHTTPClient::post(url, body, new LLRemoteParcelRequestResponder(getObserverHandle())); + } + else + { + mDescEditor->setText(getString("server_update_text")); + } +} + +void LLPanelPlaceInfo::displayAgentParcelInfo() +{ + mPosRegion = gAgent.getPositionAgent(); + + LLViewerRegion* region = gAgent.getRegion(); + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!region || !parcel) + return; + + LLParcelData parcel_data; + + // HACK: Converting sim access flags to the format + // returned by remote parcel response. + switch(region->getSimAccess()) + { + case SIM_ACCESS_MATURE: + parcel_data.flags = 0x1; + + case SIM_ACCESS_ADULT: + parcel_data.flags = 0x2; + + default: + parcel_data.flags = 0; + } + + // Adding "For Sale" flag in remote parcel response format. + if (parcel->getForSale()) + { + parcel_data.flags |= DFQ_FOR_SALE; + } + + parcel_data.desc = parcel->getDesc(); + parcel_data.name = parcel->getName(); + parcel_data.sim_name = gAgent.getRegion()->getName(); + parcel_data.snapshot_id = parcel->getSnapshotID(); + LLVector3d global_pos = gAgent.getPositionGlobal(); + parcel_data.global_x = global_pos.mdV[0]; + parcel_data.global_y = global_pos.mdV[1]; + parcel_data.global_z = global_pos.mdV[2]; + + + + processParcelInfo(parcel_data); +} + +void LLPanelPlaceInfo::onCommitTitleOrNote(LANDMARK_INFO_TYPE type) +{ + LLInventoryItem* item = gInventory.getItem(mLandmarkID); + if (!item) + return; + + std::string current_value; + std::string item_value; + if (type == TITLE) + { + if (mTitleEditor) + { + current_value = mTitleEditor->getText(); + item_value = item->getName(); + } + } + else + { + if (mNotesEditor) + { + current_value = mNotesEditor->getText(); + item_value = item->getDescription(); + } + } + + if (item_value != current_value && + gAgent.allowOperation(PERM_MODIFY, item->getPermissions(), GP_OBJECT_MANIPULATE)) + { + LLPointer new_item = new LLViewerInventoryItem(item); + + if (type == TITLE) + { + new_item->rename(current_value); + } + else + { + new_item->setDescription(current_value); + } + + new_item->updateServer(FALSE); + gInventory.updateItem(new_item); + gInventory.notifyObservers(); + } +} + +void LLPanelPlaceInfo::createLandmark(const LLUUID& folder_id) +{ + std::string name = mTitleEditor->getText(); + std::string desc = mNotesEditor->getText(); + + LLStringUtil::trim(name); + LLStringUtil::trim(desc); + + // If typed name is empty use the parcel name instead. + if (name.empty()) + { + name = mParcelName->getText(); + } + + LLStringUtil::replaceChar(desc, '\n', ' '); + // If no folder chosen use the "Landmarks" folder. + LLLandmarkActions::createLandmarkHere(name, desc, + folder_id.notNull() ? folder_id : gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK)); +} + +void LLPanelPlaceInfo::createPick(const LLVector3d& global_pos) +{ + LLPickData pick_data; + + pick_data.agent_id = gAgent.getID(); + pick_data.session_id = gAgent.getSessionID(); + pick_data.pick_id = LLUUID::generateNewID(); + pick_data.creator_id = gAgentID; + + //legacy var need to be deleted + pick_data.top_pick = FALSE; + pick_data.parcel_id = mParcelID; + pick_data.name = mParcelName->getText(); + pick_data.desc = mDescEditor->getText(); + pick_data.snapshot_id = mSnapshotCtrl->getImageAssetID(); + pick_data.pos_global = global_pos; + pick_data.sort_order = 0; + pick_data.enabled = TRUE; + + LLAvatarPropertiesProcessor::instance().sendDataUpdate(&pick_data, APT_PICK_INFO); +} + +void LLPanelPlaceInfo::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + if (mMinHeight > 0 && mScrollingPanel != NULL) + { + mScrollingPanel->reshape(mScrollingPanel->getRect().getWidth(), mMinHeight); + } + + LLView::reshape(width, height, called_from_parent); +} diff --git a/indra/newview/llpanelplaceinfo.h b/indra/newview/llpanelplaceinfo.h new file mode 100644 index 0000000000..77ce2c6619 --- /dev/null +++ b/indra/newview/llpanelplaceinfo.h @@ -0,0 +1,150 @@ +/** + * @file llpanelplaceinfo.h + * @brief Displays place information in Side Tray. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPLACEINFO_H +#define LL_LLPANELPLACEINFO_H + +#include "llpanel.h" + +#include "v3dmath.h" +#include "lluuid.h" + +#include "lliconctrl.h" + +#include "llpanelmedia.h" +#include "llremoteparcelrequest.h" + +class LLButton; +class LLInventoryItem; +class LLLineEditor; +class LLTextBox; +class LLTextEditor; +class LLTextureCtrl; + +class LLPanelPlaceInfo : public LLPanel, LLRemoteParcelInfoObserver +{ +public: + enum INFO_TYPE + { + AGENT, + CREATE_LANDMARK, + LANDMARK, + PLACE, + TELEPORT_HISTORY + }; + + LLPanelPlaceInfo(); + /*virtual*/ ~LLPanelPlaceInfo(); + + /*virtual*/ BOOL postBuild(); + + // Ignore all old location information, useful if you are + // recycling an existing dialog and need to clear it. + void resetLocation(); + + // Sends a request for data about the given parcel, which will + // only update the location if there is none already available. + /*virtual*/ void setParcelID(const LLUUID& parcel_id); + + // Depending on how the panel was triggered + // (from landmark or current location, or other) + // sets a corresponding title and contents. + void setInfoType(INFO_TYPE type); + + // Create a landmark for the current location + // in a folder specified by folder_id. + void createLandmark(const LLUUID& folder_id); + + // Create a pick for the location specified + // by global_pos. + void createPick(const LLVector3d& global_pos); + + BOOL isMediaPanelVisible(); + void toggleMediaPanel(BOOL visible); + void displayItemInfo(const LLInventoryItem* pItem); + /*virtual*/ void setErrorStatus(U32 status, const std::string& reason); + + void sendParcelInfoRequest(); + + // Displays information about a remote parcel. + // Sends a request to the server. + void displayParcelInfo(const LLVector3& pos_region, + const LLUUID& region_id, + const LLVector3d& pos_global); + + // Displays information about the parcel the agent is currently on + // without sending a request to the server. + void displayAgentParcelInfo(); + + void nameUpdatedCallback(LLTextBox* text, + const std::string& first, + const std::string& last); + + /*virtual*/ void processParcelInfo(const LLParcelData& parcel_data); + /*virtual*/ void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + +private: + enum LANDMARK_INFO_TYPE + { + TITLE, + NOTE + }; + + void onCommitTitleOrNote(LANDMARK_INFO_TYPE type); + + LLUUID mParcelID; + LLUUID mRequestedID; + LLUUID mLandmarkID; + LLVector3 mPosRegion; + std::string mCurrentTitle; + S32 mMinHeight; + + LLTextBox* mTitle; + LLTextureCtrl* mSnapshotCtrl; + LLTextBox* mRegionName; + LLTextBox* mParcelName; + LLTextEditor* mDescEditor; + LLIconCtrl* mRating; + LLButton* mRegionInfoDrillIn; + LLButton* mMediaDrillIn; + LLTextBox* mOwner; + LLTextBox* mCreator; + LLTextBox* mCreated; + LLLineEditor* mTitleEditor; + LLTextEditor* mNotesEditor; + LLTextBox* mLocationEditor; + LLPanel* mScrollingPanel; + LLPanel* mInfoPanel; + LLMediaPanel* mMediaPanel; +}; + +#endif // LL_LLPANELPLACEINFO_H diff --git a/indra/newview/llpanelplaces.cpp b/indra/newview/llpanelplaces.cpp new file mode 100644 index 0000000000..7cb9e61e72 --- /dev/null +++ b/indra/newview/llpanelplaces.cpp @@ -0,0 +1,827 @@ +/** + * @file llpanelplaces.cpp + * @brief Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llassettype.h" +#include "llwindow.h" + +#include "lllandmark.h" + +#include "llfloaterreg.h" +#include "llnotifications.h" +#include "llfiltereditor.h" +#include "lltabcontainer.h" +#include "lltrans.h" +#include "lluictrlfactory.h" + +#include "llagent.h" +#include "lllandmarkactions.h" +#include "lllandmarklist.h" +#include "llfloaterworldmap.h" +#include "llpanelplaces.h" +#include "llpanellandmarks.h" +#include "llpanelteleporthistory.h" +#include "llsidetray.h" +#include "lltoggleablemenu.h" +#include "llviewerinventory.h" +#include "llviewermenu.h" +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" + +static const S32 LANDMARK_FOLDERS_MENU_WIDTH = 250; +static const std::string AGENT_INFO_TYPE = "agent"; +static const std::string CREATE_LANDMARK_INFO_TYPE = "create_landmark"; +static const std::string LANDMARK_INFO_TYPE = "landmark"; +static const std::string REMOTE_PLACE_INFO_TYPE = "remote_place"; +static const std::string TELEPORT_HISTORY_INFO_TYPE = "teleport_history"; + +// Helper functions +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right); +static std::string getFullFolderName(const LLViewerInventoryCategory* cat); +static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats); +static const LLVector3 get_pos_local_from_global(const LLVector3d &pos_global); +static void onSLURLBuilt(std::string& slurl); + +static LLRegisterPanelClassWrapper t_places("panel_places"); + +LLPanelPlaces::LLPanelPlaces() + : LLPanel(), + mFilterSubString(LLStringUtil::null), + mActivePanel(NULL), + mFilterEditor(NULL), + mPlaceInfo(NULL), + mItem(NULL), + mPlaceMenu(NULL), + mLandmarkMenu(NULL), + mLandmarkFoldersMenuHandle(), + mPosGlobal() +{ + gInventory.addObserver(this); + + LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback( + boost::bind(&LLPanelPlaces::onAgentParcelChange, this)); + + //LLUICtrlFactory::getInstance()->buildPanel(this, "panel_places.xml"); // Called from LLRegisterPanelClass::defaultPanelClassBuilder() +} + +LLPanelPlaces::~LLPanelPlaces() +{ + if (gInventory.containsObserver(this)) + gInventory.removeObserver(this); + + LLView::deleteViewByHandle(mLandmarkFoldersMenuHandle); +} + +BOOL LLPanelPlaces::postBuild() +{ + mCreateLandmarkBtn = getChild("create_landmark_btn"); + mCreateLandmarkBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onCreateLandmarkButtonClicked, this, LLUUID())); + + mFolderMenuBtn = getChild("folder_menu_btn"); + mFolderMenuBtn->setClickedCallback(boost::bind(&LLPanelPlaces::showLandmarkFoldersMenu, this)); + + mTeleportBtn = getChild("teleport_btn"); + mTeleportBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onTeleportButtonClicked, this)); + + mShowOnMapBtn = getChild("map_btn"); + mShowOnMapBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShowOnMapButtonClicked, this)); + + mShareBtn = getChild("share_btn"); + //mShareBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onShareButtonClicked, this)); + + mOverflowBtn = getChild("overflow_btn"); + + // *TODO: Assign the action to an appropriate event. + //mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::toggleMediaPanel, this)); + mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::onOverflowButtonClicked, this)); + + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + registrar.add("Places.OverflowMenu.Action", boost::bind(&LLPanelPlaces::onOverflowMenuItemClicked, this, _2)); + + mPlaceMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_place.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!mPlaceMenu) + { + llwarns << "Error loading Place menu" << llendl; + } + + mLandmarkMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_landmark.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + if (!mLandmarkMenu) + { + llwarns << "Error loading Landmark menu" << llendl; + } + + mTabContainer = getChild("Places Tabs"); + if (mTabContainer) + { + mTabContainer->setCommitCallback(boost::bind(&LLPanelPlaces::onTabSelected, this)); + } + + mFilterEditor = getChild("Filter"); + if (mFilterEditor) + { + mFilterEditor->setCommitCallback(boost::bind(&LLPanelPlaces::onFilterEdit, this, _2)); + } + + mPlaceInfo = getChild("panel_place_info"); + + LLButton* back_btn = mPlaceInfo->getChild("back_btn"); + back_btn->setClickedCallback(boost::bind(&LLPanelPlaces::onBackButtonClicked, this)); + + // *TODO: Assign the action to an appropriate event. + mOverflowBtn->setClickedCallback(boost::bind(&LLPanelPlaces::toggleMediaPanel, this)); + + return TRUE; +} + +void LLPanelPlaces::onOpen(const LLSD& key) +{ + mFilterEditor->clear(); + onFilterEdit(""); + + if(mPlaceInfo == NULL || key.size() == 0) + return; + + mPlaceInfoType = key["type"].asString(); + mPosGlobal.setZero(); + togglePlaceInfoPanel(TRUE); + updateVerbs(); + + if (mPlaceInfoType == AGENT_INFO_TYPE) + { + mPlaceInfo->setInfoType(LLPanelPlaceInfo::AGENT); + mPlaceInfo->displayAgentParcelInfo(); + + mPosGlobal = gAgent.getPositionGlobal(); + } + else if (mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) + { + mPlaceInfo->setInfoType(LLPanelPlaceInfo::CREATE_LANDMARK); + mPlaceInfo->displayAgentParcelInfo(); + + mPosGlobal = gAgent.getPositionGlobal(); + } + else if (mPlaceInfoType == LANDMARK_INFO_TYPE) + { + LLUUID item_uuid = key["id"].asUUID(); + LLInventoryItem* item = gInventory.getItem(item_uuid); + if (!item) + return; + + setItem(item); + } + else if (mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) + { + if (mPlaceInfo->isMediaPanelVisible()) + { + toggleMediaPanel(); + } + + mPosGlobal = LLVector3d(key["x"].asReal(), + key["y"].asReal(), + key["z"].asReal()); + + mPlaceInfo->setInfoType(LLPanelPlaceInfo::PLACE); + mPlaceInfo->displayParcelInfo(get_pos_local_from_global(mPosGlobal), + LLUUID(), + mPosGlobal); + } + else if (mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + { + S32 index = key["id"].asInteger(); + + const LLTeleportHistory::slurl_list_t& hist_items = + LLTeleportHistory::getInstance()->getItems(); + + mPosGlobal = hist_items[index].mGlobalPos; + + mPlaceInfo->setInfoType(LLPanelPlaceInfo::TELEPORT_HISTORY); + mPlaceInfo->displayParcelInfo(get_pos_local_from_global(mPosGlobal), + hist_items[index].mRegionID, + mPosGlobal); + } + + +} + +void LLPanelPlaces::setItem(LLInventoryItem* item) +{ + if (!mPlaceInfo) + return; + + mItem = item; + + // If the item is a link get a linked item + if (mItem->getType() == LLAssetType::AT_LINK) + { + mItem = gInventory.getItem(mItem->getAssetUUID()); + if (mItem.isNull()) + return; + } + + mPlaceInfo->setInfoType(LLPanelPlaceInfo::LANDMARK); + mPlaceInfo->displayItemInfo(mItem); + + LLLandmark* lm = gLandmarkList.getAsset(mItem->getAssetUUID(), + boost::bind(&LLPanelPlaces::onLandmarkLoaded, this, _1)); + if (lm) + { + onLandmarkLoaded(lm); + } +} + +void LLPanelPlaces::onLandmarkLoaded(LLLandmark* landmark) +{ + if (!mPlaceInfo) + return; + + LLUUID region_id; + landmark->getRegionID(region_id); + landmark->getGlobalPos(mPosGlobal); + mPlaceInfo->displayParcelInfo(landmark->getRegionPos(), + region_id, + mPosGlobal); +} + +void LLPanelPlaces::onFilterEdit(const std::string& search_string) +{ + if (mFilterSubString != search_string) + { + mFilterSubString = search_string; + + // Searches are case-insensitive + LLStringUtil::toUpper(mFilterSubString); + LLStringUtil::trimHead(mFilterSubString); + + mActivePanel->onSearchEdit(mFilterSubString); + } +} + +void LLPanelPlaces::onTabSelected() +{ + mActivePanel = dynamic_cast(mTabContainer->getCurrentPanel()); + if (!mActivePanel) + return; + + onFilterEdit(mFilterSubString); + mActivePanel->updateVerbs(); +} + +/* +void LLPanelPlaces::onShareButtonClicked() +{ + // TODO: Launch the "Things" Share wizard +} +*/ + +void LLPanelPlaces::onTeleportButtonClicked() +{ + if (!mPlaceInfo) + return; + + if (mPlaceInfo->getVisible()) + { + if (mPlaceInfoType == LANDMARK_INFO_TYPE) + { + LLSD payload; + payload["asset_id"] = mItem->getAssetUUID(); + LLNotifications::instance().add("TeleportFromLandmark", LLSD(), payload); + } + else if (mPlaceInfoType == AGENT_INFO_TYPE || + mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || + mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + { + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if (!mPosGlobal.isExactlyZero() && worldmap_instance) + { + gAgent.teleportViaLocation(mPosGlobal); + worldmap_instance->trackLocation(mPosGlobal); + } + } + } + else + { + mActivePanel->onTeleport(); + } +} + +void LLPanelPlaces::onShowOnMapButtonClicked() +{ + if (!mPlaceInfo) + return; + + if (mPlaceInfo->getVisible()) + { + LLFloaterWorldMap* worldmap_instance = LLFloaterWorldMap::getInstance(); + if(!worldmap_instance) + return; + + if (mPlaceInfoType == AGENT_INFO_TYPE || + mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE || + mPlaceInfoType == REMOTE_PLACE_INFO_TYPE || + mPlaceInfoType == TELEPORT_HISTORY_INFO_TYPE) + { + if (!mPosGlobal.isExactlyZero()) + { + worldmap_instance->trackLocation(mPosGlobal); + LLFloaterReg::showInstance("world_map", "center"); + } + } + else if (mPlaceInfoType == LANDMARK_INFO_TYPE) + { + LLLandmark* landmark = gLandmarkList.getAsset(mItem->getAssetUUID()); + if (!landmark) + return; + + LLVector3d landmark_global_pos; + if (!landmark->getGlobalPos(landmark_global_pos)) + return; + + if (!landmark_global_pos.isExactlyZero()) + { + worldmap_instance->trackLocation(landmark_global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } + } + } + else + { + mActivePanel->onShowOnMap(); + } +} + +void LLPanelPlaces::onOverflowButtonClicked() +{ + LLToggleableMenu* menu; + + bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; + + if ((is_agent_place_info_visible || + mPlaceInfoType == "remote_place" || + mPlaceInfoType == "teleport_history") && mPlaceMenu != NULL) + { + menu = mPlaceMenu; + + // Enable adding a landmark only for agent current parcel and if + // there is no landmark already pointing to that parcel in agent's inventory. + menu->getChild("landmark")->setEnabled(is_agent_place_info_visible && + !LLLandmarkActions::landmarkAlreadyExists()); + } + else if (mPlaceInfoType == LANDMARK_INFO_TYPE && mLandmarkMenu != NULL) + { + menu = mLandmarkMenu; + + BOOL is_landmark_removable = FALSE; + if (mItem.notNull()) + { + const LLUUID& item_id = mItem->getUUID(); + const LLUUID& trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH); + is_landmark_removable = gInventory.isObjectDescendentOf(item_id, gInventory.getRootFolderID()) && + !gInventory.isObjectDescendentOf(item_id, trash_id); + } + + menu->getChild("delete")->setEnabled(is_landmark_removable); + } + else + { + return; + } + + if (!menu->toggleVisibility()) + return; + + menu->updateParent(LLMenuGL::sMenuContainer); + LLRect rect = mOverflowBtn->getRect(); + menu->setButtonRect(rect, this); + LLMenuGL::showPopup(this, menu, rect.mRight, rect.mTop); +} + +void LLPanelPlaces::onOverflowMenuItemClicked(const LLSD& param) +{ + std::string item = param.asString(); + if (item == "landmark") + { + onOpen(LLSD().insert("type", CREATE_LANDMARK_INFO_TYPE)); + } + else if (item == "copy") + { + LLLandmarkActions::getSLURLfromPosGlobal(mPosGlobal, boost::bind(&onSLURLBuilt, _1)); + } + else if (item == "delete") + { + gInventory.removeItem(mItem->getUUID()); + + onBackButtonClicked(); + } + else if (item == "pick") + { + if (!mPlaceInfo) + return; + + mPlaceInfo->createPick(mPosGlobal); + + onBackButtonClicked(); + } +} + +void LLPanelPlaces::onCreateLandmarkButtonClicked(const LLUUID& folder_id) +{ + if (!mPlaceInfo) + return; + + mPlaceInfo->createLandmark(folder_id); +} + +void LLPanelPlaces::onBackButtonClicked() +{ + if (!mPlaceInfo) + return; + + if (mPlaceInfo->isMediaPanelVisible()) + { + toggleMediaPanel(); + } + else + { + togglePlaceInfoPanel(FALSE); + + // Resetting mPlaceInfoType when Place Info panel is closed. + mPlaceInfoType = LLStringUtil::null; + } + + updateVerbs(); +} + +void LLPanelPlaces::toggleMediaPanel() +{ + if (!mPlaceInfo) + return; + + mPlaceInfo->toggleMediaPanel(!mPlaceInfo->isMediaPanelVisible()); + + // Refresh the current place info because + // the media panel controls can't refer to + // the remote parcel media. + onOpen(LLSD().insert("type", AGENT_INFO_TYPE)); +} + +void LLPanelPlaces::togglePlaceInfoPanel(BOOL visible) +{ + if (!mPlaceInfo) + return; + + mPlaceInfo->setVisible(visible); + mFilterEditor->setVisible(!visible); + mTabContainer->setVisible(!visible); + + if (visible) + { + mPlaceInfo->resetLocation(); + + LLRect rect = getRect(); + LLRect new_rect = LLRect(rect.mLeft, rect.mTop, rect.mRight, mTabContainer->getRect().mBottom); + mPlaceInfo->reshape(new_rect.getWidth(),new_rect.getHeight()); + } +} + +//virtual +void LLPanelPlaces::changed(U32 mask) +{ + if (!(gInventory.isInventoryUsable() && LLTeleportHistory::getInstance())) + return; + + LLLandmarksPanel* landmarks_panel = new LLLandmarksPanel(); + if (landmarks_panel) + { + landmarks_panel->setPanelPlacesButtons(this); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(landmarks_panel). + label(getString("landmarks_tab_title")). + insert_at(LLTabContainer::END)); + } + + LLTeleportHistoryPanel* teleport_history_panel = new LLTeleportHistoryPanel(); + if (teleport_history_panel) + { + teleport_history_panel->setPanelPlacesButtons(this); + + mTabContainer->addTabPanel( + LLTabContainer::TabPanelParams(). + panel(teleport_history_panel). + label(getString("teleport_history_tab_title")). + insert_at(LLTabContainer::END)); + } + + mTabContainer->selectFirstTab(); + + mActivePanel = dynamic_cast(mTabContainer->getCurrentPanel()); + + // we don't need to monitor inventory changes anymore, + // so remove the observer + gInventory.removeObserver(this); +} + +void LLPanelPlaces::onAgentParcelChange() +{ + if (!mPlaceInfo) + return; + + if (mPlaceInfo->getVisible() && mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE) + { + onOpen(LLSD().insert("type", mPlaceInfoType)); + } + else if (mPlaceInfo->isMediaPanelVisible()) + { + onOpen(LLSD().insert("type", AGENT_INFO_TYPE)); + } + else + { + updateVerbs(); + } +} + +void LLPanelPlaces::updateVerbs() +{ + if (!mPlaceInfo) + return; + + bool is_place_info_visible = mPlaceInfo->getVisible(); + bool is_agent_place_info_visible = mPlaceInfoType == AGENT_INFO_TYPE; + bool is_create_landmark_visible = mPlaceInfoType == CREATE_LANDMARK_INFO_TYPE; + bool is_media_panel_visible = mPlaceInfo->isMediaPanelVisible(); + + mTeleportBtn->setVisible(!is_create_landmark_visible); + mShareBtn->setVisible(!is_create_landmark_visible); + mCreateLandmarkBtn->setVisible(is_create_landmark_visible); + mFolderMenuBtn->setVisible(is_create_landmark_visible); + + mOverflowBtn->setEnabled(is_place_info_visible && !is_media_panel_visible && !is_create_landmark_visible); + + if (is_place_info_visible) + { + if (is_agent_place_info_visible) + { + // We don't need to teleport to the current location + // so check if the location is not within the current parcel. + mTeleportBtn->setEnabled(!is_media_panel_visible && + !mPosGlobal.isExactlyZero() && + !LLViewerParcelMgr::getInstance()->inAgentParcel(mPosGlobal)); + } + else if (is_create_landmark_visible) + { + // Enable "Create Landmark" only if there is no landmark + // for the current parcel. + bool no_landmark = !LLLandmarkActions::landmarkAlreadyExists(); + mCreateLandmarkBtn->setEnabled(no_landmark); + mFolderMenuBtn->setEnabled(no_landmark); + } + else if (mPlaceInfoType == LANDMARK_INFO_TYPE || mPlaceInfoType == REMOTE_PLACE_INFO_TYPE) + { + mTeleportBtn->setEnabled(TRUE); + } + + mShowOnMapBtn->setEnabled(!is_media_panel_visible); + } + else + { + mActivePanel->updateVerbs(); + } +} + +void LLPanelPlaces::showLandmarkFoldersMenu() +{ + if (mLandmarkFoldersMenuHandle.isDead()) + { + LLToggleableMenu::Params menu_p; + menu_p.name("landmarks_folders_menu"); + menu_p.can_tear_off(false); + menu_p.visible(false); + menu_p.scrollable(true); + menu_p.max_scrollable_items = 10; + + LLToggleableMenu* menu = LLUICtrlFactory::create(menu_p); + + mLandmarkFoldersMenuHandle = menu->getHandle(); + } + + LLToggleableMenu* menu = (LLToggleableMenu*)mLandmarkFoldersMenuHandle.get(); + if(!menu) + return; + + if (!menu->toggleVisibility()) + return; + + // Collect all folders that can contain landmarks. + LLInventoryModel::cat_array_t cats; + collectLandmarkFolders(cats); + + // Sort the folders by their full name. + folder_vec_t folders; + S32 count = cats.count(); + for (S32 i = 0; i < count; i++) + { + const LLViewerInventoryCategory* cat = cats.get(i); + std::string cat_full_name = getFullFolderName(cat); + folders.push_back(folder_pair_t(cat->getUUID(), cat_full_name)); + } + sort(folders.begin(), folders.end(), cmp_folders); + + LLRect btn_rect = mFolderMenuBtn->getRect(); + + LLRect root_rect = getRootView()->getRect(); + + // Check it there are changed items or viewer dimensions + // have changed since last call + if (mLandmarkFoldersCache.size() == count && + mRootViewWidth == root_rect.getWidth() && + mRootViewHeight == root_rect.getHeight()) + { + S32 i; + for (i = 0; i < count; i++) + { + if (mLandmarkFoldersCache[i].second != folders[i].second) + { + break; + } + } + + // Check passed, just show the menu + if (i == count) + { + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + + menu->setButtonRect(btn_rect, this); + LLMenuGL::showPopup(this, menu, btn_rect.mRight, btn_rect.mTop); + return; + } + } + + // If there are changes, store the new viewer dimensions + // and a list of folders + mRootViewWidth = root_rect.getWidth(); + mRootViewHeight = root_rect.getHeight(); + mLandmarkFoldersCache = folders; + + menu->empty(); + + // Menu width must not exceed the root view limits, + // so we assume the space between the left edge of + // the root view and + LLRect screen_btn_rect; + localRectToScreen(btn_rect, &screen_btn_rect); + S32 free_space = screen_btn_rect.mRight; + U32 max_width = llmin(LANDMARK_FOLDERS_MENU_WIDTH, free_space); + + for(folder_vec_t::const_iterator it = mLandmarkFoldersCache.begin(); it != mLandmarkFoldersCache.end(); it++) + { + const std::string& item_name = it->second; + + LLMenuItemCallGL::Params item_params; + item_params.name(item_name); + item_params.label(item_name); + + item_params.on_click.function(boost::bind(&LLPanelPlaces::onCreateLandmarkButtonClicked, this, it->first)); + + LLMenuItemCallGL *menu_item = LLUICtrlFactory::create(item_params); + + // *TODO: Use a separate method for menu width calculation. + // Check whether item name wider than menu + if (menu_item->getNominalWidth() > max_width) + { + S32 chars_total = item_name.length(); + S32 chars_fitted = 1; + menu_item->setLabel(LLStringExplicit("")); + S32 label_space = max_width - menu_item->getFont()->getWidth("...") - + menu_item->getNominalWidth(); // This returns width of menu item with empty label (pad pixels) + + while (chars_fitted < chars_total && menu_item->getFont()->getWidth(item_name, 0, chars_fitted) < label_space) + { + chars_fitted++; + } + chars_fitted--; // Rolling back one char, that doesn't fit + + menu_item->setLabel(item_name.substr(0, chars_fitted) + "..."); + } + + menu->addChild(menu_item); + } + + menu->buildDrawLabels(); + menu->updateParent(LLMenuGL::sMenuContainer); + menu->setButtonRect(btn_rect, this); + LLMenuGL::showPopup(this, menu, btn_rect.mRight, btn_rect.mTop); +} + +static bool cmp_folders(const folder_pair_t& left, const folder_pair_t& right) +{ + return left.second < right.second; +} + +static std::string getFullFolderName(const LLViewerInventoryCategory* cat) +{ + std::string name = cat->getName(); + LLUUID parent_id; + + // translate category name, if it's right below the root + // FIXME: it can throw notification about non existent string in strings.xml + if (cat->getParentUUID().notNull() && cat->getParentUUID() == gInventory.getRootFolderID()) + { + LLTrans::findString(name, "InvFolder " + name); + } + + // we don't want "My Inventory" to appear in the name + while ((parent_id = cat->getParentUUID()).notNull() && parent_id != gInventory.getRootFolderID()) + { + cat = gInventory.getCategory(parent_id); + name = cat->getName() + "/" + name; + } + + return name; +} + +static void collectLandmarkFolders(LLInventoryModel::cat_array_t& cats) +{ + // Add the "Landmarks" category itself. + LLUUID landmarks_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); + LLViewerInventoryCategory* landmarks_cat = gInventory.getCategory(landmarks_id); + if (!landmarks_cat) + { + llwarns << "Cannot find the landmarks folder" << llendl; + } + else + { + cats.put(landmarks_cat); + } + + // Add descendent folders of the "Landmarks" category. + LLInventoryModel::item_array_t items; // unused + LLIsType is_category(LLAssetType::AT_CATEGORY); + gInventory.collectDescendentsIf( + landmarks_id, + cats, + items, + LLInventoryModel::EXCLUDE_TRASH, + is_category); + + // Add the "My Favorites" category. + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + LLViewerInventoryCategory* favorites_cat = gInventory.getCategory(favorites_id); + if (!favorites_cat) + { + llwarns << "Cannot find the favorites folder" << llendl; + } + else + { + cats.put(favorites_cat); + } +} + +static const LLVector3 get_pos_local_from_global(const LLVector3d &pos_global) +{ + F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); + F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS ); + + LLVector3 pos_local(region_x, region_y, (F32)pos_global.mdV[VZ]); + return pos_local; +} + +static void onSLURLBuilt(std::string& slurl) +{ + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(slurl)); + + LLSD args; + args["SLURL"] = slurl; + + LLNotifications::instance().add("CopySLURL", args); +} diff --git a/indra/newview/llpanelplaces.h b/indra/newview/llpanelplaces.h new file mode 100644 index 0000000000..089a854762 --- /dev/null +++ b/indra/newview/llpanelplaces.h @@ -0,0 +1,128 @@ +/** + * @file llpanelplaces.h + * @brief Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPLACES_H +#define LL_LLPANELPLACES_H + +#include "lltimer.h" + +#include "llpanel.h" + +#include "llinventory.h" + +#include "llinventorymodel.h" +#include "llpanelplaceinfo.h" + +class LLInventoryItem; +class LLLandmark; +class LLPanelPlacesTab; +class LLFilterEditor; +class LLTabContainer; + +typedef std::pair folder_pair_t; + +class LLPanelPlaces : public LLPanel, LLInventoryObserver +{ +public: + LLPanelPlaces(); + virtual ~LLPanelPlaces(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void changed(U32 mask); + /*virtual*/ void onOpen(const LLSD& key); + + void setItem(LLInventoryItem* item); + +private: + void onLandmarkLoaded(LLLandmark* landmark); + void onFilterEdit(const std::string& search_string); + void onTabSelected(); + + //void onShareButtonClicked(); + void onTeleportButtonClicked(); + void onShowOnMapButtonClicked(); + void onOverflowButtonClicked(); + void onOverflowMenuItemClicked(const LLSD& param); + void onCreateLandmarkButtonClicked(const LLUUID& folder_id); + void onBackButtonClicked(); + + void toggleMediaPanel(); + void togglePlaceInfoPanel(BOOL visible); + + void onAgentParcelChange(); + void updateVerbs(); + + void showLandmarkFoldersMenu(); + + LLFilterEditor* mFilterEditor; + LLPanelPlacesTab* mActivePanel; + LLTabContainer* mTabContainer; + LLPanelPlaceInfo* mPlaceInfo; + LLToggleableMenu* mPlaceMenu; + LLToggleableMenu* mLandmarkMenu; + + LLButton* mCreateLandmarkBtn; + LLButton* mFolderMenuBtn; + LLButton* mTeleportBtn; + LLButton* mShowOnMapBtn; + LLButton* mShareBtn; + LLButton* mOverflowBtn; + + // Pointer to a landmark item or to a linked landmark + LLPointer mItem; + + // Absolute position of the location for teleport, may not + // be available (hence zero) + LLVector3d mPosGlobal; + + // Search string for filtering landmarks and teleport + // history locations + std::string mFilterSubString; + + // Information type currently shown in Place Information panel + std::string mPlaceInfoType; + + // Menu handle for pop-up menu to chose a landmark saving + // folder when creating a new landmark + LLHandle mLandmarkFoldersMenuHandle; + + typedef std::vector folder_vec_t; + + // List of folders to choose from when creating a landmark + folder_vec_t mLandmarkFoldersCache; + + // If root view width or height is changed + // the pop-up menu must be updated + S32 mRootViewWidth; + S32 mRootViewHeight; +}; + +#endif //LL_LLPANELPLACES_H diff --git a/indra/newview/llpanelplacestab.cpp b/indra/newview/llpanelplacestab.cpp new file mode 100644 index 0000000000..7c0a7b0cc4 --- /dev/null +++ b/indra/newview/llpanelplacestab.cpp @@ -0,0 +1,87 @@ +/** + * @file llpanelplacestab.cpp + * @brief Tabs interface for Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llpanelplacestab.h" + +#include "llwindow.h" + +#include "llnotifications.h" + +#include "llbutton.h" +#include "llslurl.h" +#include "llworldmap.h" + +bool LLPanelPlacesTab::isTabVisible() +{ + LLUICtrl* parent = getParentUICtrl(); + if (!parent) return false; + if (!parent->getVisible()) return false; + return true; +} + +void LLPanelPlacesTab::setPanelPlacesButtons(LLPanelPlaces* panel) +{ + //mShareBtn = panel->getChild("share_btn"); + mTeleportBtn = panel->getChild("teleport_btn"); + mShowOnMapBtn = panel->getChild("map_btn"); +} + +void LLPanelPlacesTab::onRegionResponse(const LLVector3d& landmark_global_pos, + U64 region_handle, + const std::string& url, + const LLUUID& snapshot_id, + bool teleport) +{ + std::string sim_name; + bool gotSimName = LLWorldMap::getInstance()->simNameFromPosGlobal( landmark_global_pos, sim_name ); + + std::string sl_url; + if ( gotSimName ) + { + F32 region_x = (F32)fmod( landmark_global_pos.mdV[VX], (F64)REGION_WIDTH_METERS ); + F32 region_y = (F32)fmod( landmark_global_pos.mdV[VY], (F64)REGION_WIDTH_METERS ); + + sl_url = LLSLURL::buildSLURL(sim_name, llround(region_x), llround(region_y), llround((F32)landmark_global_pos.mdV[VZ])); + } + else + { + sl_url = ""; + } + + LLView::getWindow()->copyTextToClipboard(utf8str_to_wstring(sl_url)); + + LLSD args; + args["SLURL"] = sl_url; + + LLNotifications::instance().add("CopySLURL", args); +} diff --git a/indra/newview/llpanelplacestab.h b/indra/newview/llpanelplacestab.h new file mode 100644 index 0000000000..1c70869414 --- /dev/null +++ b/indra/newview/llpanelplacestab.h @@ -0,0 +1,66 @@ +/** + * @file llpanelplacestab.h + * @brief Tabs interface for Side Bar "Places" panel + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2004-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELPLACESTAB_H +#define LL_LLPANELPLACESTAB_H + +#include "llpanel.h" + +#include "llpanelplaces.h" + +class LLPanelPlacesTab : public LLPanel +{ +public: + LLPanelPlacesTab() : LLPanel() {} + virtual ~LLPanelPlacesTab() {} + + virtual void onSearchEdit(const std::string& string) = 0; + virtual void updateVerbs() = 0; // Updates buttons at the bottom of Places panel + //virtual void onShare() = 0; + virtual void onShowOnMap() = 0; + virtual void onTeleport() = 0; + //virtual void onCopySLURL() = 0; + + bool isTabVisible(); // Check if parent TabContainer is visible. + + void setPanelPlacesButtons(LLPanelPlaces* panel); + void onRegionResponse(const LLVector3d& landmark_global_pos, + U64 region_handle, + const std::string& url, + const LLUUID& snapshot_id, + bool teleport); +protected: + //LLButton* mShareBtn; + LLButton* mTeleportBtn; + LLButton* mShowOnMapBtn; +}; + +#endif //LL_LLPANELPLACESTAB_H diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp new file mode 100644 index 0000000000..6d3d307526 --- /dev/null +++ b/indra/newview/llpanelprofile.cpp @@ -0,0 +1,178 @@ +/** +* @file llpanelprofile.cpp +* @brief Profile panel implementation +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llpanelprofile.h" + +#include "llagent.h" +#include "llavataractions.h" +#include "llcommandhandler.h" +#include "llpanelpicks.h" +#include "lltabcontainer.h" + +static const std::string PANEL_PICKS = "panel_picks"; +static const std::string PANEL_PROFILE = "panel_profile"; + +class LLAgentHandler : public LLCommandHandler +{ +public: + // requires trusted browser to trigger + LLAgentHandler() : LLCommandHandler("agent", true) { } + + bool handle(const LLSD& params, const LLSD& query_map, + LLMediaCtrl* web) + { + if (params.size() < 2) return false; + LLUUID agent_id; + if (!agent_id.set(params[0], FALSE)) + { + return false; + } + + if (params[1].asString() == "about") + { + LLAvatarActions::showProfile(agent_id); + return true; + } + return false; + } +}; +LLAgentHandler gAgentHandler; + + +LLPanelProfile::LLPanelProfile() + : LLPanel() + , mTabCtrl(NULL) + , mAvatarId(LLUUID::null) +{ +} + +BOOL LLPanelProfile::postBuild() +{ + mTabCtrl = getChild("tabs"); + + getTabCtrl()->setCommitCallback(boost::bind(&LLPanelProfile::onTabSelected, this, _2)); + + LLPanelPicks* panel_picks = getChild(PANEL_PICKS); + panel_picks->setProfilePanel(this); + + getTabContainer()[PANEL_PICKS] = panel_picks; + getTabContainer()[PANEL_PROFILE] = getChild(PANEL_PROFILE); + + return TRUE; +} + +void LLPanelProfile::onOpen(const LLSD& key) +{ + if (key.has("open_tab_name")) + { + getTabContainer()[PANEL_PICKS]->onClose(); + + // onOpen from selected panel will be called from onTabSelected callback + getTabCtrl()->selectTabByName(key["open_tab_name"]); + } + else + { + getTabCtrl()->getCurrentPanel()->onOpen(getAvatarId()); + } + + // Update the avatar name. + gCacheName->get(getAvatarId(), FALSE, + boost::bind(&LLPanelProfile::onAvatarNameCached, this, _1, _2, _3, _4)); +} + +//*TODO redo panel toggling +void LLPanelProfile::togglePanel(LLPanel* panel) +{ + // TRUE - we need to open/expand "panel" + bool expand = getChildList()->back() != panel; // mTabCtrl->getVisible(); + + if (expand) + { + //*NOTE on view profile panel along with tabcontainer there is + // a backbutton that will be shown when there will be a panel over it even + //if that panel has visible backgroud + setAllChildrenVisible(FALSE); + + panel->setVisible(TRUE); + if (panel->getParent() != this) + { + addChildInBack(panel); + } + else + { + sendChildToBack(panel); + } + + LLRect new_rect = getRect(); + panel->reshape(new_rect.getWidth(), new_rect.getHeight()); + new_rect.setLeftTopAndSize(0, new_rect.getHeight(), new_rect.getWidth(), new_rect.getHeight()); + panel->setRect(new_rect); + } + else + { + this->setAllChildrenVisible(TRUE); + panel->setVisible(FALSE); + if (panel->getParent() == this) + { + removeChild(panel); + } + sendChildToBack(getTabCtrl()); + getTabCtrl()->getCurrentPanel()->onOpen(getAvatarId()); + } +} + +void LLPanelProfile::onTabSelected(const LLSD& param) +{ + std::string tab_name = param.asString(); + if (NULL != getTabContainer()[tab_name]) + { + getTabContainer()[tab_name]->onOpen(getAvatarId()); + } +} + +void LLPanelProfile::setAllChildrenVisible(BOOL visible) +{ + const child_list_t* child_list = getChildList(); + child_list_const_iter_t child_it = child_list->begin(); + for (; child_it != child_list->end(); ++child_it) + { + LLView* viewp = *child_it; + viewp->setVisible(visible); + } +} + +void LLPanelProfile::onAvatarNameCached(const LLUUID& id, const std::string& first_name, const std::string& last_name, BOOL is_group) +{ + llassert(getAvatarId() == id); + getChild("user_name", FALSE)->setValue(first_name + " " + last_name); +} diff --git a/indra/newview/llpanelprofile.h b/indra/newview/llpanelprofile.h new file mode 100644 index 0000000000..0864ec1bc3 --- /dev/null +++ b/indra/newview/llpanelprofile.h @@ -0,0 +1,88 @@ +/** +* @file llpanelprofile.h +* @brief Profile panel +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLPANELPROFILE_H +#define LL_LLPANELPROFILE_H + +#include "llviewerprecompiledheaders.h" +#include "llpanel.h" +#include "llpanelavatar.h" + +class LLTabContainer; + +/** +* Base class for Profile View and Me Profile. +*/ +class LLPanelProfile : public LLPanel +{ + LOG_CLASS(LLPanelProfile); + +public: + /*virtual*/ BOOL postBuild(); + + /*virtual*/ void onOpen(const LLSD& key); + + virtual void togglePanel(LLPanel*); + +protected: + + LLPanelProfile(); + + virtual void onTabSelected(const LLSD& param); + + virtual void setAllChildrenVisible(BOOL visible); + + LLTabContainer* getTabCtrl() { return mTabCtrl; } + + const LLUUID& getAvatarId() { return mAvatarId; } + + void setAvatarId(const LLUUID& avatar_id) { mAvatarId = avatar_id; } + + typedef std::map profile_tabs_t; + + profile_tabs_t& getTabContainer() { return mTabContainer; } + +private: + // LLCacheName will call this function when avatar name is loaded from server. + // This is required to display names that have not been cached yet. + void onAvatarNameCached( + const LLUUID& id, + const std::string& first_name, + const std::string& last_name, + BOOL is_group); + + LLTabContainer* mTabCtrl; + profile_tabs_t mTabContainer; + LLUUID mAvatarId; +}; + +#endif //LL_LLPANELPROFILE_H diff --git a/indra/newview/llpanelprofileview.cpp b/indra/newview/llpanelprofileview.cpp new file mode 100644 index 0000000000..18184a6476 --- /dev/null +++ b/indra/newview/llpanelprofileview.cpp @@ -0,0 +1,96 @@ +/** +* @file llpanelprofileview.cpp +* @brief Side tray "Profile View" panel +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llpanelprofileview.h" + +#include "llpanelavatar.h" +#include "llpanelpicks.h" +#include "llsidetraypanelcontainer.h" +#include "llpanelprofile.h" + +static LLRegisterPanelClassWrapper t_panel_target_profile("panel_profile_view"); + +static std::string PANEL_NOTES = "panel_notes"; +static const std::string PANEL_PROFILE = "panel_profile"; + +LLPanelProfileView::LLPanelProfileView() +: LLPanelProfile() +{ +} + +LLPanelProfileView::~LLPanelProfileView(void) +{ +} + +/*virtual*/ +void LLPanelProfileView::onOpen(const LLSD& key) +{ + LLUUID id; + if(key.has("id")) + { + id = key["id"]; + } + if(id.notNull() && getAvatarId() != id) + { + setAvatarId(id); + } + + LLPanelProfile::onOpen(key); +} + +BOOL LLPanelProfileView::postBuild() +{ + LLPanelProfile::postBuild(); + + getTabContainer()[PANEL_NOTES] = getChild(PANEL_NOTES); + + //*TODO remove this, according to style guide we don't use status combobox + getTabContainer()[PANEL_PROFILE]->childSetVisible("online_me_status_text", FALSE); + getTabContainer()[PANEL_PROFILE]->childSetVisible("status_combo", FALSE); + + childSetCommitCallback("back",boost::bind(&LLPanelProfileView::onBackBtnClick,this),NULL); + + return TRUE; +} + + +//private + +void LLPanelProfileView::onBackBtnClick() +{ + LLSideTrayPanelContainer* parent = dynamic_cast(getParent()); + if(parent) + { + parent->openPreviousPanel(); + } +} diff --git a/indra/newview/llpanelprofileview.h b/indra/newview/llpanelprofileview.h new file mode 100644 index 0000000000..92def7b7ca --- /dev/null +++ b/indra/newview/llpanelprofileview.h @@ -0,0 +1,68 @@ +/** +* @file llpanelprofileview.h +* @brief Side tray "Profile View" panel +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLPANELPROFILEVIEW_H +#define LL_LLPANELPROFILEVIEW_H + +#include "llpanel.h" +#include "llpanelprofile.h" +#include "llavatarpropertiesprocessor.h" + +class LLPanelProfile; +class LLPanelProfileTab; + + +/** +* Panel for displaying Avatar's profile. It consists of three sub panels - Profile, +* Picks and Notes. +*/ +class LLPanelProfileView : public LLPanelProfile +{ + LOG_CLASS(LLPanelProfileView); + friend class LLUICtrlFactory; + +public: + + LLPanelProfileView(); + + /*virtual*/ ~LLPanelProfileView(); + + /*virtual*/ void onOpen(const LLSD& key); + + /*virtual*/ BOOL postBuild(); + +protected: + + void onBackBtnClick(); +}; + +#endif //LL_LLPANELPROFILEVIEW_H diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp new file mode 100644 index 0000000000..8b378c33e3 --- /dev/null +++ b/indra/newview/llpanelteleporthistory.cpp @@ -0,0 +1,234 @@ +/** + * @file llpanelteleporthistory.cpp + * @brief Teleport history represented by a scrolling list + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" + +#include "llfloaterworldmap.h" +#include "llpanelteleporthistory.h" +#include "llsidetray.h" +#include "llworldmap.h" + +// Not yet implemented; need to remove buildPanel() from constructor when we switch +//static LLRegisterPanelClassWrapper t_teleport_history("panel_teleport_history"); + +LLTeleportHistoryPanel::LLTeleportHistoryPanel() + : LLPanelPlacesTab(), + mFilterSubString(LLStringUtil::null), + mTeleportHistory(NULL), + mHistoryItems(NULL) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_teleport_history.xml"); +} + +LLTeleportHistoryPanel::~LLTeleportHistoryPanel() +{ +} + +BOOL LLTeleportHistoryPanel::postBuild() +{ + mTeleportHistory = LLTeleportHistory::getInstance(); + if (mTeleportHistory) + { + mTeleportHistory->setHistoryChangedCallback(boost::bind(&LLTeleportHistoryPanel::showTeleportHistory, this)); + } + + mHistoryItems = getChild("history_items"); + if (mHistoryItems) + { + mHistoryItems->setDoubleClickCallback(onDoubleClickItem, this); + mHistoryItems->setCommitOnSelectionChange(FALSE); + mHistoryItems->setCommitCallback(boost::bind(&LLTeleportHistoryPanel::handleItemSelect, this, _2)); + } + + return TRUE; +} + +// virtual +void LLTeleportHistoryPanel::onSearchEdit(const std::string& string) +{ + if (mFilterSubString != string) + { + mFilterSubString = string; + showTeleportHistory(); + } +} + +// virtual +void LLTeleportHistoryPanel::onShowOnMap() +{ + LLScrollListItem* itemp = mHistoryItems->getFirstSelected(); + if(!itemp) + return; + + S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); + + const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); + + LLVector3d global_pos = hist_items[index].mGlobalPos; + + if (!global_pos.isExactlyZero()) + { + LLFloaterWorldMap::getInstance()->trackLocation(global_pos); + LLFloaterReg::showInstance("world_map", "center"); + } +} + +// virtual +void LLTeleportHistoryPanel::onTeleport() +{ + LLScrollListItem* itemp = mHistoryItems->getFirstSelected(); + if(!itemp) + return; + + S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); + + // teleport to existing item in history, so we don't add it again + mTeleportHistory->goToItem(index); +} + +/* +// virtual +void LLTeleportHistoryPanel::onCopySLURL() +{ + LLScrollListItem* itemp = mHistoryItems->getFirstSelected(); + if(!itemp) + return; + + S32 index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); + + const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); + + LLVector3d global_pos = hist_items[index].mGlobalPos; + + U64 new_region_handle = to_region_handle(global_pos); + + LLWorldMap::url_callback_t cb = boost::bind( + &LLPanelPlacesTab::onRegionResponse, this, + global_pos, _1, _2, _3, _4); + + LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, cb, std::string("unused"), false); +} +*/ + +// virtual +void LLTeleportHistoryPanel::updateVerbs() +{ + if (!isTabVisible()) + return; + + S32 index = 0; + S32 cur_item = 0; + + LLScrollListItem* itemp = mHistoryItems->getFirstSelected(); + if (itemp) + { + index = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); + cur_item = mTeleportHistory->getCurrentItemIndex(); + } + + mTeleportBtn->setEnabled(index != cur_item); + mShowOnMapBtn->setEnabled(itemp != NULL); +} + +void LLTeleportHistoryPanel::showTeleportHistory() +{ + const LLTeleportHistory::slurl_list_t& hist_items = mTeleportHistory->getItems(); + + mHistoryItems->deleteAllItems(); + + S32 cur_item = mTeleportHistory->getCurrentItemIndex(); + + for (LLTeleportHistory::slurl_list_t::const_iterator iter = hist_items.begin(); + iter != hist_items.end(); ++iter) + { + std::string landmark_title = (*iter).mTitle; + LLStringUtil::toUpper(landmark_title); + + std::string::size_type match_offset = mFilterSubString.size() ? landmark_title.find(mFilterSubString) : std::string::npos; + bool passed = mFilterSubString.size() == 0 || match_offset != std::string::npos; + + if (!passed) + continue; + + S32 index = iter - hist_items.begin(); + + LLSD row; + row["id"] = index; + + LLSD& icon_column = row["columns"][LIST_ICON]; + icon_column["column"] = "landmark_icon"; + icon_column["type"] = "icon"; + icon_column["value"] = "inv_item_landmark.tga"; + + LLSD& region_column = row["columns"][LIST_ITEM_TITLE]; + region_column["column"] = "region"; + region_column["type"] = "text"; + region_column["value"] = (*iter).mTitle; + + LLSD& index_column = row["columns"][LIST_INDEX]; + index_column["column"] = "index"; + index_column["type"] = "text"; + index_column["value"] = index; + + mHistoryItems->addElement(row, ADD_TOP); + + if (cur_item == index) + { + LLScrollListItem* itemp = mHistoryItems->getItem(index); + ((LLScrollListText*)itemp->getColumn(LIST_ITEM_TITLE))->setFontStyle(LLFontGL::BOLD); + } + } + + updateVerbs(); +} + +void LLTeleportHistoryPanel::handleItemSelect(const LLSD& data) +{ + updateVerbs(); +} + +//static +void LLTeleportHistoryPanel::onDoubleClickItem(void* user_data) +{ + LLTeleportHistoryPanel* self = (LLTeleportHistoryPanel*)user_data; + + LLScrollListItem* itemp = self->mHistoryItems->getFirstSelected(); + if(!itemp) + return; + + LLSD key; + key["type"] = "teleport_history"; + key["id"] = itemp->getColumn(LIST_INDEX)->getValue().asInteger(); + + LLSideTray::getInstance()->showPanel("panel_places", key); +} diff --git a/indra/newview/llpanelteleporthistory.h b/indra/newview/llpanelteleporthistory.h new file mode 100644 index 0000000000..553385b37e --- /dev/null +++ b/indra/newview/llpanelteleporthistory.h @@ -0,0 +1,73 @@ +/** + * @file llpanelteleporthistory.h + * @brief Teleport history represented by a scrolling list + * class definition + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLPANELTELEPORTHISTORY_H +#define LL_LLPANELTELEPORTHISTORY_H + +#include "lluictrlfactory.h" +#include "llscrolllistctrl.h" + +#include "llpanelplacestab.h" +#include "llteleporthistory.h" + +class LLTeleportHistoryPanel : public LLPanelPlacesTab +{ +public: + LLTeleportHistoryPanel(); + virtual ~LLTeleportHistoryPanel(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void onSearchEdit(const std::string& string); + /*virtual*/ void onShowOnMap(); + /*virtual*/ void onTeleport(); + ///*virtual*/ void onCopySLURL(); + /*virtual*/ void updateVerbs(); + + void showTeleportHistory(); + void handleItemSelect(const LLSD& data); + + static void onDoubleClickItem(void* user_data); + +private: + enum TELEPORT_HISTORY_COLUMN_ORDER + { + LIST_ICON, + LIST_ITEM_TITLE, + LIST_INDEX + }; + + LLTeleportHistory* mTeleportHistory; + LLScrollListCtrl* mHistoryItems; + std::string mFilterSubString; +}; + +#endif //LL_LLPANELTELEPORTHISTORY_H diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 6d014a23de..ce16b95bc0 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -49,7 +49,6 @@ #include "material_codes.h" // project includes -#include "llagent.h" #include "llbutton.h" #include "llcheckboxctrl.h" #include "llcolorswatch.h" @@ -107,8 +106,8 @@ BOOL LLPanelVolume::postBuild() childSetCommitCallback("Light Checkbox Ctrl",onCommitIsLight,this); LLColorSwatchCtrl* LightColorSwatch = getChild("colorswatch"); if(LightColorSwatch){ - LightColorSwatch->setOnCancelCallback(onLightCancelColor); - LightColorSwatch->setOnSelectCallback(onLightSelectColor); + LightColorSwatch->setOnCancelCallback(boost::bind(&LLPanelVolume::onLightCancelColor, this, _2)); + LightColorSwatch->setOnSelectCallback(boost::bind(&LLPanelVolume::onLightSelectColor, this, _2)); childSetCommitCallback("colorswatch",onCommitLight,this); } childSetCommitCallback("Light Intensity",onCommitLight,this); @@ -125,8 +124,8 @@ BOOL LLPanelVolume::postBuild() return TRUE; } -LLPanelVolume::LLPanelVolume(const std::string& name) - : LLPanel(name) +LLPanelVolume::LLPanelVolume() + : LLPanel() { setMouseOpaque(FALSE); @@ -317,7 +316,7 @@ void LLPanelVolume::getState( ) } // static -BOOL LLPanelVolume::precommitValidate( LLUICtrl* ctrl, void* userdata ) +bool LLPanelVolume::precommitValidate( const LLSD& data ) { // TODO: Richard will fill this in later. return TRUE; // FALSE means that validation failed and new value should not be commited. @@ -427,21 +426,19 @@ void LLPanelVolume::sendIsFlexible() llinfos << "update flexible sent" << llendl; } -void LLPanelVolume::onLightCancelColor(LLUICtrl* ctrl, void* userdata) +void LLPanelVolume::onLightCancelColor(const LLSD& data) { - LLPanelVolume* self = (LLPanelVolume*) userdata; - LLColorSwatchCtrl* LightColorSwatch = self->getChild("colorswatch"); + LLColorSwatchCtrl* LightColorSwatch = getChild("colorswatch"); if(LightColorSwatch) { - LightColorSwatch->setColor(self->mLightSavedColor); + LightColorSwatch->setColor(mLightSavedColor); } - onLightSelectColor(NULL, userdata); + onLightSelectColor(data); } -void LLPanelVolume::onLightSelectColor(LLUICtrl* ctrl, void* userdata) +void LLPanelVolume::onLightSelectColor(const LLSD& data) { - LLPanelVolume* self = (LLPanelVolume*) userdata; - LLViewerObject* objectp = self->mObject; + LLViewerObject* objectp = mObject; if (!objectp || (objectp->getPCode() != LL_PCODE_VOLUME)) { return; @@ -449,13 +446,13 @@ void LLPanelVolume::onLightSelectColor(LLUICtrl* ctrl, void* userdata) LLVOVolume *volobjp = (LLVOVolume *)objectp; - LLColorSwatchCtrl* LightColorSwatch = self->getChild("colorswatch"); + LLColorSwatchCtrl* LightColorSwatch = getChild("colorswatch"); if(LightColorSwatch) { LLColor4 clr = LightColorSwatch->get(); LLColor3 clr3( clr ); volobjp->setLightColor(clr3); - self->mLightSavedColor = clr; + mLightSavedColor = clr; } } diff --git a/indra/newview/llpanelvolume.h b/indra/newview/llpanelvolume.h index 841880b147..f285141bbe 100644 --- a/indra/newview/llpanelvolume.h +++ b/indra/newview/llpanelvolume.h @@ -35,7 +35,7 @@ #include "v3math.h" #include "llpanel.h" -#include "llmemory.h" +#include "llpointer.h" #include "llvolume.h" class LLSpinCtrl; @@ -51,7 +51,7 @@ class LLColorSwatchCtrl; class LLPanelVolume : public LLPanel { public: - LLPanelVolume(const std::string& name); + LLPanelVolume(); virtual ~LLPanelVolume(); virtual void draw(); @@ -64,15 +64,15 @@ public: void sendIsLight(); void sendIsFlexible(); - static BOOL precommitValidate(LLUICtrl* ctrl,void* userdata); + static bool precommitValidate(const LLSD& data); static void onCommitIsLight( LLUICtrl* ctrl, void* userdata); static void onCommitLight( LLUICtrl* ctrl, void* userdata); static void onCommitIsFlexible( LLUICtrl* ctrl, void* userdata); static void onCommitFlexible( LLUICtrl* ctrl, void* userdata); - static void onLightCancelColor(LLUICtrl* ctrl, void* userdata); - static void onLightSelectColor(LLUICtrl* ctrl, void* userdata); + void onLightCancelColor(const LLSD& data); + void onLightSelectColor(const LLSD& data); protected: void getState(); diff --git a/indra/newview/llparcelselection.h b/indra/newview/llparcelselection.h index 5f26fafc33..0481bea6f7 100644 --- a/indra/newview/llparcelselection.h +++ b/indra/newview/llparcelselection.h @@ -33,7 +33,8 @@ #ifndef LLPARCELSELECTION_H #define LLPARCELSELECTION_H -#include "llmemory.h" +#include "llrefcount.h" +#include "llsafehandle.h" class LLParcel; diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index 6d7082bf9a..ab253e012d 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -34,11 +34,13 @@ #include "stdenums.h" #include "llpreview.h" + #include "lllineeditor.h" #include "llinventory.h" #include "llinventorymodel.h" #include "llresmgr.h" #include "lltextbox.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "lltooldraganddrop.h" #include "llradiogroup.h" @@ -47,129 +49,72 @@ #include "llviewerobjectlist.h" #include "lldbstrings.h" #include "llagent.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llselectmgr.h" -#include "llinventoryview.h" #include "llviewerinventory.h" +#include "llviewerwindow.h" +#include "lltrans.h" // Constants -// Globals and statics -LLPreview::preview_multimap_t LLPreview::sPreviewsBySource; -LLPreview::preview_map_t LLPreview::sInstances; -std::map > LLMultiPreview::sAutoOpenPreviewHandles; - -// Functions -LLPreview::LLPreview(const std::string& name) : - LLFloater(name), - mCopyToInvBtn(NULL), +LLPreview::LLPreview(const LLSD& key) +: LLFloater(key), + mItemUUID(key.asUUID()), + mObjectUUID(), // set later by setObjectID() + mCopyToInvBtn( NULL ), mForceClose(FALSE), mUserResized(FALSE), mCloseAfterSave(FALSE), mAssetStatus(PREVIEW_ASSET_UNLOADED), - mItem(NULL), - mDirty(TRUE) -{ - // don't add to instance list, since ItemID is null - mAuxItem = new LLInventoryItem; // (LLPointer is auto-deleted) - // don't necessarily steal focus on creation -- sometimes these guys pop up without user action - setAutoFocus(FALSE); - gInventory.addObserver(this); -} - -LLPreview::LLPreview(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid, BOOL allow_resize, S32 min_width, S32 min_height, LLPointer inv_item ) -: LLFloater(name, rect, title, allow_resize, min_width, min_height ), - mItemUUID(item_uuid), - mSourceID(LLUUID::null), - mObjectUUID(object_uuid), - mCopyToInvBtn( NULL ), - mForceClose( FALSE ), - mUserResized(FALSE), - mCloseAfterSave(FALSE), - mAssetStatus(PREVIEW_ASSET_UNLOADED), - mItem(inv_item), mDirty(TRUE) { mAuxItem = new LLInventoryItem; // don't necessarily steal focus on creation -- sometimes these guys pop up without user action setAutoFocus(FALSE); - if (mItemUUID.notNull()) - { - sInstances[mItemUUID] = this; - } gInventory.addObserver(this); + + refreshFromItem(); +} + +BOOL LLPreview::postBuild() +{ + refreshFromItem(); + return TRUE; } LLPreview::~LLPreview() { gFocusMgr.releaseFocusIfNeeded( this ); // calls onCommit() - - if (mItemUUID.notNull()) - { - sInstances.erase( mItemUUID ); - } - - if (mSourceID.notNull()) - { - preview_multimap_t::iterator found_it = sPreviewsBySource.find(mSourceID); - for (; found_it != sPreviewsBySource.end(); ++found_it) - { - if (found_it->second == getHandle()) - { - sPreviewsBySource.erase(found_it); - break; - } - } - } gInventory.removeObserver(this); } -void LLPreview::setItemID(const LLUUID& item_id) -{ - if (mItemUUID.notNull()) - { - sInstances.erase(mItemUUID); - } - - mItemUUID = item_id; - - if (mItemUUID.notNull()) - { - sInstances[mItemUUID] = this; - } -} - void LLPreview::setObjectID(const LLUUID& object_id) { mObjectUUID = object_id; -} - -void LLPreview::setSourceID(const LLUUID& source_id) -{ - if (mSourceID.notNull()) + if (getAssetStatus() == PREVIEW_ASSET_UNLOADED) { - // erase old one - preview_multimap_t::iterator found_it = sPreviewsBySource.find(mSourceID); - for (; found_it != sPreviewsBySource.end(); ++found_it) - { - if (found_it->second == getHandle()) - { - sPreviewsBySource.erase(found_it); - break; - } - } + loadAsset(); } - mSourceID = source_id; - sPreviewsBySource.insert(preview_multimap_t::value_type(mSourceID, getHandle())); } -const LLViewerInventoryItem *LLPreview::getItem() const +void LLPreview::setItem( LLInventoryItem* item ) { - if(mItem) - return mItem; - const LLViewerInventoryItem *item = NULL; - if(mObjectUUID.isNull()) + mItem = item; + if (mItem && getAssetStatus() == PREVIEW_ASSET_UNLOADED) + { + loadAsset(); + } +} + +const LLInventoryItem *LLPreview::getItem() const +{ + const LLInventoryItem *item = NULL; + if (mItem.notNull()) + { + item = mItem; + } + else if (mObjectUUID.isNull()) { // it's an inventory item, so get the item. item = gInventory.getItem(mItemUUID); @@ -180,7 +125,7 @@ const LLViewerInventoryItem *LLPreview::getItem() const LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(object) { - item = (LLViewerInventoryItem*)object->getInventoryObject(mItemUUID); + item = dynamic_cast(object->getInventoryObject(mItemUUID)); } } return item; @@ -189,7 +134,7 @@ const LLViewerInventoryItem *LLPreview::getItem() const // Sub-classes should override this function if they allow editing void LLPreview::onCommit() { - const LLViewerInventoryItem *item = getItem(); + const LLViewerInventoryItem *item = dynamic_cast(getItem()); if(item) { if (!item->isComplete()) @@ -226,7 +171,7 @@ void LLPreview::onCommit() // update the object itself. if( item->getType() == LLAssetType::AT_OBJECT ) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( avatar ) { LLViewerObject* obj = avatar->getWornAttachment( item->getUUID() ); @@ -249,23 +194,37 @@ void LLPreview::changed(U32 mask) mDirty = TRUE; } +void LLPreview::setNotecardInfo(const LLUUID& notecard_inv_id, + const LLUUID& object_id) +{ + mNotecardInventoryID = notecard_inv_id; + mNotecardObjectID = object_id; +} + void LLPreview::draw() { LLFloater::draw(); if (mDirty) { mDirty = FALSE; - const LLViewerInventoryItem *item = getItem(); - if (item) - { - refreshFromItem(item); - } + refreshFromItem(); } } -void LLPreview::refreshFromItem(const LLInventoryItem* item) +void LLPreview::refreshFromItem() { - setTitle(llformat("%s: %s",getTitleName(),item->getName().c_str())); + const LLInventoryItem* item = getItem(); + if (!item) + { + return; + } + if (hasString("Title")) + { + LLStringUtil::format_map_t args; + args["[NAME]"] = item->getName(); + LLUIString title = getString("Title", args); + setTitle(title.getString()); + } childSetText("desc",item->getDescription()); BOOL can_agent_manipulate = item->getPermissions().allowModifyBy(gAgent.getID()); @@ -286,81 +245,33 @@ void LLPreview::onRadio(LLUICtrl*, void* userdata) self->onCommit(); } -// static -LLPreview* LLPreview::find(const LLUUID& item_uuid) -{ - LLPreview* instance = NULL; - preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid); - if(found_it != LLPreview::sInstances.end()) - { - instance = found_it->second; - } - return instance; -} - -// static -LLPreview* LLPreview::show( const LLUUID& item_uuid, BOOL take_focus ) -{ - LLPreview* instance = LLPreview::find(item_uuid); - if(instance) - { - if (LLFloater::getFloaterHost() && LLFloater::getFloaterHost() != instance->getHost()) - { - // this preview window is being opened in a new context - // needs to be rehosted - LLFloater::getFloaterHost()->addFloater(instance, TRUE); - } - instance->open(); /*Flawfinder: ignore*/ - if (take_focus) - { - instance->setFocus(TRUE); - } - } - - return instance; -} - -// static -bool LLPreview::save( const LLUUID& item_uuid, LLPointer* itemptr ) -{ - bool res = false; - LLPreview* instance = LLPreview::find(item_uuid); - if(instance) - { - res = instance->saveItem(itemptr); - } - if (!res) - { - delete itemptr; - } - return res; -} - // static void LLPreview::hide(const LLUUID& item_uuid, BOOL no_saving /* = FALSE */ ) { - preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid); - if(found_it != LLPreview::sInstances.end()) + LLFloater* floater = LLFloaterReg::findInstance("preview", LLSD(item_uuid)); + if (!floater) floater = LLFloaterReg::findInstance("preview_avatar", LLSD(item_uuid)); + + LLPreview* preview = dynamic_cast(floater); + if (preview) { - LLPreview* instance = found_it->second; - if ( no_saving ) { - instance->mForceClose = TRUE; + preview->mForceClose = TRUE; } - - instance->close(); + preview->closeFloater(); } } // static -void LLPreview::rename(const LLUUID& item_uuid, const std::string& new_name) +void LLPreview::dirty(const LLUUID& item_uuid) { - preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid); - if(found_it != LLPreview::sInstances.end()) + LLFloater* floater = LLFloaterReg::findInstance("preview", LLSD(item_uuid)); + if (!floater) floater = LLFloaterReg::findInstance("preview_avatar", LLSD(item_uuid)); + + LLPreview* preview = dynamic_cast(floater); + if(preview) { - LLPreview* instance = found_it->second; - instance->setTitle( new_name ); + preview->mDirty = TRUE; } } @@ -397,7 +308,7 @@ BOOL LLPreview::handleHover(S32 x, S32 y, MASK mask) { S32 screen_x; S32 screen_y; - const LLViewerInventoryItem *item = getItem(); + const LLInventoryItem *item = getItem(); localPointToScreen(x, y, &screen_x, &screen_y ); if(item @@ -426,22 +337,20 @@ BOOL LLPreview::handleHover(S32 x, S32 y, MASK mask) return LLFloater::handleHover(x,y,mask); } -void LLPreview::open() /*Flawfinder: ignore*/ +void LLPreview::onOpen(const LLSD& key) { if (!getFloaterHost() && !getHost() && getAssetStatus() == PREVIEW_ASSET_UNLOADED) { loadAsset(); } - LLFloater::open(); /*Flawfinder: ignore*/ } -// virtual -bool LLPreview::saveItem(LLPointer* itemptr) +void LLPreview::setAuxItem( const LLInventoryItem* item ) { - return false; + if ( mAuxItem ) + mAuxItem->copyItem(item); } - // static void LLPreview::onBtnCopyToInv(void* userdata) { @@ -453,7 +362,7 @@ void LLPreview::onBtnCopyToInv(void* userdata) // Copy to inventory if (self->mNotecardInventoryID.notNull()) { - copy_inventory_from_notecard(self->mObjectID, + copy_inventory_from_notecard(self->mNotecardObjectID, self->mNotecardInventoryID, item); } else @@ -468,14 +377,14 @@ void LLPreview::onBtnCopyToInv(void* userdata) cb); } } - self->close(); + self->closeFloater(); } // static void LLPreview::onKeepBtn(void* data) { LLPreview* self = (LLPreview*)data; - self->close(); + self->closeFloater(); } // static @@ -483,11 +392,11 @@ void LLPreview::onDiscardBtn(void* data) { LLPreview* self = (LLPreview*)data; - const LLViewerInventoryItem* item = self->getItem(); + const LLInventoryItem* item = self->getItem(); if (!item) return; self->mForceClose = TRUE; - self->close(); + self->closeFloater(); // Delete the item entirely /* @@ -517,55 +426,60 @@ void LLPreview::onDiscardBtn(void* data) } } -//static -LLPreview* LLPreview::getFirstPreviewForSource(const LLUUID& source_id) +void LLPreview::handleReshape(const LLRect& new_rect, bool by_user) { - preview_multimap_t::iterator found_it = sPreviewsBySource.find(source_id); - if (found_it != sPreviewsBySource.end()) - { - // just return first one - return (LLPreview*)found_it->second.get(); - } - return NULL; -} - -void LLPreview::userSetShape(const LLRect& new_rect) -{ - if(new_rect.getWidth() != getRect().getWidth() || new_rect.getHeight() != getRect().getHeight()) + if(by_user + && (new_rect.getWidth() != getRect().getWidth() || new_rect.getHeight() != getRect().getHeight())) { userResized(); } - LLFloater::userSetShape(new_rect); + LLFloater::handleReshape(new_rect, by_user); } // // LLMultiPreview // -LLMultiPreview::LLMultiPreview(const LLRect& rect) : LLMultiFloater(std::string("Preview"), rect) +LLMultiPreview::LLMultiPreview() + : LLMultiFloater(LLSD()) { + // *TODO: There should be a .xml file for this + const LLRect& nextrect = LLFloaterReg::getFloaterRect("preview"); // place where the next preview should show up + if (nextrect.getWidth() > 0) + { + setRect(nextrect); + } + else + { + // start with a rect in the top-left corner ; will get resized + LLRect rect; + rect.setLeftTopAndSize(0, gViewerWindow->getWindowHeight(), 200, 200); + setRect(rect); + } + setTitle(LLTrans::getString("MultiPreviewTitle")); + buildTabContainer(); setCanResize(TRUE); } -void LLMultiPreview::open() /*Flawfinder: ignore*/ +void LLMultiPreview::onOpen(const LLSD& key) { - LLMultiFloater::open(); /*Flawfinder: ignore*/ LLPreview* frontmost_preview = (LLPreview*)mTabContainer->getCurrentPanel(); if (frontmost_preview && frontmost_preview->getAssetStatus() == LLPreview::PREVIEW_ASSET_UNLOADED) { frontmost_preview->loadAsset(); } + LLMultiFloater::onOpen(key); } -void LLMultiPreview::userSetShape(const LLRect& new_rect) +void LLMultiPreview::handleReshape(const LLRect& new_rect, bool by_user) { if(new_rect.getWidth() != getRect().getWidth() || new_rect.getHeight() != getRect().getHeight()) { LLPreview* frontmost_preview = (LLPreview*)mTabContainer->getCurrentPanel(); if (frontmost_preview) frontmost_preview->userResized(); } - LLFloater::userSetShape(new_rect); + LLFloater::handleReshape(new_rect, by_user); } @@ -578,22 +492,3 @@ void LLMultiPreview::tabOpen(LLFloater* opened_floater, bool from_click) } } -//static -LLMultiPreview* LLMultiPreview::getAutoOpenInstance(const LLUUID& id) -{ - handle_map_t::iterator found_it = sAutoOpenPreviewHandles.find(id); - if (found_it != sAutoOpenPreviewHandles.end()) - { - return (LLMultiPreview*)found_it->second.get(); - } - return NULL; -} - -//static -void LLMultiPreview::setAutoOpenInstance(LLMultiPreview* previewp, const LLUUID& id) -{ - if (previewp) - { - sAutoOpenPreviewHandles[id] = previewp->getHandle(); - } -} diff --git a/indra/newview/llpreview.h b/indra/newview/llpreview.h index ff084bea27..c5f2bfcf47 100644 --- a/indra/newview/llpreview.h +++ b/indra/newview/llpreview.h @@ -33,15 +33,14 @@ #ifndef LL_LLPREVIEW_H #define LL_LLPREVIEW_H -#include "llfloater.h" +#include "llmultifloater.h" #include "llresizehandle.h" -#include "llmap.h" +#include "llpointer.h" #include "lluuid.h" -#include "llviewerinventory.h" -#include "lltabcontainer.h" -#include "llinventorymodel.h" +#include "llinventorymodel.h" // LLInventoryObserver #include +class LLInventoryItem; class LLLineEditor; class LLRadioGroup; class LLPreview; @@ -49,18 +48,12 @@ class LLPreview; class LLMultiPreview : public LLMultiFloater { public: - LLMultiPreview(const LLRect& rect); + LLMultiPreview(); - /*virtual*/void open(); /*Flawfinder: ignore*/ + /*virtual*/void onOpen(const LLSD& key); /*virtual*/void tabOpen(LLFloater* opened_floater, bool from_click); - /*virtual*/ void userSetShape(const LLRect& new_rect); + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); - static LLMultiPreview* getAutoOpenInstance(const LLUUID& id); - static void setAutoOpenInstance(LLMultiPreview* previewp, const LLUUID& id); - -protected: - typedef std::map > handle_map_t; - static handle_map_t sAutoOpenPreviewHandles; }; // https://wiki.lindenlab.com/mediawiki/index.php?title=LLPreview&oldid=81373 @@ -76,40 +69,32 @@ public: PREVIEW_ASSET_LOADED } EAssetStatus; public: - // Used for XML-based construction. - LLPreview(const std::string& name); - LLPreview(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid, BOOL allow_resize = FALSE, S32 min_width = 0, S32 min_height = 0, LLPointer inv_item = NULL ); + LLPreview(const LLSD& key ); virtual ~LLPreview(); - - void setItemID(const LLUUID& item_id); + + /*virtual*/ BOOL postBuild(); + void setObjectID(const LLUUID& object_id); - void setSourceID(const LLUUID& source_id); - const LLViewerInventoryItem *getItem() const; // searches if not constructed with it - - static LLPreview* find(const LLUUID& item_uuid); - static LLPreview* show(const LLUUID& item_uuid, BOOL take_focus = TRUE ); - static void hide(const LLUUID& item_uuid, BOOL no_saving = FALSE ); - static void rename(const LLUUID& item_uuid, const std::string& new_name); - static bool save(const LLUUID& item_uuid, LLPointer* itemptr); + void setItem( LLInventoryItem* item ); + + const LLInventoryItem* getItem() const; // searches if not constructed with it + static void hide(const LLUUID& item_uuid, BOOL no_saving = FALSE ); + static void dirty(const LLUUID& item_uuid); + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual void open(); /*Flawfinder: ignore*/ - virtual bool saveItem(LLPointer* itemptr); - - void setAuxItem( const LLInventoryItem* item ) - { - if ( mAuxItem ) - mAuxItem->copyItem(item); - } + virtual void onOpen(const LLSD& key); + + void setAuxItem( const LLInventoryItem* item ); static void onBtnCopyToInv(void* userdata); void addKeepDiscardButtons(); static void onKeepBtn(void* data); static void onDiscardBtn(void* data); - /*virtual*/ void userSetShape(const LLRect& new_rect); + /*virtual*/ void handleReshape(const LLRect& new_rect, bool by_user = false); void userResized() { mUserResized = TRUE; }; @@ -117,12 +102,13 @@ public: virtual EAssetStatus getAssetStatus() { return mAssetStatus;} static LLPreview* getFirstPreviewForSource(const LLUUID& source_id); - void setNotecardInfo(const LLUUID& notecard_inv_id, const LLUUID& object_id) - { mNotecardInventoryID = notecard_inv_id; mObjectID = object_id; } + + // Why is this at the LLPreview level? JC + void setNotecardInfo(const LLUUID& notecard_inv_id, const LLUUID& object_id); // llview - virtual void draw(); - void refreshFromItem(const LLInventoryItem* item); + /*virtual*/ void draw(); + void refreshFromItem(); protected: virtual void onCommit(); @@ -135,13 +121,11 @@ protected: // for LLInventoryObserver virtual void changed(U32 mask); BOOL mDirty; - virtual const char *getTitleName() const { return "Preview"; } protected: LLUUID mItemUUID; - LLUUID mSourceID; - // mObjectID will have a value if it is associated with a task in + // mObjectUUID will have a value if it is associated with a task in // the world, and will be == LLUUID::null if it's in the agent // inventory. LLUUID mObjectUUID; @@ -149,6 +133,7 @@ protected: LLRect mClientRect; LLPointer mAuxItem; // HACK! + LLPointer mItem; // For embedded items (Landmarks) LLButton* mCopyToInvBtn; // Close without saving changes @@ -162,27 +147,20 @@ protected: EAssetStatus mAssetStatus; - typedef std::map preview_map_t; - typedef std::multimap > preview_multimap_t; - - static preview_multimap_t sPreviewsBySource; - static preview_map_t sInstances; LLUUID mNotecardInventoryID; - LLUUID mObjectID; - LLPointer mItem; + // I am unsure if this is always the same as mObjectUUID, or why it exists + // at the LLPreview level. JC 2009-06-24 + LLUUID mNotecardObjectID; }; const S32 PREVIEW_BORDER = 4; const S32 PREVIEW_PAD = 5; -const S32 PREVIEW_BUTTON_WIDTH = 100; const S32 PREVIEW_LINE_HEIGHT = 19; -const S32 PREVIEW_CLOSE_BOX_SIZE = 16; const S32 PREVIEW_BORDER_WIDTH = 2; const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH; const S32 PREVIEW_VPAD = 2; -const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE; const S32 PREVIEW_HEADER_SIZE = 2*PREVIEW_LINE_HEIGHT + 2 * PREVIEW_VPAD; #endif // LL_LLPREVIEW_H diff --git a/indra/newview/llpreviewanim.cpp b/indra/newview/llpreviewanim.cpp index 3212de0639..3bda30e0c6 100644 --- a/indra/newview/llpreviewanim.cpp +++ b/indra/newview/llpreviewanim.cpp @@ -36,8 +36,7 @@ #include "llbutton.h" #include "llresmgr.h" #include "llinventory.h" -#include "llinventoryview.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llagent.h" // gAgent #include "llkeyframemotion.h" #include "llfilepicker.h" @@ -47,51 +46,10 @@ extern LLAgent gAgent; -LLPreviewAnim::LLPreviewAnim(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const S32& activate, const LLUUID& object_uuid ) : - LLPreview( name, rect, title, item_uuid, object_uuid) +LLPreviewAnim::LLPreviewAnim(const LLSD& key) + : LLPreview( key ) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_animation.xml"); - - childSetAction("Anim play btn",playAnim,this); - childSetAction("Anim audition btn",auditionAnim,this); - - const LLInventoryItem* item = getItem(); - - childSetCommitCallback("desc", LLPreview::onText, this); - childSetText("desc", item->getDescription()); - childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); - - setTitle(title); - - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } - - // preload the animation - if(item) - { - gAgent.getAvatarObject()->createMotion(item->getAssetUUID()); - } - - switch ( activate ) - { - case 1: - { - playAnim( (void *) this ); - break; - } - case 2: - { - auditionAnim( (void *) this ); - break; - } - default: - { - //do nothing - } - } + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_animation.xml", FALSE); } // static @@ -107,6 +65,48 @@ void LLPreviewAnim::endAnimCallback( void *userdata ) } } +// virtual +BOOL LLPreviewAnim::postBuild() +{ + mCloseSignal.connect(boost::bind(&LLPreviewAnim::onClose, this)); + + const LLInventoryItem* item = getItem(); + if(item) + { + gAgent.getAvatarObject()->createMotion(item->getAssetUUID()); // preload the animation + childSetText("desc", item->getDescription()); + } + + childSetAction("Anim play btn",playAnim, this); + childSetAction("Anim audition btn",auditionAnim, this); + + childSetCommitCallback("desc", LLPreview::onText, this); + childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); + + return LLPreview::postBuild(); +} + +void LLPreviewAnim::activate(e_activation_type type) +{ + switch ( type ) + { + case PLAY: + { + playAnim( (void *) this ); + break; + } + case AUDITION: + { + auditionAnim( (void *) this ); + break; + } + default: + { + //do nothing + } + } +} + // static void LLPreviewAnim::playAnim( void *userdata ) { @@ -181,7 +181,7 @@ void LLPreviewAnim::auditionAnim( void *userdata ) } } -void LLPreviewAnim::onClose(bool app_quitting) +void LLPreviewAnim::onClose() { const LLInventoryItem *item = getItem(); @@ -199,5 +199,4 @@ void LLPreviewAnim::onClose(bool app_quitting) motion->setDeactivateCallback(NULL, (void *)NULL); } } - destroy(); } diff --git a/indra/newview/llpreviewanim.h b/indra/newview/llpreviewanim.h index fe794d4283..d24e624c32 100644 --- a/indra/newview/llpreviewanim.h +++ b/indra/newview/llpreviewanim.h @@ -39,18 +39,17 @@ class LLPreviewAnim : public LLPreview { public: - LLPreviewAnim(const std::string& name, const LLRect& rect, const std::string& title, - const LLUUID& item_uuid, - const S32& activate, - const LLUUID& object_uuid = LLUUID::null); + enum e_activation_type { NONE = 0, PLAY = 1, AUDITION = 2 }; + LLPreviewAnim(const LLSD& key); static void playAnim( void* userdata ); static void auditionAnim( void* userdata ); static void endAnimCallback( void *userdata ); - + /*virtual*/ BOOL postBuild(); + void activate(e_activation_type type); + protected: - virtual void onClose(bool app_quitting); - virtual const char *getTitleName() const { return "Animation"; } + void onClose(); LLAnimPauseRequest mPauseRequest; LLUUID mItemID; diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 76a9b80645..04827e3a78 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -41,11 +41,13 @@ #include "lldarray.h" #include "llstring.h" #include "lldir.h" +#include "llfloaterreg.h" #include "llmultigesture.h" #include "llvfile.h" // newview #include "llagent.h" // todo: remove +#include "llanimationstates.h" #include "llassetuploadresponders.h" #include "llbutton.h" #include "llcheckboxctrl.h" @@ -59,6 +61,8 @@ #include "llnotify.h" #include "llradiogroup.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "lltextbox.h" #include "lluictrlfactory.h" #include "llviewerinventory.h" @@ -67,15 +71,16 @@ #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" // busycount +#include "llvoavatarself.h" #include "llappviewer.h" // gVFS #include "llanimstatelabels.h" #include "llresmgr.h" +#include "lltrans.h" -// *TODO: Translate? -const std::string NONE_LABEL = "---"; -const std::string SHIFT_LABEL = "Shift"; -const std::string CTRL_LABEL = "Ctrl"; +std::string NONE_LABEL; +std::string SHIFT_LABEL; +std::string CTRL_LABEL; void dialog_refresh_all(); @@ -92,12 +97,9 @@ protected: void LLInventoryGestureAvailable::done() { - LLPreview* preview = NULL; - item_ref_t::iterator it = mComplete.begin(); - item_ref_t::iterator end = mComplete.end(); - for(; it < end; ++it) + for(item_ref_t::iterator it = mComplete.begin(); it != mComplete.end(); ++it) { - preview = LLPreview::find((*it)); + LLPreviewGesture* preview = LLFloaterReg::findTypedInstance("preview_gesture", *it); if(preview) { preview->refresh(); @@ -117,43 +119,16 @@ struct SortItemPtrsByName }; // static -LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus) +LLPreviewGesture* LLPreviewGesture::show(const LLUUID& item_id, const LLUUID& object_id) { - LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(item_id); - if (previewp) + LLPreviewGesture* preview = LLFloaterReg::showTypedInstance("preview_gesture", LLSD(item_id), TAKE_FOCUS_YES); + if (!preview) { - previewp->open(); /*Flawfinder: ignore*/ - if (take_focus) - { - previewp->setFocus(TRUE); - } - return previewp; + return NULL; } - - LLPreviewGesture* self = new LLPreviewGesture(); - - // Finish internal construction - self->init(item_id, object_id); - - // Builds and adds to gFloaterView - LLUICtrlFactory::getInstance()->buildFloater(self, "floater_preview_gesture.xml"); - self->setTitle(title); - - // Move window to top-left of screen - LLMultiFloater* hostp = self->getHost(); - if (hostp == NULL) - { - LLRect r = self->getRect(); - LLRect screen = gFloaterView->getRect(); - r.setLeftTopAndSize(0, screen.getHeight(), r.getWidth(), r.getHeight()); - self->setRect(r); - } - else - { - // re-add to host to update title - hostp->addFloater(self, TRUE); - } - + + preview->setObjectID(object_id); + // Start speculative download of sounds and animations LLUUID animation_folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_ANIMATION); gInventory.startBackgroundFetch(animation_folder_id); @@ -162,8 +137,8 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& gInventory.startBackgroundFetch(sound_folder_id); // this will call refresh when we have everything. - LLViewerInventoryItem* item = (LLViewerInventoryItem*)self->getItem(); - if(item && !item->isComplete()) + LLViewerInventoryItem* item = (LLViewerInventoryItem*)preview->getItem(); + if (item && !item->isComplete()) { LLInventoryGestureAvailable* observer; observer = new LLInventoryGestureAvailable(); @@ -174,18 +149,12 @@ LLPreviewGesture* LLPreviewGesture::show(const std::string& title, const LLUUID& else { // not sure this is necessary. - self->refresh(); + preview->refresh(); } - if (take_focus) - { - self->setFocus(TRUE); - } - - return self; + return preview; } - // virtual BOOL LLPreviewGesture::handleKeyHere(KEY key, MASK mask) { @@ -291,11 +260,9 @@ BOOL LLPreviewGesture::canClose() } } -// virtual -void LLPreviewGesture::onClose(bool app_quitting) +void LLPreviewGesture::onClose() { - gGestureManager.stopGesture(mPreviewGesture); - LLPreview::onClose(app_quitting); + LLGestureManager::instance().stopGesture(mPreviewGesture); } // virtual @@ -304,18 +271,11 @@ void LLPreviewGesture::onUpdateSucceeded() refresh(); } -// virtual -void LLPreviewGesture::setMinimized(BOOL minimize) +void LLPreviewGesture::onVisibilityChange ( const LLSD& new_visibility ) { - if (minimize != isMinimized()) + if (new_visibility.asBoolean()) { - LLFloater::setMinimized(minimize); - - // We're being restored - if (!minimize) - { - refresh(); - } + refresh(); } } @@ -326,15 +286,15 @@ bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const L switch(option) { case 0: // "Yes" - gGestureManager.stopGesture(mPreviewGesture); + LLGestureManager::instance().stopGesture(mPreviewGesture); mCloseAfterSave = TRUE; onClickSave(this); break; case 1: // "No" - gGestureManager.stopGesture(mPreviewGesture); + LLGestureManager::instance().stopGesture(mPreviewGesture); mDirty = FALSE; // Force the dirty flag because user has clicked NO on confirm save dialog... - close(); + closeFloater(); break; case 2: // "Cancel" @@ -347,8 +307,8 @@ bool LLPreviewGesture::handleSaveChangesDialog(const LLSD& notification, const L } -LLPreviewGesture::LLPreviewGesture() -: LLPreview("Gesture Preview"), +LLPreviewGesture::LLPreviewGesture(const LLSD& key) +: LLPreview(key), mTriggerEditor(NULL), mModifierCombo(NULL), mKeyCombo(NULL), @@ -368,6 +328,12 @@ LLPreviewGesture::LLPreviewGesture() mPreviewGesture(NULL), mDirty(FALSE) { + NONE_LABEL = LLTrans::getString("---"); + SHIFT_LABEL = LLTrans::getString("KBShift"); + CTRL_LABEL = LLTrans::getString("KBCtrl"); + + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_gesture.xml", FALSE); + } @@ -388,6 +354,9 @@ LLPreviewGesture::~LLPreviewGesture() BOOL LLPreviewGesture::postBuild() { + mCloseSignal.connect(boost::bind(&LLPreviewGesture::onClose, this)); + mVisibleSignal.connect(boost::bind(&LLPreviewGesture::onVisibilityChange, this, _2)); + LLLineEditor* edit; LLComboBox* combo; LLButton* btn; @@ -396,10 +365,9 @@ BOOL LLPreviewGesture::postBuild() LLCheckBoxCtrl* check; edit = getChild("trigger_editor"); - edit->setKeystrokeCallback(onKeystrokeCommit); - edit->setCommitCallback(onCommitSetDirty); + edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitCallback(onCommitSetDirty, this); edit->setCommitOnFocusLost(TRUE); - edit->setCallbackUserData(this); edit->setIgnoreTab(TRUE); mTriggerEditor = edit; @@ -409,56 +377,47 @@ BOOL LLPreviewGesture::postBuild() edit = getChild("replace_editor"); edit->setEnabled(FALSE); - edit->setKeystrokeCallback(onKeystrokeCommit); - edit->setCommitCallback(onCommitSetDirty); + edit->setKeystrokeCallback(onKeystrokeCommit, this); + edit->setCommitCallback(onCommitSetDirty, this); edit->setCommitOnFocusLost(TRUE); - edit->setCallbackUserData(this); edit->setIgnoreTab(TRUE); mReplaceEditor = edit; combo = getChild( "modifier_combo"); - combo->setCommitCallback(onCommitSetDirty); - combo->setCallbackUserData(this); + combo->setCommitCallback(onCommitSetDirty, this); mModifierCombo = combo; combo = getChild( "key_combo"); - combo->setCommitCallback(onCommitSetDirty); - combo->setCallbackUserData(this); + combo->setCommitCallback(onCommitSetDirty, this); mKeyCombo = combo; list = getChild("library_list"); - list->setCommitCallback(onCommitLibrary); - list->setDoubleClickCallback(onClickAdd); - list->setCallbackUserData(this); + list->setCommitCallback(onCommitLibrary, this); + list->setDoubleClickCallback(onClickAdd, this); mLibraryList = list; btn = getChild( "add_btn"); - btn->setClickedCallback(onClickAdd); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickAdd, this); btn->setEnabled(FALSE); mAddBtn = btn; btn = getChild( "up_btn"); - btn->setClickedCallback(onClickUp); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickUp, this); btn->setEnabled(FALSE); mUpBtn = btn; btn = getChild( "down_btn"); - btn->setClickedCallback(onClickDown); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickDown, this); btn->setEnabled(FALSE); mDownBtn = btn; btn = getChild( "delete_btn"); - btn->setClickedCallback(onClickDelete); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickDelete, this); btn->setEnabled(FALSE); mDeleteBtn = btn; list = getChild("step_list"); - list->setCommitCallback(onCommitStep); - list->setCallbackUserData(this); + list->setCommitCallback(onCommitStep, this); mStepList = list; // Options @@ -468,69 +427,59 @@ BOOL LLPreviewGesture::postBuild() combo = getChild( "animation_list"); combo->setVisible(FALSE); - combo->setCommitCallback(onCommitAnimation); - combo->setCallbackUserData(this); + combo->setCommitCallback(onCommitAnimation, this); mAnimationCombo = combo; LLRadioGroup* group; group = getChild("animation_trigger_type"); group->setVisible(FALSE); - group->setCommitCallback(onCommitAnimationTrigger); - group->setCallbackUserData(this); + group->setCommitCallback(onCommitAnimationTrigger, this); mAnimationRadio = group; combo = getChild( "sound_list"); combo->setVisible(FALSE); - combo->setCommitCallback(onCommitSound); - combo->setCallbackUserData(this); + combo->setCommitCallback(onCommitSound, this); mSoundCombo = combo; edit = getChild("chat_editor"); edit->setVisible(FALSE); - edit->setCommitCallback(onCommitChat); - //edit->setKeystrokeCallback(onKeystrokeCommit); + edit->setCommitCallback(onCommitChat, this); + //edit->setKeystrokeCallback(onKeystrokeCommit, this); edit->setCommitOnFocusLost(TRUE); - edit->setCallbackUserData(this); edit->setIgnoreTab(TRUE); mChatEditor = edit; check = getChild( "wait_anim_check"); check->setVisible(FALSE); - check->setCommitCallback(onCommitWait); - check->setCallbackUserData(this); + check->setCommitCallback(onCommitWait, this); mWaitAnimCheck = check; check = getChild( "wait_time_check"); check->setVisible(FALSE); - check->setCommitCallback(onCommitWait); - check->setCallbackUserData(this); + check->setCommitCallback(onCommitWait, this); mWaitTimeCheck = check; edit = getChild("wait_time_editor"); edit->setEnabled(FALSE); edit->setVisible(FALSE); edit->setPrevalidate(LLLineEditor::prevalidateFloat); -// edit->setKeystrokeCallback(onKeystrokeCommit); +// edit->setKeystrokeCallback(onKeystrokeCommit, this); edit->setCommitOnFocusLost(TRUE); - edit->setCommitCallback(onCommitWaitTime); - edit->setCallbackUserData(this); + edit->setCommitCallback(onCommitWaitTime, this); edit->setIgnoreTab(TRUE); mWaitTimeEditor = edit; // Buttons at the bottom check = getChild( "active_check"); - check->setCommitCallback(onCommitActive); - check->setCallbackUserData(this); + check->setCommitCallback(onCommitActive, this); mActiveCheck = check; btn = getChild( "save_btn"); - btn->setClickedCallback(onClickSave); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickSave, this); mSaveBtn = btn; btn = getChild( "preview_btn"); - btn->setClickedCallback(onClickPreview); - btn->setCallbackUserData(this); + btn->setClickedCallback(onClickPreview, this); mPreviewBtn = btn; @@ -540,7 +489,6 @@ BOOL LLPreviewGesture::postBuild() addAnimations(); addSounds(); - const LLInventoryItem* item = getItem(); if (item) @@ -550,7 +498,7 @@ BOOL LLPreviewGesture::postBuild() childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); } - return TRUE; + return LLPreview::postBuild(); } @@ -605,7 +553,7 @@ void LLPreviewGesture::addAnimations() PERM_ITEM_UNRESTRICTED, gAgent.getID(), gAgent.getGroupID()); - gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items, LLInventoryModel::EXCLUDE_TRASH, @@ -650,7 +598,7 @@ void LLPreviewGesture::addSounds() PERM_ITEM_UNRESTRICTED, gAgent.getID(), gAgent.getGroupID()); - gInventory.collectDescendentsIf(gAgent.getInventoryRootID(), + gInventory.collectDescendentsIf(gInventory.getRootFolderID(), cats, items, LLInventoryModel::EXCLUDE_TRASH, @@ -680,16 +628,9 @@ void LLPreviewGesture::addSounds() } -void LLPreviewGesture::init(const LLUUID& item_id, const LLUUID& object_id) -{ - // Sets ID and adds to instance list - setItemID(item_id); - setObjectID(object_id); -} - - void LLPreviewGesture::refresh() { + LLPreview::refresh(); // If previewing or item is incomplete, all controls are disabled LLViewerInventoryItem* item = (LLViewerInventoryItem*)getItem(); bool is_complete = (item && item->isComplete()) ? true : false; @@ -831,7 +772,7 @@ void LLPreviewGesture::refresh() mOptionsText->setText(optionstext); - BOOL active = gGestureManager.isGestureActive(mItemUUID); + BOOL active = LLGestureManager::instance().isGestureActive(mItemUUID); mActiveCheck->set(active); // Can only preview if there are steps @@ -850,7 +791,7 @@ void LLPreviewGesture::initDefaultGesture() item = addStep( STEP_ANIMATION ); LLGestureStepAnimation* anim = (LLGestureStepAnimation*)item->getUserdata(); anim->mAnimAssetID = ANIM_AGENT_HELLO; - anim->mAnimName = "Wave"; + anim->mAnimName = LLTrans::getString("Wave"); updateLabel(item); item = addStep( STEP_WAIT ); @@ -860,7 +801,7 @@ void LLPreviewGesture::initDefaultGesture() item = addStep( STEP_CHAT ); LLGestureStepChat* chat_step = (LLGestureStepChat*)item->getUserdata(); - chat_step->mChatText = "Hello, avatar!"; + chat_step->mChatText = LLTrans::getString("HelloAvatar"); updateLabel(item); // Start with item list selected @@ -874,7 +815,11 @@ void LLPreviewGesture::initDefaultGesture() void LLPreviewGesture::loadAsset() { const LLInventoryItem* item = getItem(); - if (!item) return; + if (!item) + { + mAssetStatus = PREVIEW_ASSET_ERROR; + return; + } LLUUID asset_id = item->getAssetUUID(); if (asset_id.isNull()) @@ -883,6 +828,7 @@ void LLPreviewGesture::loadAsset() // Blank gesture will be fine. initDefaultGesture(); refresh(); + mAssetStatus = PREVIEW_ASSET_LOADED; return; } @@ -910,11 +856,10 @@ void LLPreviewGesture::onLoadComplete(LLVFS *vfs, void* user_data, S32 status, LLExtStat ext_status) { LLUUID* item_idp = (LLUUID*)user_data; - LLPreview* preview = LLPreview::find(*item_idp); - if (preview) - { - LLPreviewGesture* self = (LLPreviewGesture*)preview; + LLPreviewGesture* self = LLFloaterReg::findTypedInstance("preview_gesture", *item_idp); + if (self) + { if (0 == status) { LLVFile file(vfs, asset_uuid, type, LLVFile::READ); @@ -1016,7 +961,7 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture) LLGestureStep* step = gesture->mSteps[i]; LLGestureStep* new_step = NULL; - + switch(step->getType()) { case STEP_ANIMATION: @@ -1061,7 +1006,7 @@ void LLPreviewGesture::loadUIFromGesture(LLMultiGesture* gesture) // Create an enabled item with this step LLSD row; - row["columns"][0]["value"] = new_step->getLabel(); + row["columns"][0]["value"] = getLabel( new_step->getLabel()); row["columns"][0]["font"] = "SANSSERIF_SMALL"; LLScrollListItem* item = mStepList->addElement(row); item->setUserdata(new_step); @@ -1179,10 +1124,10 @@ void LLPreviewGesture::saveIfNeeded() // If this gesture is active, then we need to update the in-memory // active map with the new pointer. - if (!delayedUpload && gGestureManager.isGestureActive(mItemUUID)) + if (!delayedUpload && LLGestureManager::instance().isGestureActive(mItemUUID)) { // gesture manager now owns the pointer - gGestureManager.replaceGesture(mItemUUID, gesture, asset_id); + LLGestureManager::instance().replaceGesture(mItemUUID, gesture, asset_id); // replaceGesture may deactivate other gestures so let the // inventory know. @@ -1262,10 +1207,10 @@ void LLPreviewGesture::onSaveComplete(const LLUUID& asset_uuid, void* user_data, } // Find our window and close it if requested. - LLPreviewGesture* previewp = (LLPreviewGesture*)LLPreview::find(info->mItemUUID); + LLPreviewGesture* previewp = LLFloaterReg::findTypedInstance("preview_gesture", info->mItemUUID); if (previewp && previewp->mCloseAfterSave) { - previewp->close(); + previewp->closeFloater(); } } else @@ -1374,7 +1319,7 @@ void LLPreviewGesture::updateLabel(LLScrollListItem* item) LLScrollListCell* cell = item->getColumn(0); LLScrollListText* text_cell = (LLScrollListText*)cell; - std::string label = step->getLabel(); + std::string label = getLabel( step->getLabel()); text_cell->setText(label); } @@ -1619,24 +1564,26 @@ LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) { case STEP_ANIMATION: step = new LLGestureStepAnimation(); + break; case STEP_SOUND: step = new LLGestureStepSound(); break; case STEP_CHAT: - step = new LLGestureStepChat(); + step = new LLGestureStepChat(); break; case STEP_WAIT: - step = new LLGestureStepWait(); + step = new LLGestureStepWait(); break; default: llerrs << "Unknown step type: " << (S32)step_type << llendl; return NULL; } + // Create an enabled item with this step LLSD row; - row["columns"][0]["value"] = step->getLabel(); + row["columns"][0]["value"] = getLabel(step->getLabel()); row["columns"][0]["font"] = "SANSSERIF_SMALL"; LLScrollListItem* step_item = mStepList->addElement(row); step_item->setUserdata(step); @@ -1650,6 +1597,42 @@ LLScrollListItem* LLPreviewGesture::addStep( const EStepType step_type ) return step_item; } +// static +std::string LLPreviewGesture::getLabel(std::vector labels) +{ + std::vector v_labels = labels ; + std::string result(""); + + if( v_labels.size() != 2) + { + return result; + } + + if(v_labels[0]=="Chat") + { + result=LLTrans::getString("Chat"); + } + else if(v_labels[0]=="Sound") + { + result=LLTrans::getString("Sound"); + } + else if(v_labels[0]=="Wait") + { + result=LLTrans::getString("Wait"); + } + else if(v_labels[0]=="AnimFlagStop") + { + result=LLTrans::getString("AnimFlagStop"); + } + else if(v_labels[0]=="AnimFlagStart") + { + result=LLTrans::getString("AnimFlagStart"); + } + + result.append(v_labels[1]); + return result; + +} // static void LLPreviewGesture::onClickUp(void* data) { @@ -1705,13 +1688,13 @@ void LLPreviewGesture::onClickDelete(void* data) void LLPreviewGesture::onCommitActive(LLUICtrl* ctrl, void* data) { LLPreviewGesture* self = (LLPreviewGesture*)data; - if (!gGestureManager.isGestureActive(self->mItemUUID)) + if (!LLGestureManager::instance().isGestureActive(self->mItemUUID)) { - gGestureManager.activateGesture(self->mItemUUID); + LLGestureManager::instance().activateGesture(self->mItemUUID); } else { - gGestureManager.deactivateGesture(self->mItemUUID); + LLGestureManager::instance().deactivateGesture(self->mItemUUID); } // Make sure the (active) label in the inventory gets updated. @@ -1750,14 +1733,14 @@ void LLPreviewGesture::onClickPreview(void* data) self->mPreviewBtn->setLabel(self->getString("stop_txt")); // play it, and delete when done - gGestureManager.playGesture(self->mPreviewGesture); + LLGestureManager::instance().playGesture(self->mPreviewGesture); self->refresh(); } else { // Will call onDonePreview() below - gGestureManager.stopGesture(self->mPreviewGesture); + LLGestureManager::instance().stopGesture(self->mPreviewGesture); self->refresh(); } diff --git a/indra/newview/llpreviewgesture.h b/indra/newview/llpreviewgesture.h index c245c0e8da..16ac935775 100644 --- a/indra/newview/llpreviewgesture.h +++ b/indra/newview/llpreviewgesture.h @@ -52,40 +52,36 @@ class LLPreviewGesture : public LLPreview public: // Pass an object_id if this gesture is inside an object in the world, // otherwise use LLUUID::null. - static LLPreviewGesture* show(const std::string& title, const LLUUID& item_id, const LLUUID& object_id, BOOL take_focus = TRUE); + static LLPreviewGesture* show(const LLUUID& item_id, const LLUUID& object_id); + + LLPreviewGesture(const LLSD& key); + virtual ~LLPreviewGesture(); // LLView - virtual BOOL handleKeyHere(KEY key, MASK mask); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, + /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); + /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void* cargo_data, EAcceptance* accept, std::string& tooltip_msg); // LLPanel - virtual BOOL postBuild(); + /*virtual*/ BOOL postBuild(); // LLFloater - virtual BOOL canClose(); - virtual void setMinimized(BOOL minimize); - virtual void onClose(bool app_quitting); - virtual void onUpdateSucceeded(); + /*virtual*/ BOOL canClose(); + /*virtual*/ void onUpdateSucceeded(); + /*virtual*/ void refresh(); + protected: - LLPreviewGesture(); - virtual ~LLPreviewGesture(); - - void init(const LLUUID& item_id, const LLUUID& object_id); - // Populate various comboboxes void addModifiers(); void addKeys(); void addAnimations(); void addSounds(); - void refresh(); - void initDefaultGesture(); void loadAsset(); @@ -111,7 +107,11 @@ protected: // Add a step. Pass the name of the step, like "Animation", // "Sound", "Chat", or "Wait" LLScrollListItem* addStep(const enum EStepType step_type); - + + void onClose(); + void onVisibilityChange ( const LLSD& new_visibility ); + + static std::string getLabel(std::vector labels); static void updateLabel(LLScrollListItem* item); static void onCommitSetDirty(LLUICtrl* ctrl, void* data); @@ -139,8 +139,6 @@ protected: static void onDonePreview(LLMultiGesture* gesture, void* data); - virtual const char *getTitleName() const { return "Gesture"; } - protected: // LLPreview contains mDescEditor LLLineEditor* mTriggerEditor; diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 4abe390bc5..cadab71ba8 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -40,6 +40,7 @@ #include "llassetuploadresponders.h" #include "llviewerwindow.h" #include "llbutton.h" +#include "llfloaterreg.h" #include "llinventorymodel.h" #include "lllineeditor.h" #include "llnotify.h" @@ -61,92 +62,20 @@ #include "lllineeditor.h" #include "lluictrlfactory.h" -///---------------------------------------------------------------------------- -/// Local function declarations, constants, enums, and typedefs -///---------------------------------------------------------------------------- - -const S32 PREVIEW_MIN_WIDTH = - 2 * PREVIEW_BORDER + - 2 * PREVIEW_BUTTON_WIDTH + - PREVIEW_PAD + RESIZE_HANDLE_WIDTH + - PREVIEW_PAD; -const S32 PREVIEW_MIN_HEIGHT = - 2 * PREVIEW_BORDER + - 3*(20 + PREVIEW_PAD) + - 2 * SCROLLBAR_SIZE + 128; - ///---------------------------------------------------------------------------- /// Class LLPreviewNotecard ///---------------------------------------------------------------------------- // Default constructor -LLPreviewNotecard::LLPreviewNotecard(const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& item_id, - const LLUUID& object_id, - const LLUUID& asset_id, - BOOL show_keep_discard, - LLPointer inv_item) : - LLPreview(name, rect, title, item_id, object_id, TRUE, - PREVIEW_MIN_WIDTH, - PREVIEW_MIN_HEIGHT, - inv_item), - mAssetID( asset_id ), - mNotecardItemID(item_id), - mObjectID(object_id) +LLPreviewNotecard::LLPreviewNotecard(const LLSD& key) //const LLUUID& item_id, + : LLPreview( key ) { - LLRect curRect = rect; - - if (show_keep_discard) - { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard_keep_discard.xml"); - childSetAction("Keep",onKeepBtn,this); - childSetAction("Discard",onDiscardBtn,this); - } - else - { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard.xml"); - childSetAction("Save",onClickSave,this); - - if( mAssetID.isNull() ) - { - const LLInventoryItem* item = getItem(); - if( item ) - { - mAssetID = item->getAssetUUID(); - } - } - } - - // only assert shape if not hosted in a multifloater - if (!getHost()) - { - reshape(curRect.getWidth(), curRect.getHeight(), TRUE); - setRect(curRect); - } - - childSetVisible("lock", FALSE); - - const LLInventoryItem* item = getItem(); - - childSetCommitCallback("desc", LLPreview::onText, this); + const LLInventoryItem *item = getItem(); if (item) - childSetText("desc", item->getDescription()); - childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); - - setTitle(title); - - LLViewerTextEditor* editor = getChild("Notecard Editor"); - - if (editor) { - editor->setWordWrap(TRUE); - editor->setSourceID(item_id); - editor->setHandleEditKeysDirectly(TRUE); - } - - gAgent.changeCameraToDefault(); + mAssetID = item->getAssetUUID(); + } + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_notecard.xml", FALSE); } LLPreviewNotecard::~LLPreviewNotecard() @@ -158,25 +87,27 @@ BOOL LLPreviewNotecard::postBuild() LLViewerTextEditor *ed = getChild("Notecard Editor"); if (ed) { - ed->setNotecardInfo(mNotecardItemID, mObjectID); + ed->setNotecardInfo(mItemUUID, mObjectID, getKey()); ed->makePristine(); } - return TRUE; + + childSetAction("Save", onClickSave, this); + childSetVisible("lock", FALSE); + + const LLInventoryItem* item = getItem(); + + childSetCommitCallback("desc", LLPreview::onText, this); + if (item) + childSetText("desc", item->getDescription()); + childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); + + return LLPreview::postBuild(); } -bool LLPreviewNotecard::saveItem(LLPointer* itemptr) +bool LLPreviewNotecard::saveItem() { - LLInventoryItem* item = NULL; - if (itemptr && itemptr->notNull()) - { - item = (LLInventoryItem*)(*itemptr); - } - bool res = saveIfNeeded(item); - if (res) - { - delete itemptr; - } - return res; + LLInventoryItem* item = gInventory.getItem(mItemUUID); + return saveIfNeeded(item); } void LLPreviewNotecard::setEnabled( BOOL enabled ) @@ -188,20 +119,15 @@ void LLPreviewNotecard::setEnabled( BOOL enabled ) childSetVisible("lock", !enabled); childSetEnabled("desc", enabled); childSetEnabled("Save", enabled && editor && (!editor->isPristine())); - } void LLPreviewNotecard::draw() { - - - //childSetFocus("Save", FALSE); - LLViewerTextEditor* editor = getChild("Notecard Editor"); - BOOL script_changed = !editor->isPristine(); + BOOL changed = !editor->isPristine(); - childSetEnabled("Save", script_changed && getEnabled()); + childSetEnabled("Save", changed && getEnabled()); LLPreview::draw(); } @@ -255,8 +181,13 @@ bool LLPreviewNotecard::hasEmbeddedInventory() return editor->hasEmbeddedInventory(); } -void LLPreviewNotecard::refreshFromInventory() +void LLPreviewNotecard::refreshFromInventory(const LLUUID& new_item_id) { + if (new_item_id.notNull()) + { + mItemUUID = new_item_id; + setKey(LLSD(new_item_id)); + } lldebugs << "LLPreviewNotecard::refreshFromInventory()" << llendl; loadAsset(); } @@ -287,7 +218,6 @@ void LLPreviewNotecard::loadAsset() } else { - LLUUID* new_uuid = new LLUUID(mItemUUID); LLHost source_sim = LLHost::invalid; if (mObjectUUID.notNull()) { @@ -305,7 +235,6 @@ void LLPreviewNotecard::loadAsset() editor->makePristine(); editor->setEnabled(FALSE); mAssetStatus = PREVIEW_ASSET_LOADED; - delete new_uuid; return; } } @@ -318,7 +247,7 @@ void LLPreviewNotecard::loadAsset() item->getAssetUUID(), item->getType(), &onLoadComplete, - (void*)new_uuid, + (void*)new LLUUID(mItemUUID), TRUE); mAssetStatus = PREVIEW_ASSET_LOADING; } @@ -343,7 +272,9 @@ void LLPreviewNotecard::loadAsset() editor->setText(LLStringUtil::null); editor->makePristine(); editor->setEnabled(TRUE); - mAssetStatus = PREVIEW_ASSET_LOADED; + // Don't set asset status here; we may not have set the item id yet + // (e.g. when this gets called initially) + //mAssetStatus = PREVIEW_ASSET_LOADED; } } @@ -355,7 +286,8 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, { llinfos << "LLPreviewNotecard::onLoadComplete()" << llendl; LLUUID* item_id = (LLUUID*)user_data; - LLPreviewNotecard* preview = LLPreviewNotecard::getInstance(*item_id); + + LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance("preview_notecard", LLSD(*item_id)); if( preview ) { if(0 == status) @@ -419,18 +351,6 @@ void LLPreviewNotecard::onLoadComplete(LLVFS *vfs, delete item_id; } -// static -LLPreviewNotecard* LLPreviewNotecard::getInstance(const LLUUID& item_id) -{ - LLPreview* instance = NULL; - preview_map_t::iterator found_it = LLPreview::sInstances.find(item_id); - if(found_it != LLPreview::sInstances.end()) - { - instance = found_it->second; - } - return (LLPreviewNotecard*)instance; -} - // static void LLPreviewNotecard::onClickSave(void* user_data) { @@ -590,10 +510,11 @@ void LLPreviewNotecard::onSaveComplete(const LLUUID& asset_uuid, void* user_data } // Find our window and close it if requested. - LLPreviewNotecard* previewp = (LLPreviewNotecard*)LLPreview::find(info->mItemUUID); + + LLPreviewNotecard* previewp = LLFloaterReg::findTypedInstance("preview_notecard", info->mItemUUID); if (previewp && previewp->mCloseAfterSave) { - previewp->close(); + previewp->closeFloater(); } } else @@ -624,7 +545,7 @@ bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const case 1: // "No" mForceClose = TRUE; - close(); + closeFloater(); break; case 2: // "Cancel" @@ -636,16 +557,4 @@ bool LLPreviewNotecard::handleSaveChangesDialog(const LLSD& notification, const return false; } -void LLPreviewNotecard::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPreview::reshape( width, height, called_from_parent ); - - if( !isMinimized() ) - { - // So that next time you open a script it will have the same height and width - // (although not the same position). - gSavedSettings.setRect("NotecardEditorRect", getRect()); - } -} - // EOF diff --git a/indra/newview/llpreviewnotecard.h b/indra/newview/llpreviewnotecard.h index f5cd2bb2a9..5b8cf1c2f6 100644 --- a/indra/newview/llpreviewnotecard.h +++ b/indra/newview/llpreviewnotecard.h @@ -49,28 +49,21 @@ class LLButton; class LLPreviewNotecard : public LLPreview { public: - LLPreviewNotecard(const std::string& name, const LLRect& rect, const std::string& title, - const LLUUID& item_id, - const LLUUID& object_id = LLUUID::null, - const LLUUID& asset_id = LLUUID::null, - BOOL show_keep_discard = FALSE, - LLPointer inv_item = NULL); + LLPreviewNotecard(const LLSD& key); virtual ~LLPreviewNotecard(); - // llpreview - virtual bool saveItem(LLPointer* itemptr); + bool saveItem(); // llview virtual void draw(); virtual BOOL handleKeyHere(KEY key, MASK mask); virtual void setEnabled( BOOL enabled ); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); // llfloater virtual BOOL canClose(); // llpanel - virtual BOOL postBuild(); + virtual BOOL postBuild(); // reach into the text editor, and grab the drag item const LLInventoryItem* getDragItem(); @@ -82,15 +75,13 @@ public: // After saving a notecard, the tcp based upload system will // change the asset, therefore, we need to re-fetch it from the // asset system. :( - void refreshFromInventory(); + void refreshFromInventory(const LLUUID& item_id = LLUUID::null); protected: virtual void loadAsset(); bool saveIfNeeded(LLInventoryItem* copyitem = NULL); - static LLPreviewNotecard* getInstance(const LLUUID& uuid); - static void onLoadComplete(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, @@ -104,15 +95,12 @@ protected: bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); - virtual const char *getTitleName() const { return "Note"; } - protected: LLViewerTextEditor* mEditor; LLButton* mSaveBtn; LLUUID mAssetID; - LLUUID mNotecardItemID; LLUUID mObjectID; }; diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index 0bacb95d2d..b256914d29 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -40,6 +40,7 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldir.h" +#include "llfloaterreg.h" #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" @@ -48,6 +49,8 @@ #include "llscrollbar.h" #include "llscrollcontainer.h" #include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "llslider.h" #include "lscript_rt_interface.h" #include "lscript_export.h" @@ -80,15 +83,13 @@ #include "llviewertexteditor.h" #include "llviewerwindow.h" #include "lluictrlfactory.h" -#include "llwebbrowserctrl.h" +#include "llmediactrl.h" #include "lluictrlfactory.h" - +#include "lltrans.h" #include "llviewercontrol.h" #include "llappviewer.h" - #include "llpanelinventory.h" - const std::string HELLO_LSL = "default\n" "{\n" @@ -109,34 +110,8 @@ const std::string DEFAULT_SCRIPT_DESC = "(No Description)"; // *TODO:Translate? // Description and header information -const S32 SCRIPT_BORDER = 4; -const S32 SCRIPT_PAD = 5; -const S32 SCRIPT_BUTTON_WIDTH = 128; -const S32 SCRIPT_BUTTON_HEIGHT = 24; // HACK: Use BTN_HEIGHT where possible. -const S32 LINE_COLUMN_HEIGHT = 14; -const S32 BTN_PAD = 8; - -const S32 SCRIPT_EDITOR_MIN_HEIGHT = 2 * SCROLLBAR_SIZE + 2 * LLPANEL_BORDER_WIDTH + 128; - -const S32 SCRIPT_MIN_WIDTH = - 2 * SCRIPT_BORDER + - 2 * SCRIPT_BUTTON_WIDTH + - SCRIPT_PAD + RESIZE_HANDLE_WIDTH + - SCRIPT_PAD; - -const S32 SCRIPT_MIN_HEIGHT = - 2 * SCRIPT_BORDER + - 3*(SCRIPT_BUTTON_HEIGHT + SCRIPT_PAD) + - LINE_COLUMN_HEIGHT + - SCRIPT_EDITOR_MIN_HEIGHT; - const S32 MAX_EXPORT_SIZE = 1000; -const S32 SCRIPT_SEARCH_WIDTH = 300; -const S32 SCRIPT_SEARCH_HEIGHT = 120; -const S32 SCRIPT_SEARCH_LABEL_WIDTH = 50; -const S32 SCRIPT_SEARCH_BUTTON_WIDTH = 80; -const S32 TEXT_EDIT_COLUMN_HEIGHT = 16; const S32 MAX_HISTORY_COUNT = 10; const F32 LIVE_HELP_REFRESH_TIME = 1.f; @@ -152,9 +127,10 @@ static bool have_script_upload_cap(LLUUID& object_id) class LLFloaterScriptSearch : public LLFloater { public: - LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core); + LLFloaterScriptSearch(LLScriptEdCore* editor_core); ~LLFloaterScriptSearch(); + /*virtual*/ BOOL postBuild(); static void show(LLScriptEdCore* editor_core); static void onBtnSearch(void* userdata); void handleBtnSearch(); @@ -168,8 +144,6 @@ public: LLScriptEdCore* getEditorCore() { return mEditorCore; } static LLFloaterScriptSearch* getInstance() { return sInstance; } - void open(); /*Flawfinder: ignore*/ - private: LLScriptEdCore* mEditorCore; @@ -179,28 +153,14 @@ private: LLFloaterScriptSearch* LLFloaterScriptSearch::sInstance = NULL; -LLFloaterScriptSearch::LLFloaterScriptSearch(std::string title, LLRect rect, LLScriptEdCore* editor_core) - : LLFloater("script search",rect,title), mEditorCore(editor_core) +LLFloaterScriptSearch::LLFloaterScriptSearch(LLScriptEdCore* editor_core) +: LLFloater(LLSD()), + mEditorCore(editor_core) { - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_search.xml"); + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_search.xml", NULL); - childSetAction("search_btn", onBtnSearch,this); - childSetAction("replace_btn", onBtnReplace,this); - childSetAction("replace_all_btn", onBtnReplaceAll,this); - - setDefaultBtn("search_btn"); - - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } - sInstance = this; - - childSetFocus("search_text", TRUE); - + // find floater in which script panel is embedded LLView* viewp = (LLView*)editor_core; while(viewp) @@ -215,26 +175,33 @@ LLFloaterScriptSearch::LLFloaterScriptSearch(std::string title, LLRect rect, LLS } } +BOOL LLFloaterScriptSearch::postBuild() +{ + childSetAction("search_btn", onBtnSearch,this); + childSetAction("replace_btn", onBtnReplace,this); + childSetAction("replace_all_btn", onBtnReplaceAll,this); + + setDefaultBtn("search_btn"); + + return TRUE; +} + //static void LLFloaterScriptSearch::show(LLScriptEdCore* editor_core) { if (sInstance && sInstance->mEditorCore && sInstance->mEditorCore != editor_core) { - sInstance->close(); + sInstance->closeFloater(); delete sInstance; } if (!sInstance) { - S32 left = 0; - S32 top = 0; - gFloaterView->getNewFloaterPosition(&left,&top); - // sInstance will be assigned in the constructor. - new LLFloaterScriptSearch("Script Search",LLRect(left,top,left + SCRIPT_SEARCH_WIDTH,top - SCRIPT_SEARCH_HEIGHT),editor_core); + new LLFloaterScriptSearch(editor_core); } - sInstance->open(); /*Flawfinder: ignore*/ + sInstance->openFloater(); } LLFloaterScriptSearch::~LLFloaterScriptSearch() @@ -281,19 +248,21 @@ void LLFloaterScriptSearch::handleBtnReplaceAll() mEditorCore->mEditor->replaceTextAll(childGetText("search_text"), childGetText("replace_text"), caseChk->get()); } -void LLFloaterScriptSearch::open() /*Flawfinder: ignore*/ -{ - LLFloater::open(); /*Flawfinder: ignore*/ - childSetFocus("search_text", TRUE); -} + /// --------------------------------------------------------------------------- /// LLScriptEdCore /// --------------------------------------------------------------------------- +struct LLSECKeywordCompare +{ + bool operator()(const std::string& lhs, const std::string& rhs) + { + return (LLStringUtil::compareDictInsensitive( lhs, rhs ) < 0 ); + } +}; + LLScriptEdCore::LLScriptEdCore( - const std::string& name, - const LLRect& rect, const std::string& sample, const std::string& help_url, const LLHandle& floater_handle, @@ -303,7 +272,7 @@ LLScriptEdCore::LLScriptEdCore( void* userdata, S32 bottom_pad) : - LLPanel( std::string("name"), rect ), + LLPanel(), mSampleText(sample), mHelpURL(help_url), mEditor( NULL ), @@ -321,65 +290,76 @@ LLScriptEdCore::LLScriptEdCore( setBorderVisible(FALSE); - LLUICtrlFactory::getInstance()->buildPanel(this, "floater_script_ed_panel.xml"); - - mErrorList = getChild("lsl errors"); - - mFunctions = getChild( "Insert..."); - - childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this); - - mEditor = getChild("Script Editor"); - mEditor->setFollowsAll(); - mEditor->setHandleEditKeysDirectly(TRUE); - mEditor->setEnabled(TRUE); - mEditor->setWordWrap(TRUE); + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_script_ed.xml"); std::vector funcs; std::vector tooltips; - for (S32 i = 0; i < gScriptLibrary.mNextNumber; i++) + for (std::vector::const_iterator i = gScriptLibrary.mFunctions.begin(); + i != gScriptLibrary.mFunctions.end(); ++i) { // Make sure this isn't a god only function, or the agent is a god. - if (!gScriptLibrary.mFunctions[i]->mGodOnly || gAgent.isGodlike()) + if (!i->mGodOnly || gAgent.isGodlike()) { - funcs.push_back(ll_safe_string(gScriptLibrary.mFunctions[i]->mName)); - tooltips.push_back(ll_safe_string(gScriptLibrary.mFunctions[i]->mDesc)); + std::string name = i->mName; + funcs.push_back(name); + + std::string desc_name = "LSLTipText_"; + desc_name += name; + std::string desc = LLTrans::getString(desc_name); + + F32 sleep_time = i->mSleepTime; + if( sleep_time ) + { + desc += "\n"; + + LLStringUtil::format_map_t args; + args["[SLEEP_TIME]"] = llformat("%.1f", sleep_time ); + desc += LLTrans::getString("LSLTipSleepTime", args); + } + + // A \n linefeed is not part of xml. Let's add one to keep all + // the tips one-per-line in strings.xml + LLStringUtil::replaceString( desc, "\\n", "\n" ); + + tooltips.push_back(desc); } } + LLColor3 color(0.5f, 0.0f, 0.15f); - mEditor->loadKeywords(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"keywords.ini"), funcs, tooltips, color); - + std::vector primary_keywords; + std::vector secondary_keywords; LLKeywordToken *token; LLKeywords::keyword_iterator_t token_it; for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it) { token = token_it->second; - if (token->getColor() == color) - mFunctions->add(wstring_to_utf8str(token->getToken())); + if (token->getColor() == color) // Wow, what a disgusting hack. + { + primary_keywords.push_back( wstring_to_utf8str(token->getToken()) ); + } + else + { + secondary_keywords.push_back( wstring_to_utf8str(token->getToken()) ); + } } - for (token_it = mEditor->keywordsBegin(); token_it != mEditor->keywordsEnd(); ++token_it) + // Case-insensitive dictionary sort for primary keywords. We don't sort the secondary + // keywords. They're intelligently grouped in keywords.ini. + std::stable_sort( primary_keywords.begin(), primary_keywords.end(), LLSECKeywordCompare() ); + + for (std::vector::const_iterator iter= primary_keywords.begin(); + iter!= primary_keywords.end(); ++iter) { - token = token_it->second; - if (token->getColor() != color) - mFunctions->add(wstring_to_utf8str(token->getToken())); + mFunctions->add(*iter); } - - childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); - childSetAction("Save_btn", onBtnSave,this); - - initMenu(); - - // Do the work that addTabPanel() normally does. - //LLRect tab_panel_rect( 0, getRect().getHeight(), getRect().getWidth(), 0 ); - //tab_panel_rect.stretch( -LLPANEL_BORDER_WIDTH ); - //mCodePanel->setFollowsAll(); - //mCodePanel->translate( tab_panel_rect.mLeft - mCodePanel->getRect().mLeft, tab_panel_rect.mBottom - mCodePanel->getRect().mBottom); - //mCodePanel->reshape( tab_panel_rect.getWidth(), tab_panel_rect.getHeight(), TRUE ); - + for (std::vector::const_iterator iter= secondary_keywords.begin(); + iter!= secondary_keywords.end(); ++iter) + { + mFunctions->add(*iter); + } } LLScriptEdCore::~LLScriptEdCore() @@ -390,57 +370,74 @@ LLScriptEdCore::~LLScriptEdCore() LLFloaterScriptSearch* script_search = LLFloaterScriptSearch::getInstance(); if (script_search && script_search->getEditorCore() == this) { - script_search->close(); + script_search->closeFloater(); delete script_search; } } -void LLScriptEdCore::initMenu() +BOOL LLScriptEdCore::postBuild() { - LLMenuItemCallGL* menuItem = getChild("Save"); - menuItem->setMenuCallback(onBtnSave, this); - menuItem->setEnabledCallback(hasChanged); + mErrorList = getChild("lsl errors"); + + mFunctions = getChild( "Insert..."); + + childSetCommitCallback("Insert...", &LLScriptEdCore::onBtnInsertFunction, this); + + mEditor = getChild("Script Editor"); + + childSetCommitCallback("lsl errors", &LLScriptEdCore::onErrorList, this); + childSetAction("Save_btn", boost::bind(&LLScriptEdCore::doSave,this,FALSE)); + + initMenu(); + return TRUE; +} + +void LLScriptEdCore::initMenu() +{ + // *TODO: Skinning - make these callbacks data driven + LLMenuItemCallGL* menuItem; + + menuItem = getChild("Save"); + menuItem->setClickCallback(boost::bind(&LLScriptEdCore::doSave, this, FALSE)); + menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this)); menuItem = getChild("Revert All Changes"); - menuItem->setMenuCallback(onBtnUndoChanges, this); - menuItem->setEnabledCallback(hasChanged); + menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnUndoChanges, this)); + menuItem->setEnableCallback(boost::bind(&LLScriptEdCore::hasChanged, this)); menuItem = getChild("Undo"); - menuItem->setMenuCallback(onUndoMenu, this); - menuItem->setEnabledCallback(enableUndoMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::undo, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canUndo, mEditor)); menuItem = getChild("Redo"); - menuItem->setMenuCallback(onRedoMenu, this); - menuItem->setEnabledCallback(enableRedoMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::redo, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canRedo, mEditor)); menuItem = getChild("Cut"); - menuItem->setMenuCallback(onCutMenu, this); - menuItem->setEnabledCallback(enableCutMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::cut, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCut, mEditor)); menuItem = getChild("Copy"); - menuItem->setMenuCallback(onCopyMenu, this); - menuItem->setEnabledCallback(enableCopyMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::copy, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canCopy, mEditor)); menuItem = getChild("Paste"); - menuItem->setMenuCallback(onPasteMenu, this); - menuItem->setEnabledCallback(enablePasteMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::paste, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canPaste, mEditor)); menuItem = getChild("Select All"); - menuItem->setMenuCallback(onSelectAllMenu, this); - menuItem->setEnabledCallback(enableSelectAllMenu); + menuItem->setClickCallback(boost::bind(&LLTextEditor::selectAll, mEditor)); + menuItem->setEnableCallback(boost::bind(&LLTextEditor::canSelectAll, mEditor)); menuItem = getChild("Search / Replace..."); - menuItem->setMenuCallback(onSearchMenu, this); - menuItem->setEnabledCallback(NULL); + menuItem->setClickCallback(boost::bind(&LLFloaterScriptSearch::show, this)); menuItem = getChild("Help..."); - menuItem->setMenuCallback(onBtnHelp, this); - menuItem->setEnabledCallback(NULL); + menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnHelp, this)); menuItem = getChild("LSL Wiki Help..."); - menuItem->setMenuCallback(onBtnDynamicHelp, this); - menuItem->setEnabledCallback(NULL); + menuItem->setClickCallback(boost::bind(&LLScriptEdCore::onBtnDynamicHelp, this)); } void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid) @@ -452,17 +449,16 @@ void LLScriptEdCore::setScriptText(const std::string& text, BOOL is_valid) } } -BOOL LLScriptEdCore::hasChanged(void* userdata) +bool LLScriptEdCore::hasChanged() { - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; + if (!mEditor) return false; - return ((!self->mEditor->isPristine() || self->mEnableSave) && self->mHasScriptData); + return !mEditor->isPristine(); } void LLScriptEdCore::draw() { - BOOL script_changed = hasChanged(this); + BOOL script_changed = hasChanged(); childSetEnabled("Save_btn", script_changed); if( mEditor->hasFocus() ) @@ -470,8 +466,11 @@ void LLScriptEdCore::draw() S32 line = 0; S32 column = 0; mEditor->getCurrentLineAndColumn( &line, &column, FALSE ); // don't include wordwrap + LLStringUtil::format_map_t args; std::string cursor_pos; - cursor_pos = llformat("Line %d, Column %d", line, column ); + args["[LINE]"] = llformat ("%d", line); + args["[COLUMN]"] = llformat ("%d", column); + cursor_pos = LLTrans::getString("CursorPos", args); childSetText("line_col", cursor_pos); } else @@ -492,7 +491,7 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) // update back and forward buttons LLButton* fwd_button = help_floater->getChild("fwd_btn"); LLButton* back_button = help_floater->getChild("back_btn"); - LLWebBrowserCtrl* browser = help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* browser = help_floater->getChild("lsl_guide_html"); back_button->setEnabled(browser->canNavigateBack()); fwd_button->setEnabled(browser->canNavigateForward()); @@ -501,12 +500,12 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) return; } - const LLTextSegment* segment = NULL; - std::vector selected_segments; + LLTextSegmentPtr segment = NULL; + std::vector selected_segments; mEditor->getSelectedSegments(selected_segments); // try segments in selection range first - std::vector::iterator segment_iter; + std::vector::iterator segment_iter; for (segment_iter = selected_segments.begin(); segment_iter != selected_segments.end(); ++segment_iter) { if((*segment_iter)->getToken() && (*segment_iter)->getToken()->getType() == LLKeywordToken::WORD) @@ -519,7 +518,7 @@ void LLScriptEdCore::updateDynamicHelp(BOOL immediate) // then try previous segment in case we just typed it if (!segment) { - const LLTextSegment* test_segment = mEditor->getPreviousSegment(); + const LLTextSegmentPtr test_segment = mEditor->getPreviousSegment(); if(test_segment->getToken() && test_segment->getToken()->getType() == LLKeywordToken::WORD) { segment = test_segment; @@ -551,7 +550,7 @@ void LLScriptEdCore::setHelpPage(const std::string& help_string) LLFloater* help_floater = mLiveHelpHandle.get(); if (!help_floater) return; - LLWebBrowserCtrl* web_browser = help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* web_browser = help_floater->getChild("lsl_guide_html"); if (!web_browser) return; LLComboBox* history_combo = help_floater->getChild("history_combo"); @@ -580,9 +579,7 @@ void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string) // separate history items from full item list if (mLiveHelpHistorySize == 0) { - LLSD row; - row["columns"][0]["type"] = "separator"; - history_combo->addElement(row, ADD_TOP); + history_combo->addSeparator(ADD_TOP); } // delete all history items over history limit while(mLiveHelpHistorySize > MAX_HISTORY_COUNT - 1) @@ -612,7 +609,7 @@ void LLScriptEdCore::addHelpItemToHistory(const std::string& help_string) BOOL LLScriptEdCore::canClose() { - if(mForceClose || !hasChanged(this)) + if(mForceClose || !hasChanged()) { return TRUE; } @@ -631,14 +628,14 @@ bool LLScriptEdCore::handleSaveChangesDialog(const LLSD& notification, const LLS { case 0: // "Yes" // close after saving - LLScriptEdCore::doSave( this, TRUE ); + doSave( TRUE ); break; case 1: // "No" mForceClose = TRUE; // This will close immediately because mForceClose is true, so we won't // infinite loop with these dialogs. JC - ((LLFloater*) getParent())->close(); + ((LLFloater*) getParent())->closeFloater(); break; case 2: // "Cancel" @@ -666,46 +663,42 @@ bool LLScriptEdCore::onHelpWebDialog(const LLSD& notification, const LLSD& respo return false; } -// static -void LLScriptEdCore::onBtnHelp(void* userdata) +void LLScriptEdCore::onBtnHelp() { - LLScriptEdCore* corep = (LLScriptEdCore*)userdata; LLSD payload; - payload["help_url"] = corep->mHelpURL; + payload["help_url"] = mHelpURL; LLNotifications::instance().add("WebLaunchLSLGuide", LLSD(), payload, onHelpWebDialog); } -// static -void LLScriptEdCore::onBtnDynamicHelp(void* userdata) +void LLScriptEdCore::onBtnDynamicHelp() { - LLScriptEdCore* corep = (LLScriptEdCore*)userdata; - - LLFloater* live_help_floater = corep->mLiveHelpHandle.get(); + LLFloater* live_help_floater = mLiveHelpHandle.get(); if (live_help_floater) { live_help_floater->setFocus(TRUE); - corep->updateDynamicHelp(TRUE); + updateDynamicHelp(TRUE); return; } - live_help_floater = new LLFloater(std::string("lsl_help")); - LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml"); - ((LLFloater*)corep->getParent())->addDependentFloater(live_help_floater, TRUE); - live_help_floater->childSetCommitCallback("lock_check", onCheckLock, userdata); + live_help_floater = new LLFloater(LLSD()); + LLUICtrlFactory::getInstance()->buildFloater(live_help_floater, "floater_lsl_guide.xml", NULL); + LLFloater* parent = dynamic_cast(getParent()); + parent->addDependentFloater(live_help_floater, TRUE); + live_help_floater->childSetCommitCallback("lock_check", onCheckLock, this); live_help_floater->childSetValue("lock_check", gSavedSettings.getBOOL("ScriptHelpFollowsCursor")); - live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, userdata); - live_help_floater->childSetAction("back_btn", onClickBack, userdata); - live_help_floater->childSetAction("fwd_btn", onClickForward, userdata); + live_help_floater->childSetCommitCallback("history_combo", onHelpComboCommit, this); + live_help_floater->childSetAction("back_btn", onClickBack, this); + live_help_floater->childSetAction("fwd_btn", onClickForward, this); - LLWebBrowserCtrl* browser = live_help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* browser = live_help_floater->getChild("lsl_guide_html"); browser->setAlwaysRefresh(TRUE); LLComboBox* help_combo = live_help_floater->getChild("history_combo"); LLKeywordToken *token; LLKeywords::keyword_iterator_t token_it; - for (token_it = corep->mEditor->keywordsBegin(); - token_it != corep->mEditor->keywordsEnd(); + for (token_it = mEditor->keywordsBegin(); + token_it != mEditor->keywordsEnd(); ++token_it) { token = token_it->second; @@ -714,10 +707,10 @@ void LLScriptEdCore::onBtnDynamicHelp(void* userdata) help_combo->sortByName(); // re-initialize help variables - corep->mLastHelpToken = NULL; - corep->mLiveHelpHandle = live_help_floater->getHandle(); - corep->mLiveHelpHistorySize = 0; - corep->updateDynamicHelp(TRUE); + mLastHelpToken = NULL; + mLiveHelpHandle = live_help_floater->getHandle(); + mLiveHelpHistorySize = 0; + updateDynamicHelp(TRUE); } //static @@ -727,7 +720,7 @@ void LLScriptEdCore::onClickBack(void* userdata) LLFloater* live_help_floater = corep->mLiveHelpHandle.get(); if (live_help_floater) { - LLWebBrowserCtrl* browserp = live_help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* browserp = live_help_floater->getChild("lsl_guide_html"); if (browserp) { browserp->navigateBack(); @@ -742,7 +735,7 @@ void LLScriptEdCore::onClickForward(void* userdata) LLFloater* live_help_floater = corep->mLiveHelpHandle.get(); if (live_help_floater) { - LLWebBrowserCtrl* browserp = live_help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* browserp = live_help_floater->getChild("lsl_guide_html"); if (browserp) { browserp->navigateForward(); @@ -784,7 +777,7 @@ void LLScriptEdCore::onHelpComboCommit(LLUICtrl* ctrl, void* userdata) corep->addHelpItemToHistory(help_string); - LLWebBrowserCtrl* web_browser = live_help_floater->getChild("lsl_guide_html"); + LLMediaCtrl* web_browser = live_help_floater->getChild("lsl_guide_html"); LLUIString url_string = gSavedSettings.getString("LSLHelpURL"); url_string.setArg("[LSL_STRING]", help_string); web_browser->navigateTo(url_string); @@ -805,154 +798,25 @@ void LLScriptEdCore::onBtnInsertFunction(LLUICtrl *ui, void* userdata) self->setHelpPage(self->mFunctions->getSimple()); } -// static -void LLScriptEdCore::doSave( void* userdata, BOOL close_after_save ) +void LLScriptEdCore::doSave( BOOL close_after_save ) { LLViewerStats::getInstance()->incStat( LLViewerStats::ST_LSL_SAVE_COUNT ); - LLScriptEdCore* self = (LLScriptEdCore*) userdata; - - if( self->mSaveCallback ) + if( mSaveCallback ) { - self->mSaveCallback( self->mUserdata, close_after_save ); + mSaveCallback( mUserdata, close_after_save ); } } -// static -void LLScriptEdCore::onBtnSave(void* data) -{ - // do the save, but don't close afterwards - doSave(data, FALSE); -} -// static -void LLScriptEdCore::onBtnUndoChanges( void* userdata ) +void LLScriptEdCore::onBtnUndoChanges() { - LLScriptEdCore* self = (LLScriptEdCore*) userdata; - if( !self->mEditor->tryToRevertToPristineState() ) + if( !mEditor->tryToRevertToPristineState() ) { - LLNotifications::instance().add("ScriptCannotUndo", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleReloadFromServerDialog, self, _1, _2)); + LLNotifications::instance().add("ScriptCannotUndo", LLSD(), LLSD(), boost::bind(&LLScriptEdCore::handleReloadFromServerDialog, this, _1, _2)); } } -void LLScriptEdCore::onSearchMenu(void* userdata) -{ - LLScriptEdCore* sec = (LLScriptEdCore*)userdata; - LLFloaterScriptSearch::show(sec); -} - -// static -void LLScriptEdCore::onUndoMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->undo(); -} - -// static -void LLScriptEdCore::onRedoMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->redo(); -} - -// static -void LLScriptEdCore::onCutMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->cut(); -} - -// static -void LLScriptEdCore::onCopyMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->copy(); -} - -// static -void LLScriptEdCore::onPasteMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->paste(); -} - -// static -void LLScriptEdCore::onSelectAllMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->selectAll(); -} - -// static -void LLScriptEdCore::onDeselectMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return; - self->mEditor->deselect(); -} - -// static -BOOL LLScriptEdCore::enableUndoMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canUndo(); -} - -// static -BOOL LLScriptEdCore::enableRedoMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canRedo(); -} - -// static -BOOL LLScriptEdCore::enableCutMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canCut(); -} - -// static -BOOL LLScriptEdCore::enableCopyMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canCopy(); -} - -// static -BOOL LLScriptEdCore::enablePasteMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canPaste(); -} - -// static -BOOL LLScriptEdCore::enableSelectAllMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canSelectAll(); -} - -// static -BOOL LLScriptEdCore::enableDeselectMenu(void* userdata) -{ - LLScriptEdCore* self = (LLScriptEdCore*)userdata; - if (!self || !self->mEditor) return FALSE; - return self->mEditor->canDeselect(); -} - // static void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data) { @@ -960,8 +824,7 @@ void LLScriptEdCore::onErrorList(LLUICtrl*, void* user_data) LLScrollListItem* item = self->mErrorList->getFirstSelected(); if(item) { - // *FIX: This fucked up little hack is here because we don't - // have a grep library. This is very brittle code. + // *FIX: replace with boost grep S32 row = 0; S32 column = 0; const LLScrollListCell* cell = item->getColumn(0); @@ -1080,8 +943,7 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) LLPreviewLSL *self = (LLPreviewLSL*)userdata; - self->mScriptEd = new LLScriptEdCore("script panel", - LLRect(), + self->mScriptEd = new LLScriptEdCore( HELLO_LSL, HELP_LSL_URL, self->getHandle(), @@ -1095,49 +957,32 @@ void* LLPreviewLSL::createScriptEdPanel(void* userdata) } -LLPreviewLSL::LLPreviewLSL(const std::string& name, const LLRect& rect, - const std::string& title, const LLUUID& item_id ) -: LLPreview( name, rect, title, item_id, LLUUID::null, TRUE, - SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT ), - mPendingUploads(0) +LLPreviewLSL::LLPreviewLSL(const LLSD& key ) + : LLPreview( key ), + mPendingUploads(0) { + mFactoryMap["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_preview.xml", FALSE); +} - LLRect curRect = rect; - - - LLCallbackMap::map_t factory_map; - factory_map["script panel"] = LLCallbackMap(LLPreviewLSL::createScriptEdPanel, this); - - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_script_preview.xml", &factory_map); - +// virtual +BOOL LLPreviewLSL::postBuild() +{ const LLInventoryItem* item = getItem(); childSetCommitCallback("desc", LLPreview::onText, this); childSetText("desc", item->getDescription()); childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); - if (!getFloaterHost() && !getHost() && getAssetStatus() == PREVIEW_ASSET_UNLOADED) - { - loadAsset(); - } - - setTitle(title); - - if (!getHost()) - { - reshape(curRect.getWidth(), curRect.getHeight(), TRUE); - setRect(curRect); - } + return LLPreview::postBuild(); } // virtual void LLPreviewLSL::callbackLSLCompileSucceeded() { llinfos << "LSL Bytecode saved" << llendl; - // *TODO: Translate - mScriptEd->mErrorList->addCommentText(std::string("Compile successful!")); - mScriptEd->mErrorList->addCommentText(std::string("Save complete.")); + mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful")); + mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); closeIfNeeded(); } @@ -1169,7 +1014,7 @@ void LLPreviewLSL::loadAsset() const LLInventoryItem* item = gInventory.getItem(mItemUUID); BOOL is_library = item && !gInventory.isObjectDescendentOf(mItemUUID, - gAgent.getInventoryRootID()); + gInventory.getRootFolderID()); if(!item) { // do the more generic search. @@ -1228,16 +1073,10 @@ void LLPreviewLSL::closeIfNeeded() mPendingUploads--; if (mPendingUploads <= 0 && mCloseAfterSave) { - close(); + closeFloater(); } } -//override the llpreview open which attempts to load asset, load after xml ui made -void LLPreviewLSL::open() /*Flawfinder: ignore*/ -{ - LLFloater::open(); /*Flawfinder: ignore*/ -} - void LLPreviewLSL::onSearchReplace(void* userdata) { LLPreviewLSL* self = (LLPreviewLSL*)userdata; @@ -1267,7 +1106,7 @@ void LLPreviewLSL::onSave(void* userdata, BOOL close_after_save) void LLPreviewLSL::saveIfNeeded() { // llinfos << "LLPreviewLSL::saveIfNeeded()" << llendl; - if(!LLScriptEdCore::hasChanged(mScriptEd)) + if(!mScriptEd->hasChanged()) { return; } @@ -1440,7 +1279,7 @@ void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 } // Find our window and close it if requested. - LLPreviewLSL* self = (LLPreviewLSL*)LLPreview::find(info->mItemUUID); + LLPreviewLSL* self = LLFloaterReg::findTypedInstance("preview_script", info->mItemUUID); if (self) { getWindow()->decBusyCount(); @@ -1448,7 +1287,7 @@ void LLPreviewLSL::onSaveComplete(const LLUUID& asset_uuid, void* user_data, S32 if (self->mPendingUploads <= 0 && self->mCloseAfterSave) { - self->close(); + self->closeFloater(); } } } @@ -1470,7 +1309,7 @@ void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_d LLPreviewLSL* self = NULL; if(instance_uuid) { - self = LLPreviewLSL::getInstance(*instance_uuid); + self = LLFloaterReg::findTypedInstance("preview_script", *instance_uuid); } if (0 == status) { @@ -1487,7 +1326,7 @@ void LLPreviewLSL::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_d if (self->mPendingUploads <= 0 && self->mCloseAfterSave) { - self->close(); + self->closeFloater(); } } } @@ -1508,7 +1347,7 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset lldebugs << "LLPreviewLSL::onLoadComplete: got uuid " << asset_uuid << llendl; LLUUID* item_uuid = (LLUUID*)user_data; - LLPreviewLSL* preview = LLPreviewLSL::getInstance(*item_uuid); + LLPreviewLSL* preview = LLFloaterReg::findTypedInstance("preview_script", *item_uuid); if( preview ) { if(0 == status) @@ -1559,37 +1398,10 @@ void LLPreviewLSL::onLoadComplete( LLVFS *vfs, const LLUUID& asset_uuid, LLAsset delete item_uuid; } -// static -LLPreviewLSL* LLPreviewLSL::getInstance( const LLUUID& item_uuid ) -{ - LLPreview* instance = NULL; - preview_map_t::iterator found_it = LLPreview::sInstances.find(item_uuid); - if(found_it != LLPreview::sInstances.end()) - { - instance = found_it->second; - } - return (LLPreviewLSL*)instance; -} - -void LLPreviewLSL::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLPreview::reshape( width, height, called_from_parent ); - - if( !isMinimized() ) - { - // So that next time you open a script it will have the same height and width - // (although not the same position). - gSavedSettings.setRect("PreviewScriptRect", getRect()); - } -} - /// --------------------------------------------------------------------------- /// LLLiveLSLEditor /// --------------------------------------------------------------------------- -LLMap LLLiveLSLEditor::sInstances; - - //static void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) @@ -1597,8 +1409,7 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) LLLiveLSLEditor *self = (LLLiveLSLEditor*)userdata; - self->mScriptEd = new LLScriptEdCore("script ed panel", - LLRect(), + self->mScriptEd = new LLScriptEdCore( HELLO_LSL, HELP_LSL_URL, self->getHandle(), @@ -1612,72 +1423,40 @@ void* LLLiveLSLEditor::createScriptEdPanel(void* userdata) } -LLLiveLSLEditor::LLLiveLSLEditor(const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& object_id, - const LLUUID& item_id) : - LLPreview(name, rect, title, item_id, object_id, TRUE, SCRIPT_MIN_WIDTH, SCRIPT_MIN_HEIGHT), - mObjectID(object_id), - mItemID(item_id), +LLLiveLSLEditor::LLLiveLSLEditor(const LLSD& key) : + LLPreview(key), mScriptEd(NULL), mAskedForRunningInfo(FALSE), mHaveRunningInfo(FALSE), mCloseAfterSave(FALSE), mPendingUploads(0), - mIsModifiable(FALSE) + mIsModifiable(FALSE), + mIsNew(false) { + mFactoryMap["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", FALSE); +} - - BOOL is_new = FALSE; - if(mItemID.isNull()) - { - mItemID.generate(); - is_new = TRUE; - } - - - LLLiveLSLEditor::sInstances.addData(mItemID ^ mObjectID, this); - - LLCallbackMap::map_t factory_map; - factory_map["script ed panel"] = LLCallbackMap(LLLiveLSLEditor::createScriptEdPanel, this); - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_live_lsleditor.xml", &factory_map); - - mMonoCheckbox = getChild("mono"); - childSetCommitCallback("mono", &LLLiveLSLEditor::onMonoCheckboxClicked, this); - childSetEnabled("mono", FALSE); - +BOOL LLLiveLSLEditor::postBuild() +{ childSetCommitCallback("running", LLLiveLSLEditor::onRunningCheckboxClicked, this); childSetEnabled("running", FALSE); childSetAction("Reset",&LLLiveLSLEditor::onReset,this); childSetEnabled("Reset", TRUE); + mMonoCheckbox = getChild("mono"); + childSetCommitCallback("mono", &LLLiveLSLEditor::onMonoCheckboxClicked, this); + childSetEnabled("mono", FALSE); mScriptEd->mEditor->makePristine(); - loadAsset(is_new); mScriptEd->mEditor->setFocus(TRUE); - - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } - - setTitle(title); + return LLPreview::postBuild(); } LLLiveLSLEditor::~LLLiveLSLEditor() { - LLLiveLSLEditor::sInstances.removeData(mItemID ^ mObjectID); -} - -// this is called via LLPreview::loadAsset() virtual method -void LLLiveLSLEditor::loadAsset() -{ - loadAsset(FALSE); } // virtual @@ -1686,9 +1465,8 @@ void LLLiveLSLEditor::callbackLSLCompileSucceeded(const LLUUID& task_id, bool is_script_running) { lldebugs << "LSL Bytecode saved" << llendl; - // *TODO: Translate - mScriptEd->mErrorList->addCommentText(std::string("Compile successful!")); - mScriptEd->mErrorList->addCommentText(std::string("Save complete.")); + mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessful")); + mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); closeIfNeeded(); } @@ -1704,6 +1482,7 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors) std::string error_message = line->asString(); LLStringUtil::stripNonprintable(error_message); row["columns"][0]["value"] = error_message; + // *TODO: change to "MONOSPACE" and change llfontgl.cpp? row["columns"][0]["font"] = "OCRA"; mScriptEd->mErrorList->addElement(row); } @@ -1711,16 +1490,15 @@ void LLLiveLSLEditor::callbackLSLCompileFailed(const LLSD& compile_errors) closeIfNeeded(); } -void LLLiveLSLEditor::loadAsset(BOOL is_new) +void LLLiveLSLEditor::loadAsset() { //llinfos << "LLLiveLSLEditor::loadAsset()" << llendl; - if(!is_new) + if(!mIsNew) { - LLViewerObject* object = gObjectList.findObject(mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(object) { - // HACK! we "know" that mItemID refers to a LLViewerInventoryItem... - LLViewerInventoryItem* item = (LLViewerInventoryItem*)object->getInventoryObject(mItemID); + LLViewerInventoryItem* item = dynamic_cast(object->getInventoryObject(mItemUUID)); if(item && (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike())) @@ -1744,23 +1522,23 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) else if(item && mItem.notNull()) { // request the text from the object - LLUUID* user_data = new LLUUID(mItemID ^ mObjectID); + LLUUID* user_data = new LLUUID(mItemUUID); // ^ mObjectUUID gAssetStorage->getInvItemAsset(object->getRegion()->getHost(), - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - object->getID(), - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &LLLiveLSLEditor::onLoadComplete, - (void*)user_data, - TRUE); + gAgent.getID(), + gAgent.getSessionID(), + item->getPermissions().getOwner(), + object->getID(), + item->getUUID(), + item->getAssetUUID(), + item->getType(), + &LLLiveLSLEditor::onLoadComplete, + (void*)user_data, + TRUE); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_GetScriptRunning); msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, mObjectID); - msg->addUUIDFast(_PREHASH_ItemID, mItemID); + msg->addUUIDFast(_PREHASH_ObjectID, mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, mItemUUID); msg->sendReliable(object->getRegion()->getHost()); mAskedForRunningInfo = TRUE; mAssetStatus = PREVIEW_ASSET_LOADING; @@ -1789,26 +1567,12 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) gMessageSystem->addUUID("AgentID", gAgent.getID()); U32 local_id = object->getLocalID(); gMessageSystem->addData("LocalID", &local_id); - gMessageSystem->addUUID("ItemID", mItemID); + gMessageSystem->addUUID("ItemID", mItemUUID); LLHost host(object->getRegion()->getIP(), object->getRegion()->getPort()); gMessageSystem->sendReliable(host); */ } - - // Initialization of the asset failed. Probably the result - // of a bug somewhere else. Set up this editor in a no-go mode. - if(mItem.isNull()) - { - // Set the inventory item to an incomplete item. - // This may be better than having a accessible null pointer around, - // though this newly allocated object will most likely be replaced. - mItem = new LLViewerInventoryItem(); - mScriptEd->setScriptText(LLStringUtil::null, FALSE); - mScriptEd->mEditor->makePristine(); - mScriptEd->mEditor->setEnabled(FALSE); - mAssetStatus = PREVIEW_ASSET_LOADED; - } } else { @@ -1817,17 +1581,17 @@ void LLLiveLSLEditor::loadAsset(BOOL is_new) LLPermissions perm; perm.init(gAgent.getID(), gAgent.getID(), LLUUID::null, gAgent.getGroupID()); perm.initMasks(PERM_ALL, PERM_ALL, PERM_NONE, PERM_NONE, PERM_MOVE | PERM_TRANSFER); - mItem = new LLViewerInventoryItem(mItemID, - mObjectID, - perm, - LLUUID::null, - LLAssetType::AT_LSL_TEXT, - LLInventoryType::IT_LSL, - DEFAULT_SCRIPT_NAME, - DEFAULT_SCRIPT_DESC, - LLSaleInfo::DEFAULT, - LLInventoryItem::II_FLAGS_NONE, - time_corrected()); + mItem = new LLViewerInventoryItem(mItemUUID, + mObjectUUID, + perm, + LLUUID::null, + LLAssetType::AT_LSL_TEXT, + LLInventoryType::IT_LSL, + DEFAULT_SCRIPT_NAME, + DEFAULT_SCRIPT_DESC, + LLSaleInfo::DEFAULT, + LLInventoryItem::II_FLAGS_NONE, + time_corrected()); mAssetStatus = PREVIEW_ASSET_LOADED; } } @@ -1839,12 +1603,12 @@ void LLLiveLSLEditor::onLoadComplete(LLVFS *vfs, const LLUUID& asset_id, { lldebugs << "LLLiveLSLEditor::onLoadComplete: got uuid " << asset_id << llendl; - LLLiveLSLEditor* instance = NULL; LLUUID* xored_id = (LLUUID*)user_data; - - if( LLLiveLSLEditor::sInstances.checkData(*xored_id) ) + + LLLiveLSLEditor* instance = LLFloaterReg::findTypedInstance("preview_scriptedit", *xored_id); + + if(instance ) { - instance = LLLiveLSLEditor::sInstances[*xored_id]; if( LL_ERR_NOERR == status ) { instance->loadScriptText(vfs, asset_id, type); @@ -1930,7 +1694,7 @@ void LLLiveLSLEditor::loadScriptText(LLVFS *vfs, const LLUUID &uuid, LLAssetType void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) { LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata; - LLViewerObject* object = gObjectList.findObject( self->mObjectID ); + LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); LLCheckBoxCtrl* runningCheckbox = self->getChild("running"); BOOL running = runningCheckbox->get(); //self->mRunningCheckbox->get(); @@ -1942,8 +1706,8 @@ void LLLiveLSLEditor::onRunningCheckboxClicked( LLUICtrl*, void* userdata ) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID); - msg->addUUIDFast(_PREHASH_ItemID, self->mItemID); + msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID); msg->addBOOLFast(_PREHASH_Running, running); msg->sendReliable(object->getRegion()->getHost()); } @@ -1958,7 +1722,7 @@ void LLLiveLSLEditor::onReset(void *userdata) { LLLiveLSLEditor* self = (LLLiveLSLEditor*) userdata; - LLViewerObject* object = gObjectList.findObject( self->mObjectID ); + LLViewerObject* object = gObjectList.findObject( self->mObjectUUID ); if(object) { LLMessageSystem* msg = gMessageSystem; @@ -1967,8 +1731,8 @@ void LLLiveLSLEditor::onReset(void *userdata) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_Script); - msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectID); - msg->addUUIDFast(_PREHASH_ItemID, self->mItemID); + msg->addUUIDFast(_PREHASH_ObjectID, self->mObjectUUID); + msg->addUUIDFast(_PREHASH_ItemID, self->mItemUUID); msg->sendReliable(object->getRegion()->getHost()); } else @@ -1979,7 +1743,7 @@ void LLLiveLSLEditor::onReset(void *userdata) void LLLiveLSLEditor::draw() { - LLViewerObject* object = gObjectList.findObject(mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectUUID); LLCheckBoxCtrl* runningCheckbox = getChild( "running"); if(object && mAskedForRunningInfo && mHaveRunningInfo) { @@ -2024,14 +1788,13 @@ void LLLiveLSLEditor::draw() { // HACK: Display this information in the title bar. // Really ought to put in main window. - // *TODO: Translate - setTitle(std::string("Script (object out of range)")); + setTitle(LLTrans::getString("ObjectOutOfRange")); runningCheckbox->setEnabled(FALSE); // object may have fallen out of range. mHaveRunningInfo = FALSE; } - LLFloater::draw(); + LLPreview::draw(); } @@ -2046,7 +1809,7 @@ void LLLiveLSLEditor::onSearchReplace(void* userdata) struct LLLiveLSLSaveData { LLLiveLSLSaveData(const LLUUID& id, const LLViewerInventoryItem* item, BOOL active); - LLUUID mObjectID; + LLUUID mSaveObjectID; LLPointer mItem; BOOL mActive; }; @@ -2054,7 +1817,7 @@ struct LLLiveLSLSaveData LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, const LLViewerInventoryItem* item, BOOL active) : - mObjectID(id), + mSaveObjectID(id), mActive(active) { llassert(item); @@ -2064,7 +1827,7 @@ LLLiveLSLSaveData::LLLiveLSLSaveData(const LLUUID& id, void LLLiveLSLEditor::saveIfNeeded() { llinfos << "LLLiveLSLEditor::saveIfNeeded()" << llendl; - LLViewerObject* object = gObjectList.findObject(mObjectID); + LLViewerObject* object = gObjectList.findObject(mObjectUUID); if(!object) { LLNotifications::instance().add("SaveScriptFailObjectNotFound"); @@ -2083,15 +1846,14 @@ void LLLiveLSLEditor::saveIfNeeded() // name on save, because the viewer object version of the item, // and the editor version would get out of synch. Here's a good // place to synch them back up. - // HACK! we "know" that mItemID refers to a LLInventoryItem... - LLInventoryItem* inv_item = (LLInventoryItem*)object->getInventoryObject(mItemID); + LLInventoryItem* inv_item = dynamic_cast(object->getInventoryObject(mItemUUID)); if(inv_item) { mItem->copyItem(inv_item); } // Don't need to save if we're pristine - if(!LLScriptEdCore::hasChanged(mScriptEd)) + if(!mScriptEd->hasChanged()) { return; } @@ -2145,8 +1907,7 @@ void LLLiveLSLEditor::saveIfNeeded() BOOL is_running = getChild( "running")->get(); if (!url.empty()) { - uploadAssetViaCaps(url, filename, mObjectID, - mItemID, is_running); + uploadAssetViaCaps(url, filename, mObjectUUID, mItemUUID, is_running); } else if (gAssetStorage) { @@ -2175,7 +1936,7 @@ void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, const LLTransactionID& tid, BOOL is_running) { - LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectID, + LLLiveLSLSaveData* data = new LLLiveLSLSaveData(mObjectUUID, mItem, is_running); gAssetStorage->storeAssetData(filename, tid, @@ -2238,8 +1999,7 @@ void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, else { llinfos << "Compile worked!" << llendl; - // *TODO: Translate - mScriptEd->mErrorList->addCommentText(std::string("Compile successful, saving...")); + mScriptEd->mErrorList->setCommentText(LLTrans::getString("CompileSuccessfulSaving")); if(gAssetStorage) { llinfos << "LLLiveLSLEditor::saveAsset " @@ -2247,7 +2007,7 @@ void LLLiveLSLEditor::uploadAssetLegacy(const std::string& filename, getWindow()->incBusyCount(); mPendingUploads++; LLLiveLSLSaveData* data = NULL; - data = new LLLiveLSLSaveData(mObjectID, + data = new LLLiveLSLSaveData(mObjectUUID, mItem, is_running); gAssetStorage->storeAssetData(dst_filename, @@ -2283,7 +2043,7 @@ void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_da } else { - LLLiveLSLEditor* self = sInstances.getIfThere(data->mItem->getUUID() ^ data->mObjectID); + LLLiveLSLEditor* self = LLFloaterReg::findTypedInstance("preview_scriptedit", data->mItem->getUUID()); // ^ data->mSaveObjectID if (self) { self->getWindow()->decBusyCount(); @@ -2291,7 +2051,7 @@ void LLLiveLSLEditor::onSaveTextComplete(const LLUUID& asset_uuid, void* user_da if (self->mPendingUploads <= 0 && self->mCloseAfterSave) { - self->close(); + self->closeFloater(); } } } @@ -2308,23 +2068,21 @@ void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* use if(0 ==status) { llinfos << "LSL Bytecode saved" << llendl; - LLUUID xor_id = data->mItem->getUUID() ^ data->mObjectID; - LLLiveLSLEditor* self = sInstances.getIfThere(xor_id); - if(self) + LLLiveLSLEditor* self = LLFloaterReg::findTypedInstance("preview_scriptedit", data->mItem->getUUID()); // ^ data->mSaveObjectID + if (self) { // Tell the user that the compile worked. - // *TODO: Translate - self->mScriptEd->mErrorList->addCommentText(std::string("Save complete.")); + self->mScriptEd->mErrorList->setCommentText(LLTrans::getString("SaveComplete")); // close the window if this completes both uploads self->getWindow()->decBusyCount(); self->mPendingUploads--; if (self->mPendingUploads <= 0 && self->mCloseAfterSave) { - self->close(); + self->closeFloater(); } } - LLViewerObject* object = gObjectList.findObject(data->mObjectID); + LLViewerObject* object = gObjectList.findObject(data->mSaveObjectID); if(object) { object->saveScript(data->mItem, data->mActive, false); @@ -2349,11 +2107,6 @@ void LLLiveLSLEditor::onSaveBytecodeComplete(const LLUUID& asset_uuid, void* use delete data; } -void LLLiveLSLEditor::open() -{ - LLFloater::open(); /*Flawfinder: ignore*/ -} - BOOL LLLiveLSLEditor::canClose() { return (mScriptEd->canClose()); @@ -2365,7 +2118,7 @@ void LLLiveLSLEditor::closeIfNeeded() mPendingUploads--; if (mPendingUploads <= 0 && mCloseAfterSave) { - close(); + closeFloater(); } } @@ -2384,42 +2137,6 @@ void LLLiveLSLEditor::onSave(void* userdata, BOOL close_after_save) self->saveIfNeeded(); } -// static -LLLiveLSLEditor* LLLiveLSLEditor::show(const LLUUID& script_id, const LLUUID& object_id) -{ - LLLiveLSLEditor* instance = NULL; - LLUUID xored_id = script_id ^ object_id; - if(LLLiveLSLEditor::sInstances.checkData(xored_id)) - { - // Move the existing view to the front - instance = LLLiveLSLEditor::sInstances[xored_id]; - instance->open(); /*Flawfinder: ignore*/ - } - return instance; -} - -// static -void LLLiveLSLEditor::hide(const LLUUID& script_id, const LLUUID& object_id) -{ - LLUUID xored_id = script_id ^ object_id; - if( LLLiveLSLEditor::sInstances.checkData( xored_id ) ) - { - LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id]; - if(instance->getParent()) - { - instance->getParent()->removeChild(instance); - } - delete instance; - } -} -// static -LLLiveLSLEditor* LLLiveLSLEditor::find(const LLUUID& script_id, const LLUUID& object_id) -{ - LLUUID xored_id = script_id ^ object_id; - return sInstances.getIfThere(xored_id); -} - - // static void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) { @@ -2427,10 +2144,10 @@ void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) LLUUID object_id; msg->getUUIDFast(_PREHASH_Script, _PREHASH_ObjectID, object_id); msg->getUUIDFast(_PREHASH_Script, _PREHASH_ItemID, item_id); - LLUUID xored_id = item_id ^ object_id; - if(LLLiveLSLEditor::sInstances.checkData(xored_id)) + + LLLiveLSLEditor* instance = LLFloaterReg::findTypedInstance("preview_scriptedit", item_id); // ^ object_id + if(instance) { - LLLiveLSLEditor* instance = LLLiveLSLEditor::sInstances[xored_id]; instance->mHaveRunningInfo = TRUE; BOOL running; msg->getBOOLFast(_PREHASH_Script, _PREHASH_Running, running); @@ -2444,22 +2161,10 @@ void LLLiveLSLEditor::processScriptRunningReply(LLMessageSystem* msg, void**) } } -void LLLiveLSLEditor::reshape(S32 width, S32 height, BOOL called_from_parent) -{ - LLFloater::reshape( width, height, called_from_parent ); - - if( !isMinimized() ) - { - // So that next time you open a script it will have the same height and width - // (although not the same position). - gSavedSettings.setRect("PreviewScriptRect", getRect()); - } -} - void LLLiveLSLEditor::onMonoCheckboxClicked(LLUICtrl*, void* userdata) { LLLiveLSLEditor* self = static_cast(userdata); - self->mMonoCheckbox->setEnabled(have_script_upload_cap(self->mObjectID)); + self->mMonoCheckbox->setEnabled(have_script_upload_cap(self->mObjectUUID)); self->mScriptEd->enableSave(self->getIsModifiable()); } diff --git a/indra/newview/llpreviewscript.h b/indra/newview/llpreviewscript.h index eb8b414709..623886101a 100644 --- a/indra/newview/llpreviewscript.h +++ b/indra/newview/llpreviewscript.h @@ -63,8 +63,6 @@ class LLScriptEdCore : public LLPanel public: LLScriptEdCore( - const std::string& name, - const LLRect& rect, const std::string& sample, const std::string& help_url, const LLHandle& floater_handle, @@ -78,45 +76,30 @@ public: void initMenu(); virtual void draw(); - + /*virtual*/ BOOL postBuild(); BOOL canClose(); void setScriptText(const std::string& text, BOOL is_valid); + + void doSave( BOOL close_after_save ); bool handleSaveChangesDialog(const LLSD& notification, const LLSD& response); bool handleReloadFromServerDialog(const LLSD& notification, const LLSD& response); static bool onHelpWebDialog(const LLSD& notification, const LLSD& response); - static void onBtnHelp(void* userdata); - static void onBtnDynamicHelp(void* userdata); static void onCheckLock(LLUICtrl*, void*); static void onHelpComboCommit(LLUICtrl* ctrl, void* userdata); static void onClickBack(void* userdata); static void onClickForward(void* userdata); static void onBtnInsertSample(void*); static void onBtnInsertFunction(LLUICtrl*, void*); - static void doSave( void* userdata, BOOL close_after_save ); - static void onBtnSave(void*); - static void onBtnUndoChanges(void*); - static void onSearchMenu(void* userdata); - static void onUndoMenu(void* userdata); - static void onRedoMenu(void* userdata); - static void onCutMenu(void* userdata); - static void onCopyMenu(void* userdata); - static void onPasteMenu(void* userdata); - static void onSelectAllMenu(void* userdata); - static void onDeselectMenu(void* userdata); +private: + void onBtnHelp(); + void onBtnDynamicHelp(); + void onBtnUndoChanges(); - static BOOL enableUndoMenu(void* userdata); - static BOOL enableRedoMenu(void* userdata); - static BOOL enableCutMenu(void* userdata); - static BOOL enableCopyMenu(void* userdata); - static BOOL enablePasteMenu(void* userdata); - static BOOL enableSelectAllMenu(void* userdata); - static BOOL enableDeselectMenu(void* userdata); - - static BOOL hasChanged(void* userdata); + bool hasChanged(); void selectFirstError(); @@ -131,8 +114,6 @@ protected: void addHelpItemToHistory(const std::string& help_string); static void onErrorList(LLUICtrl*, void* user_data); - virtual const char *getTitleName() const { return "Script"; } - private: std::string mSampleText; std::string mHelpURL; @@ -160,17 +141,15 @@ private: class LLPreviewLSL : public LLPreview { public: - LLPreviewLSL(const std::string& name, const LLRect& rect, const std::string& title, - const LLUUID& item_uuid ); + LLPreviewLSL(const LLSD& key ); virtual void callbackLSLCompileSucceeded(); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - /*virtual*/ void open(); /*Flawfinder: ignore*/ + /*virtual*/ BOOL postBuild(); protected: virtual BOOL canClose(); void closeIfNeeded(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); virtual void loadAsset(); void saveIfNeeded(); @@ -190,15 +169,13 @@ protected: void* user_data, S32 status, LLExtStat ext_status); static void onSaveComplete(const LLUUID& uuid, void* user_data, S32 status, LLExtStat ext_status); static void onSaveBytecodeComplete(const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status); -public: - static LLPreviewLSL* getInstance(const LLUUID& uuid); + protected: static void* createScriptEdPanel(void* userdata); protected: - virtual const char *getTitleName() const { return "Script"; } LLScriptEdCore* mScriptEd; // Can safely close only after both text and bytecode are uploaded S32 mPendingUploads; @@ -210,16 +187,10 @@ protected: class LLLiveLSLEditor : public LLPreview { public: - LLLiveLSLEditor(const std::string& name, const LLRect& rect, - const std::string& title, - const LLUUID& object_id, const LLUUID& item_id); + LLLiveLSLEditor(const LLSD& key); ~LLLiveLSLEditor(); - static LLLiveLSLEditor* show(const LLUUID& item_id, const LLUUID& object_id); - static void hide(const LLUUID& item_id, const LLUUID& object_id); - static LLLiveLSLEditor* find(const LLUUID& item_id, const LLUUID& object_id); - static void processScriptRunningReply(LLMessageSystem* msg, void**); virtual void callbackLSLCompileSucceeded(const LLUUID& task_id, @@ -227,14 +198,14 @@ public: bool is_script_running); virtual void callbackLSLCompileFailed(const LLSD& compile_errors); - // Overide LLPreview::open() to avoid calling loadAsset twice. - /*virtual*/ void open(); /*Flawfinder: ignore*/ - -protected: + /*virtual*/ BOOL postBuild(); + + void setIsNew() { mIsNew = TRUE; } + +private: virtual BOOL canClose(); void closeIfNeeded(); virtual void draw(); - virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); virtual void loadAsset(); void loadAsset(BOOL is_new); @@ -248,6 +219,8 @@ protected: LLViewerObject* object, const LLTransactionID& tid, BOOL is_running); + BOOL monoChecked() const; + static void onSearchReplace(void* userdata); static void onLoad(void* userdata); @@ -268,30 +241,23 @@ protected: static void* createScriptEdPanel(void* userdata); + static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); -protected: - LLUUID mObjectID; - LLUUID mItemID; // The inventory item this script is associated with - BOOL mIsNew; - LLScriptEdCore* mScriptEd; +private: + bool mIsNew; + LLScriptEdCore* mScriptEd; //LLUUID mTransmitID; - LLCheckBoxCtrl *mRunningCheckbox; - BOOL mAskedForRunningInfo; - BOOL mHaveRunningInfo; - LLButton *mResetButton; + LLCheckBoxCtrl* mRunningCheckbox; + BOOL mAskedForRunningInfo; + BOOL mHaveRunningInfo; + LLButton* mResetButton; LLPointer mItem; - BOOL mCloseAfterSave; + BOOL mCloseAfterSave; // need to save both text and script, so need to decide when done - S32 mPendingUploads; + S32 mPendingUploads; - static LLMap sInstances; BOOL getIsModifiable() const { return mIsModifiable; } // Evaluated on load assert -private: - - static void onMonoCheckboxClicked(LLUICtrl*, void* userdata); - BOOL monoChecked() const; - LLCheckBoxCtrl* mMonoCheckbox; BOOL mIsModifiable; }; diff --git a/indra/newview/llpreviewsound.cpp b/indra/newview/llpreviewsound.cpp index 26d8da5a6b..7659c50ed3 100644 --- a/indra/newview/llpreviewsound.cpp +++ b/indra/newview/llpreviewsound.cpp @@ -32,11 +32,10 @@ #include "llviewerprecompiledheaders.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" // gAgent #include "llbutton.h" #include "llinventory.h" -#include "llinventoryview.h" #include "lllineeditor.h" #include "llpreviewsound.h" #include "llresmgr.h" @@ -49,12 +48,23 @@ extern LLAgent gAgent; const F32 SOUND_GAIN = 1.0f; -LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, const std::string& title, const LLUUID& item_uuid, const LLUUID& object_uuid) : - LLPreview( name, rect, title, item_uuid, object_uuid) +LLPreviewSound::LLPreviewSound(const LLSD& key) + : LLPreview( key ) { - - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_sound.xml"); + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_sound.xml", FALSE); +} +// virtual +BOOL LLPreviewSound::postBuild() +{ + const LLInventoryItem* item = getItem(); + if (item) + { + childSetText("desc", item->getDescription()); + if (gAudiop) + gAudiop->preloadSound(item->getAssetUUID()); // preload the sound + } + childSetAction("Sound play btn",&LLPreviewSound::playSound,this); childSetAction("Sound audition btn",&LLPreviewSound::auditionSound,this); @@ -64,26 +74,10 @@ LLPreviewSound::LLPreviewSound(const std::string& name, const LLRect& rect, cons button = getChild("Sound audition btn"); button->setSoundFlags(LLView::SILENT); - const LLInventoryItem* item = getItem(); - childSetCommitCallback("desc", LLPreview::onText, this); - childSetText("desc", item->getDescription()); childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); - - // preload the sound - if(item && gAudiop) - { - gAudiop->preloadSound(item->getAssetUUID()); - } - - setTitle(title); - - if (!getHost()) - { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); - } + return LLPreview::postBuild(); } // static diff --git a/indra/newview/llpreviewsound.h b/indra/newview/llpreviewsound.h index 061fbdf685..c4bf8c9a30 100644 --- a/indra/newview/llpreviewsound.h +++ b/indra/newview/llpreviewsound.h @@ -38,16 +38,13 @@ class LLPreviewSound : public LLPreview { public: - LLPreviewSound(const std::string& name, const LLRect& rect, const std::string& title, - const LLUUID& item_uuid, - const LLUUID& object_uuid = LLUUID::null); + LLPreviewSound(const LLSD& key); static void playSound( void* userdata ); static void auditionSound( void* userdata ); protected: - virtual const char *getTitleName() const { return "Sound"; } - + /* virtual */ BOOL postBuild(); }; #endif // LL_LLPREVIEWSOUND_H diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp index 13e7cca464..9d7338c111 100644 --- a/indra/newview/llpreviewtexture.cpp +++ b/indra/newview/llpreviewtexture.cpp @@ -32,48 +32,45 @@ #include "llviewerprecompiledheaders.h" +#include "llwindow.h" + #include "llpreviewtexture.h" #include "llagent.h" #include "llbutton.h" #include "llfilepicker.h" +#include "llfloaterreg.h" #include "llimagetga.h" -#include "llinventoryview.h" #include "llinventory.h" #include "llresmgr.h" +#include "lltrans.h" #include "lltextbox.h" #include "lltextureview.h" #include "llui.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" #include "lllineeditor.h" -const S32 PREVIEW_TEXTURE_MIN_WIDTH = 300; -const S32 PREVIEW_TEXTURE_MIN_HEIGHT = 120; - const S32 CLIENT_RECT_VPAD = 4; const F32 SECONDS_TO_SHOW_FILE_SAVED_MSG = 8.f; -LLPreviewTexture::LLPreviewTexture(const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& item_uuid, - const LLUUID& object_id, - BOOL show_keep_discard) -: LLPreview(name, rect, title, item_uuid, object_id, TRUE, PREVIEW_TEXTURE_MIN_WIDTH, PREVIEW_TEXTURE_MIN_HEIGHT ), - mLoadingFullImage( FALSE ), - mShowKeepDiscard(show_keep_discard), - mCopyToInv(FALSE), - mIsCopyable(FALSE), - mLastHeight(0), - mLastWidth(0) +LLPreviewTexture::LLPreviewTexture(const LLSD& key) + : LLPreview( key ), + mLoadingFullImage( FALSE ), + mShowKeepDiscard(FALSE), + mCopyToInv(FALSE), + mIsCopyable(FALSE), + mUpdateDimensions(TRUE), + mLastHeight(0), + mLastWidth(0) { const LLInventoryItem *item = getItem(); if(item) { + mShowKeepDiscard = item->getPermissions().getCreator() != gAgent.getID(); mImageID = item->getAssetUUID(); const LLPermissions& perm = item->getPermissions(); U32 mask = PERM_NONE; @@ -94,52 +91,14 @@ LLPreviewTexture::LLPreviewTexture(const std::string& name, mIsCopyable = TRUE; } } - - init(); - - setTitle(title); - - if (!getHost()) + else // not an item, assume it's an asset id { - LLRect curRect = getRect(); - translate(rect.mLeft - curRect.mLeft, rect.mTop - curRect.mTop); + mImageID = mItemUUID; + mCopyToInv = TRUE; + mIsCopyable = TRUE; } -} - -// Note: uses asset_id as a dummy item id. -LLPreviewTexture::LLPreviewTexture( - const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& asset_id, - BOOL copy_to_inv) - : - LLPreview( - name, - rect, - title, - asset_id, - LLUUID::null, - TRUE, - PREVIEW_TEXTURE_MIN_WIDTH, - PREVIEW_TEXTURE_MIN_HEIGHT ), - mImageID(asset_id), - mLoadingFullImage( FALSE ), - mShowKeepDiscard(FALSE), - mCopyToInv(copy_to_inv), - mIsCopyable(TRUE), - mLastHeight(0), - mLastWidth(0) -{ - - init(); - - setTitle(title); - - LLRect curRect = getRect(); - translate(curRect.mLeft - rect.mLeft, curRect.mTop - rect.mTop); - + //Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_preview_texture.xml", FALSE); } @@ -153,32 +112,26 @@ LLPreviewTexture::~LLPreviewTexture() mImage = NULL; } - -void LLPreviewTexture::init() +// virtual +BOOL LLPreviewTexture::postBuild() { - - if (mCopyToInv) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_embedded_texture.xml"); - - childSetAction("Copy To Inventory",LLPreview::onBtnCopyToInv,this); + getChild("Keep")->setLabel(getString("Copy")); + childSetAction("Keep",LLPreview::onBtnCopyToInv,this); + childSetVisible("Discard", false); } - else if (mShowKeepDiscard) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_texture_keep_discard.xml"); - childSetAction("Keep",onKeepBtn,this); childSetAction("Discard",onDiscardBtn,this); } - - else + else { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_preview_texture.xml"); + childSetVisible("Keep", false); + childSetVisible("Discard", false); } - - + if (!mCopyToInv) { const LLInventoryItem* item = getItem(); @@ -190,12 +143,17 @@ void LLPreviewTexture::init() childSetPrevalidate("desc", &LLLineEditor::prevalidatePrintableNotPipe); } } + + return LLPreview::postBuild(); } void LLPreviewTexture::draw() { - updateDimensions(); - + if (mUpdateDimensions) + { + updateDimensions(); + } + LLPreview::draw(); if (!isMinimized()) @@ -241,14 +199,14 @@ void LLPreviewTexture::draw() if( mLoadingFullImage ) { - // *TODO: Translate - LLFontGL::getFontSansSerif()->renderUTF8(std::string("Receiving:"), 0, + LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("Receiving:"), 0, interior.mLeft + 4, interior.mBottom + 4, LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); - F32 data_progress = mImage->mDownloadProgress; + F32 data_progress = mImage->getDownloadProgress() ; // Draw the progress bar. const S32 BAR_HEIGHT = 12; @@ -278,11 +236,11 @@ void LLPreviewTexture::draw() else if( !mSavedFileTimer.hasExpired() ) { - // *TODO: Translate - LLFontGL::getFontSansSerif()->renderUTF8(std::string("File Saved"), 0, + LLFontGL::getFontSansSerif()->renderUTF8(LLTrans::getString("FileSaved"), 0, interior.mLeft + 4, interior.mBottom + 4, LLColor4::white, LLFontGL::LEFT, LLFontGL::BOTTOM, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } } @@ -300,10 +258,11 @@ BOOL LLPreviewTexture::canSaveAs() const // virtual void LLPreviewTexture::saveAs() { - if( mLoadingFullImage ) return; + if( mLoadingFullImage ) + return; LLFilePicker& file_picker = LLFilePicker::instance(); - const LLViewerInventoryItem* item = getItem() ; + const LLInventoryItem* item = getItem() ; if( !file_picker.getSaveFile( LLFilePicker::FFSAVE_TGA, item ? LLDir::getScrubbedFileName(item->getName()) : LLStringUtil::null) ) { // User canceled or we failed to acquire save file. @@ -317,10 +276,27 @@ void LLPreviewTexture::saveAs() 0, TRUE, FALSE, new LLUUID( mItemUUID ) ); } +// virtual +void LLPreviewTexture::reshape(S32 width, S32 height, BOOL called_from_parent) +{ +// mLastHeight = 0; +// mLastWidth = 0; + mUpdateDimensions = TRUE; + LLPreview::reshape(width, height, called_from_parent); +} + +// virtual +void LLPreviewTexture::onFocusReceived() +{ + mLastHeight = 0; + mLastWidth = 0; + mUpdateDimensions = TRUE; + LLPreview::onFocusReceived(); +} // static void LLPreviewTexture::onFileLoadedForSave(BOOL success, - LLViewerImage *src_vi, + LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, @@ -328,12 +304,8 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, void* userdata) { LLUUID* item_uuid = (LLUUID*) userdata; - LLPreviewTexture* self = NULL; - preview_map_t::iterator found_it = LLPreview::sInstances.find(*item_uuid); - if(found_it != LLPreview::sInstances.end()) - { - self = (LLPreviewTexture*) found_it->second; - } + + LLPreviewTexture* self = LLFloaterReg::findTypedInstance("preview_texture", *item_uuid); if( final || !success ) { @@ -381,10 +353,13 @@ void LLPreviewTexture::onFileLoadedForSave(BOOL success, // When we receive it, reshape the window accordingly. void LLPreviewTexture::updateDimensions() { - if (!mImage) return; - - S32 image_height = llmax(1, mImage->getHeight(0)); - S32 image_width = llmax(1, mImage->getWidth(0)); + if (!mImage) + return; + + mUpdateDimensions = FALSE; + + S32 image_height = llmax(1, mImage->getFullHeight()); + S32 image_width = llmax(1, mImage->getFullWidth()); // Attempt to make the image 1:1 on screen. // If that fails, cut width by half. S32 client_width = image_width; @@ -400,13 +375,13 @@ void LLPreviewTexture::updateDimensions() client_width /= 2; client_height /= 2; } - + S32 view_width = client_width + horiz_pad; S32 view_height = client_height + vert_pad; // set text on dimensions display (should be moved out of here and into a callback of some sort) - childSetTextArg("dimensions", "[WIDTH]", llformat("%d", mImage->mFullWidth)); - childSetTextArg("dimensions", "[HEIGHT]", llformat("%d", mImage->mFullHeight)); + childSetTextArg("dimensions", "[WIDTH]", llformat("%d", mImage->getFullWidth())); + childSetTextArg("dimensions", "[HEIGHT]", llformat("%d", mImage->getFullHeight())); // add space for dimensions S32 info_height = 0; @@ -427,27 +402,36 @@ void LLPreviewTexture::updateDimensions() view_width = llmax(view_width, getMinWidth()); view_height = llmax(view_height, getMinHeight()); - if (client_height != mLastHeight || client_width != mLastWidth) + if (view_height != mLastHeight || view_width != mLastWidth) { - mLastWidth = client_width; - mLastHeight = client_height; - - S32 old_top = getRect().mTop; - S32 old_left = getRect().mLeft; if (getHost()) { getHost()->growToFit(view_width, view_height); + reshape( view_width, view_height ); + setOrigin( 0, getHost()->getRect().getHeight() - (view_height + PREVIEW_HEADER_SIZE) ); } else { + S32 old_top = getRect().mTop; + S32 old_left = getRect().mLeft; reshape( view_width, view_height ); S32 new_bottom = old_top - getRect().getHeight(); setOrigin( old_left, new_bottom ); - // Try to keep whole view onscreen, don't allow partial offscreen. + } + + // Try to keep whole view onscreen, don't allow partial offscreen. + if (getHost()) + gFloaterView->adjustToFitScreen(getHost(), FALSE); + else gFloaterView->adjustToFitScreen(this, FALSE); + + if (image_height > 1 && image_width > 1) + { + // Resize until we know the image's height + mLastWidth = view_width; + mLastHeight = view_height; } } - if (!mUserResized) { @@ -481,14 +465,15 @@ void LLPreviewTexture::updateDimensions() void LLPreviewTexture::loadAsset() { - mImage = gImageList.getImage(mImageID, MIPMAP_TRUE, FALSE); - mImage->setBoostLevel(LLViewerImage::BOOST_PREVIEW); + mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + mImage->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); mAssetStatus = PREVIEW_ASSET_LOADING; + updateDimensions(); } LLPreview::EAssetStatus LLPreviewTexture::getAssetStatus() { - if (mImage.notNull() && (mImage->mFullWidth * mImage->mFullHeight > 0)) + if (mImage.notNull() && (mImage->getFullWidth() * mImage->getFullHeight() > 0)) { mAssetStatus = PREVIEW_ASSET_LOADED; } diff --git a/indra/newview/llpreviewtexture.h b/indra/newview/llpreviewtexture.h index 75fd39eab0..9ace304fa6 100644 --- a/indra/newview/llpreviewtexture.h +++ b/indra/newview/llpreviewtexture.h @@ -36,26 +36,14 @@ #include "llpreview.h" #include "llbutton.h" #include "llframetimer.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLImageRaw; class LLPreviewTexture : public LLPreview { public: - LLPreviewTexture( - const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& item_uuid, - const LLUUID& object_id, - BOOL show_keep_discard = FALSE); - LLPreviewTexture( - const std::string& name, - const LLRect& rect, - const std::string& title, - const LLUUID& asset_id, - BOOL copy_to_inv = FALSE); + LLPreviewTexture(const LLSD& key); ~LLPreviewTexture(); virtual void draw(); @@ -65,11 +53,14 @@ public: virtual void loadAsset(); virtual EAssetStatus getAssetStatus(); - + + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + virtual void onFocusReceived(); + static void saveToFile(void* userdata); static void onFileLoadedForSave( BOOL success, - LLViewerImage *src_vi, + LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, @@ -79,25 +70,25 @@ public: protected: void init(); + /* virtual */ BOOL postBuild(); - virtual const char *getTitleName() const { return "Texture"; } - private: void updateDimensions(); LLUUID mImageID; - LLPointer mImage; + LLPointer mImage; BOOL mLoadingFullImage; std::string mSaveFileName; LLFrameTimer mSavedFileTimer; BOOL mShowKeepDiscard; BOOL mCopyToInv; - + // This is stored off in a member variable, because the save-as // button and drag and drop functionality need to know. BOOL mIsCopyable; S32 mLastHeight; S32 mLastWidth; + BOOL mUpdateDimensions; }; diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index bfd14f709a..f70cfc59ec 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -40,8 +40,8 @@ #include "llrender.h" #include "llui.h" #include "llfontgl.h" -#include "llimagegl.h" #include "lltimer.h" +#include "lltextbox.h" #include "llglheaders.h" #include "llagent.h" @@ -50,7 +50,7 @@ #include "llprogressbar.h" #include "llstartup.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llappviewer.h" #include "llweb.h" @@ -68,9 +68,9 @@ const F32 TOTAL_LOGIN_TIME = 10.f; // seconds, wild guess at time from GL contex S32 gLastStartAnimationFrame = 0; // human-style indexing, first image = 1 const S32 ANIMATION_FRAMES = 1; //13; -// XUI:translate -LLProgressView::LLProgressView(const std::string& name, const LLRect &rect) -: LLPanel(name, rect, FALSE), +// XUI: Translate +LLProgressView::LLProgressView(const LLRect &rect) +: LLPanel(), mPercentDone( 0.f ), mURLInMessage(false), mMouseDownInActiveArea( false ) @@ -84,7 +84,7 @@ BOOL LLProgressView::postBuild() mProgressBar = getChild("login_progress_bar"); mCancelBtn = getChild("cancel_btn"); - mCancelBtn->setClickedCallback( LLProgressView::onCancelButtonClicked ); + mCancelBtn->setClickedCallback( LLProgressView::onCancelButtonClicked, NULL ); mFadeTimer.stop(); getChild("title_text")->setText(LLStringExplicit(LLAppViewer::instance()->getSecondLifeTitle())); @@ -146,10 +146,10 @@ void LLProgressView::draw() // Paint bitmap if we've got one glPushMatrix(); - if (gStartImageGL) + if (gStartTexture) { LLGLSUIDefault gls_ui; - gGL.getTexUnit(0)->bind(gStartImageGL); + gGL.getTexUnit(0)->bind(gStartTexture.get()); gGL.color4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f); F32 image_aspect = (F32)gStartImageWidth / (F32)gStartImageHeight; S32 width = getRect().getWidth(); @@ -185,7 +185,7 @@ void LLProgressView::draw() { gFocusMgr.removeTopCtrlWithoutCallback(this); LLPanel::setVisible(FALSE); - gStartImageGL = NULL; + gStartTexture = NULL; } return; } diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 9517ee1321..83574ff52a 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -43,7 +43,7 @@ class LLProgressBar; class LLProgressView : public LLPanel { public: - LLProgressView(const std::string& name, const LLRect& rect); + LLProgressView(const LLRect& rect); virtual ~LLProgressView(); BOOL postBuild(); diff --git a/indra/newview/llrecentpeople.cpp b/indra/newview/llrecentpeople.cpp new file mode 100644 index 0000000000..0c16cea004 --- /dev/null +++ b/indra/newview/llrecentpeople.cpp @@ -0,0 +1,69 @@ +/** + * @file llrecentpeople.cpp + * @brief List of people with which the user has recently interacted. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llrecentpeople.h" + +#include "llagent.h" + +using namespace LLOldEvents; + +bool LLRecentPeople::add(const LLUUID& id) +{ + if (contains(id) || id == gAgent.getID()) + return false; + + mList.insert(id); + mChangedSignal(); + return true; +} + +bool LLRecentPeople::contains(const LLUUID& id) const +{ + return mList.find(id) != mList.end(); +} + +void LLRecentPeople::get(std::vector& result) const +{ + result.clear(); + for (std::set::const_iterator pos = mList.begin(); pos != mList.end(); ++pos) + result.push_back(*pos); +} + +// virtual +bool LLRecentPeople::handleEvent(LLPointer event, const LLSD& userdata) +{ + (void) userdata; + add(event->getValue().asUUID()); + return true; +} diff --git a/indra/newview/llrecentpeople.h b/indra/newview/llrecentpeople.h new file mode 100644 index 0000000000..40ac80e8bc --- /dev/null +++ b/indra/newview/llrecentpeople.h @@ -0,0 +1,101 @@ +/** + * @file llrecentpeople.h + * @brief List of people with which the user has recently interacted. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLRECENTPEOPLE_H +#define LL_LLRECENTPEOPLE_H + +#include "llevent.h" +#include "llsingleton.h" +#include "lluuid.h" + +#include +#include +#include + +/** + * List of people the agent recently interacted with. + * + * Includes: anyone with whom the user IM'd or called + * (1:1 and ad-hoc but not SL Group chat), + * anyone with whom the user has had a transaction + * (inventory offer, friend request, etc), + * and anyone that has chatted within chat range of the user in-world. + * + *TODO: purge least recently added items? + */ +class LLRecentPeople: public LLSingleton, public LLOldEvents::LLSimpleListener +{ + LOG_CLASS(LLRecentPeople); +public: + typedef boost::signals2::signal signal_t; + + /** + * Add specified avatar to the list if it's not there already. + * + * @param id avatar to add. + * @return false if the avatar is in the list already, true otherwisr + */ + bool add(const LLUUID& id); + + /** + * @param id avatar to search. + * @return true if the avatar is in the list, false otherwise. + */ + bool contains(const LLUUID& id) const; + + /** + * Get the whole list. + * + * @param result where to put the result. + */ + void get(std::vector& result) const; + + /** + * Set callback to be called when the list changed. + * + * Multiple callbacks can be set. + * + * @return no connection; use boost::bind + boost::signals2::trackable to disconnect slots. + */ + void setChangedCallback(const signal_t::slot_type& cb) { mChangedSignal.connect(cb); } + + /** + * LLSimpleListener interface. + */ + /*virtual*/ bool handleEvent(LLPointer event, const LLSD& userdata); + +private: + std::set mList; + signal_t mChangedSignal; +}; + +#endif // LL_LLRECENTPEOPLE_H diff --git a/indra/newview/llremoteparcelrequest.cpp b/indra/newview/llremoteparcelrequest.cpp index 8ff4dea2b1..1ac0175b83 100644 --- a/indra/newview/llremoteparcelrequest.cpp +++ b/indra/newview/llremoteparcelrequest.cpp @@ -34,8 +34,7 @@ #include "llviewerprecompiledheaders.h" -#include "llagent.h" -#include "llremoteparcelrequest.h" +#include "message.h" #include "llpanelplace.h" #include "llpanel.h" @@ -43,37 +42,132 @@ #include "llsdserialize.h" #include "llviewerregion.h" #include "llview.h" -#include "message.h" -LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle place_panel_handle) -{ - mPlacePanelHandle = place_panel_handle; -} -/*virtual*/ +#include "llagent.h" +#include "llremoteparcelrequest.h" + + +LLRemoteParcelRequestResponder::LLRemoteParcelRequestResponder(LLHandle observer_handle) + : mObserverHandle(observer_handle) +{} + +//If we get back a normal response, handle it here +//virtual void LLRemoteParcelRequestResponder::result(const LLSD& content) { LLUUID parcel_id = content["parcel_id"]; - LLPanelPlace* place_panelp = (LLPanelPlace*)mPlacePanelHandle.get(); - - if(place_panelp) + // Panel inspecting the information may be closed and destroyed + // before this response is received. + LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); + if (observer) { - place_panelp->setParcelID(parcel_id); + observer->setParcelID(parcel_id); } - } -/*virtual*/ +//If we get back an error (not found, etc...), handle it here +//virtual void LLRemoteParcelRequestResponder::error(U32 status, const std::string& reason) { llinfos << "LLRemoteParcelRequest::error(" << status << ": " << reason << ")" << llendl; - LLPanelPlace* place_panelp = (LLPanelPlace*)mPlacePanelHandle.get(); - if(place_panelp) + // Panel inspecting the information may be closed and destroyed + // before this response is received. + LLRemoteParcelInfoObserver* observer = mObserverHandle.get(); + if (observer) { - place_panelp->setErrorStatus(status, reason); + observer->setErrorStatus(status, reason); } - } +void LLRemoteParcelInfoProcessor::addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer) +{ + // Check if the observer is alredy in observsrs list for this UUID + observer_multimap_t::iterator it; + + it = mObservers.find(parcel_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + return; + } + else + { + ++it; + } + } + + mObservers.insert(std::pair(parcel_id, observer)); +} + +void LLRemoteParcelInfoProcessor::removeObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer) +{ + if (!observer) + { + return; + } + + observer_multimap_t::iterator it; + + it = mObservers.find(parcel_id); + while (it != mObservers.end()) + { + if (it->second == observer) + { + mObservers.erase(it); + break; + } + else + { + ++it; + } + } +} + +//static +void LLRemoteParcelInfoProcessor::processParcelInfoReply(LLMessageSystem* msg, void**) +{ + LLParcelData parcel_data; + + msg->getUUID ("Data", "ParcelID", parcel_data.parcel_id); + msg->getUUID ("Data", "OwnerID", parcel_data.owner_id); + msg->getString ("Data", "Name", parcel_data.name); + msg->getString ("Data", "Desc", parcel_data.desc); + msg->getS32 ("Data", "ActualArea", parcel_data.actual_area); + msg->getS32 ("Data", "BillableArea", parcel_data.billable_area); + msg->getU8 ("Data", "Flags", parcel_data.flags); + msg->getF32 ("Data", "GlobalX", parcel_data.global_x); + msg->getF32 ("Data", "GlobalY", parcel_data.global_y); + msg->getF32 ("Data", "GlobalZ", parcel_data.global_z); + msg->getString ("Data", "SimName", parcel_data.sim_name); + msg->getUUID ("Data", "SnapshotID", parcel_data.snapshot_id); + msg->getF32 ("Data", "Dwell", parcel_data.dwell); + msg->getS32 ("Data", "SalePrice", parcel_data.sale_price); + msg->getS32 ("Data", "AuctionID", parcel_data.auction_id); + + LLRemoteParcelInfoProcessor::observer_multimap_t observers = LLRemoteParcelInfoProcessor::getInstance()->mObservers; + + observer_multimap_t::iterator oi = observers.find(parcel_data.parcel_id); + observer_multimap_t::iterator end = observers.upper_bound(parcel_data.parcel_id); + for (; oi != end; ++oi) + { + oi->second->processParcelInfo(parcel_data); + LLRemoteParcelInfoProcessor::getInstance()->removeObserver(parcel_data.parcel_id, oi->second); + } +} + +void LLRemoteParcelInfoProcessor::sendParcelInfoRequest(const LLUUID& parcel_id) +{ + LLMessageSystem *msg = gMessageSystem; + + msg->newMessage("ParcelInfoRequest"); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); + msg->addUUID("SessionID", gAgent.getSessionID()); + msg->nextBlock("Data"); + msg->addUUID("ParcelID", parcel_id); + gAgent.sendReliableMessage(); +} diff --git a/indra/newview/llremoteparcelrequest.h b/indra/newview/llremoteparcelrequest.h index c92ee3ff3a..3a16e25ef6 100644 --- a/indra/newview/llremoteparcelrequest.h +++ b/indra/newview/llremoteparcelrequest.h @@ -38,17 +38,73 @@ #include "llhttpclient.h" #include "llpanel.h" +class LLRemoteParcelInfoObserver; + class LLRemoteParcelRequestResponder : public LLHTTPClient::Responder { public: - LLRemoteParcelRequestResponder(LLHandle place_panel_handle); + LLRemoteParcelRequestResponder(LLHandle observer_handle); + //If we get back a normal response, handle it here - virtual void result(const LLSD& content); + /*virtual*/ void result(const LLSD& content); + //If we get back an error (not found, etc...), handle it here - virtual void error(U32 status, const std::string& reason); + /*virtual*/ void error(U32 status, const std::string& reason); protected: - LLHandle mPlacePanelHandle; + LLHandle mObserverHandle; +}; + +struct LLParcelData +{ + LLUUID parcel_id; + LLUUID owner_id; + std::string name; + std::string desc; + S32 actual_area; + S32 billable_area; + U8 flags; + F32 global_x; + F32 global_y; + F32 global_z; + std::string sim_name; + LLUUID snapshot_id; + F32 dwell; + S32 sale_price; + S32 auction_id; +}; + +// An interface class for panels which display parcel information +// like name, description, area, snapshot etc. +class LLRemoteParcelInfoObserver +{ +public: + LLRemoteParcelInfoObserver() { mObserverHandle.bind(this); } + virtual ~LLRemoteParcelInfoObserver() {} + virtual void processParcelInfo(const LLParcelData& parcel_data) = 0; + virtual void setParcelID(const LLUUID& parcel_id) = 0; + virtual void setErrorStatus(U32 status, const std::string& reason) = 0; + LLHandle getObserverHandle() const { return mObserverHandle; } + +protected: + LLRootHandle mObserverHandle; +}; + +class LLRemoteParcelInfoProcessor : public LLSingleton +{ +public: + virtual ~LLRemoteParcelInfoProcessor() {} + + void addObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer); + void removeObserver(const LLUUID& parcel_id, LLRemoteParcelInfoObserver* observer); + + void sendParcelInfoRequest(const LLUUID& parcel_id); + + static void processParcelInfoReply(LLMessageSystem* msg, void**); + +private: + typedef std::multimap observer_multimap_t; + observer_multimap_t mObservers; }; #endif // LL_LLREMOTEPARCELREQUEST_H diff --git a/indra/newview/llrootview.h b/indra/newview/llrootview.h new file mode 100644 index 0000000000..f704fecddd --- /dev/null +++ b/indra/newview/llrootview.h @@ -0,0 +1,51 @@ +/** + * @file llrootview.h + * @brief Mother of all Views + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLROOTVIEW_H +#define LL_LLROOTVIEW_H + +#include "llview.h" +#include "lluictrlfactory.h" + +class LLRootViewRegistry : public LLChildRegistry +{}; + +class LLRootView : public LLView +{ +public: + typedef LLRootViewRegistry child_registry_t; + + LLRootView(const Params& p) + : LLView(p) + {} +}; +#endif //LL_LLROOTVIEW_H diff --git a/indra/newview/llsavedsettingsglue.cpp b/indra/newview/llsavedsettingsglue.cpp index 073b51f80e..4736afa7ba 100644 --- a/indra/newview/llsavedsettingsglue.cpp +++ b/indra/newview/llsavedsettingsglue.cpp @@ -39,37 +39,27 @@ #include "llviewercontrol.h" -void LLSavedSettingsGlue::setBOOL(LLUICtrl* ctrl, void* data) +void LLSavedSettingsGlue::setBOOL(LLUICtrl* ctrl, const std::string& name) { - const char* name = (const char*)data; - LLSD value = ctrl->getValue(); - gSavedSettings.setBOOL(name, value.asBoolean()); + gSavedSettings.setBOOL(name, ctrl->getValue().asBoolean()); } -void LLSavedSettingsGlue::setS32(LLUICtrl* ctrl, void* data) +void LLSavedSettingsGlue::setS32(LLUICtrl* ctrl, const std::string& name) { - const char* name = (const char*)data; - LLSD value = ctrl->getValue(); - gSavedSettings.setS32(name, value.asInteger()); + gSavedSettings.setS32(name, ctrl->getValue().asInteger()); } -void LLSavedSettingsGlue::setF32(LLUICtrl* ctrl, void* data) +void LLSavedSettingsGlue::setF32(LLUICtrl* ctrl, const std::string& name) { - const char* name = (const char*)data; - LLSD value = ctrl->getValue(); - gSavedSettings.setF32(name, (F32)value.asReal()); + gSavedSettings.setF32(name, (F32)ctrl->getValue().asReal()); } -void LLSavedSettingsGlue::setU32(LLUICtrl* ctrl, void* data) +void LLSavedSettingsGlue::setU32(LLUICtrl* ctrl, const std::string& name) { - const char* name = (const char*)data; - LLSD value = ctrl->getValue(); - gSavedSettings.setU32(name, (U32)value.asInteger()); + gSavedSettings.setU32(name, (U32)ctrl->getValue().asInteger()); } -void LLSavedSettingsGlue::setString(LLUICtrl* ctrl, void* data) +void LLSavedSettingsGlue::setString(LLUICtrl* ctrl, const std::string& name) { - const char* name = (const char*)data; - LLSD value = ctrl->getValue(); - gSavedSettings.setString(name, value.asString()); + gSavedSettings.setString(name, ctrl->getValue().asString()); } diff --git a/indra/newview/llsavedsettingsglue.h b/indra/newview/llsavedsettingsglue.h index 8a0f36945c..6c8662dd58 100644 --- a/indra/newview/llsavedsettingsglue.h +++ b/indra/newview/llsavedsettingsglue.h @@ -42,11 +42,11 @@ class LLUICtrl; class LLSavedSettingsGlue { public: - static void setBOOL(LLUICtrl* ctrl, void* name); - static void setS32(LLUICtrl* ctrl, void* name); - static void setF32(LLUICtrl* ctrl, void* name); - static void setU32(LLUICtrl* ctrl, void* name); - static void setString(LLUICtrl* ctrl, void* name); + static void setBOOL(LLUICtrl* ctrl, const std::string& name); + static void setS32(LLUICtrl* ctrl, const std::string& name); + static void setF32(LLUICtrl* ctrl, const std::string& name); + static void setU32(LLUICtrl* ctrl, const std::string& name); + static void setString(LLUICtrl* ctrl, const std::string& name); }; #endif diff --git a/indra/newview/llscreenchannel.cpp b/indra/newview/llscreenchannel.cpp new file mode 100644 index 0000000000..68996673be --- /dev/null +++ b/indra/newview/llscreenchannel.cpp @@ -0,0 +1,551 @@ +/** + * @file llscreenchannel.cpp + * @brief Class implements a channel on a screen in which appropriate toasts may appear. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "lliconctrl.h" +#include "lltextbox.h" +#include "llscreenchannel.h" + +#include "lltoastpanel.h" +#include "llviewercontrol.h" +#include "llfloaterreg.h" +#include "lltrans.h" + +#include + +using namespace LLNotificationsUI; + +bool LLScreenChannel::mWasStartUpToastShown = false; + +//-------------------------------------------------------------------------- +LLScreenChannel::LLScreenChannel(LLUUID& id): mOverflowToastPanel(NULL), mStartUpToastPanel(NULL), + mToastAlignment(NA_BOTTOM), mCanStoreToasts(true), + mHiddenToastsNum(0), mOverflowToastHidden(false), + mIsHovering(false), mControlHovering(false), + mShowToasts(false) +{ + mID = id; + + setFollows(FOLLOWS_RIGHT | FOLLOWS_BOTTOM | FOLLOWS_TOP); + + mOverflowFormatString = LLTrans::getString("OverflowInfoChannelString"); + + setMouseOpaque( false ); +} + +void LLScreenChannel::init(S32 channel_left, S32 channel_right) +{ + S32 channel_top = getRootView()->getRect().getHeight() - gSavedSettings.getS32("NavBarMargin"); + S32 channel_bottom = getRootView()->getRect().mBottom + gSavedSettings.getS32("ChannelBottomPanelMargin"); + setRect(LLRect(channel_left, channel_top, channel_right, channel_bottom)); + +} + +//-------------------------------------------------------------------------- +LLScreenChannel::~LLScreenChannel() +{ +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::reshape(S32 width, S32 height, BOOL called_from_parent) +{ + LLUICtrl::reshape(width, height, called_from_parent); + if(mToastAlignment != NA_CENTRE) + showToasts(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::addToast(LLToast::Params p) +{ + bool store_toast = !mShowToasts && p.can_be_stored && mCanStoreToasts; + + if(!mShowToasts && !store_toast) + { + mOnRejectToast(p); + return; + } + + ToastElem new_toast_elem(p); + + mOverflowToastHidden = false; + + new_toast_elem.toast->setOnFadeCallback(boost::bind(&LLScreenChannel::onToastFade, this, new_toast_elem.toast)); + if(mControlHovering) + { + new_toast_elem.toast->setOnToastHoverCallback(boost::bind(&LLScreenChannel::onToastHover, this, _1, _2)); + } + + if(mShowToasts) + { + mToastList.push_back(new_toast_elem); + showToasts(); + } + else // store_toast + { + mHiddenToastsNum++; + storeToast(new_toast_elem); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onToastFade(LLToast* toast) +{ + std::vector::iterator it = find(mToastList.begin(), mToastList.end(), static_cast(toast)); + + bool destroy_toast = !mCanStoreToasts || !toast->getCanBeStored(); + if(destroy_toast) + { + mToastList.erase(it); + toast->mOnToastDestroy(toast); + } + else + { + storeToast((*it)); + mToastList.erase(it); + } + + showToasts(); +} + +//-------------------------------------------------------------------------- + +void LLScreenChannel::storeToast(ToastElem& toast_elem) +{ + // do not store clones + std::vector::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), toast_elem.id); + if( it != mStoredToastList.end() ) + return; + + toast_elem.toast->stopTimer(); + mStoredToastList.push_back(toast_elem); + mOnStoreToast(toast_elem.toast->getPanel(), toast_elem.id); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::loadStoredToastsToChannel() +{ + std::vector::iterator it; + + if(mStoredToastList.size() == 0) + return; + + mOverflowToastHidden = false; + + for(it = mStoredToastList.begin(); it != mStoredToastList.end(); ++it) + { + (*it).toast->resetTimer(); + mToastList.push_back((*it)); + } + + mStoredToastList.clear(); + showToasts(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::loadStoredToastByIDToChannel(LLUUID id) +{ + std::vector::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id); + + if( it == mStoredToastList.end() ) + return; + + mOverflowToastHidden = false; + + LLToast* toast = (*it).toast; + toast->resetTimer(); + mToastList.push_back((*it)); + mStoredToastList.erase(it); + + showToasts(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::removeStoredToastByID(LLUUID id) +{ + // *TODO: may be remove this function + std::vector::iterator it = find(mStoredToastList.begin(), mStoredToastList.end(), id); + + if( it == mStoredToastList.end() ) + return; + + LLToast* toast = (*it).toast; + mStoredToastList.erase(it); + toast->discardNotification(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::killToastByNotificationID(LLUUID id) +{ + // searching among toasts on a screen + std::vector::iterator it = find(mToastList.begin(), mToastList.end(), id); + + if( it != mToastList.end()) + { + LLToast* toast = (*it).toast; + // if it is a notification toast and notification is UnResponded - then respond on it + // else - simply destroy a toast + // + // NOTE: if a notification is unresponded this function will be called twice for the same toast. + // At first, the notification will be discarded, at second (it will be caused by discarding), + // the toast will be destroyed. + if(toast->getIsNotificationUnResponded()) + { + toast->discardNotification(); + } + else + { + mToastList.erase(it); + toast->mOnToastDestroy(toast); + showToasts(); + } + return; + } + + // searching among stored toasts + it = find(mStoredToastList.begin(), mStoredToastList.end(), id); + + if( it != mStoredToastList.end() ) + { + LLToast* toast = (*it).toast; + mStoredToastList.erase(it); + toast->discardNotification(); + toast->mOnToastDestroy(toast); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::modifyToastByNotificationID(LLUUID id, LLPanel* panel) +{ + std::vector::iterator it = find(mToastList.begin(), mToastList.end(), id); + + if( it != mToastList.end() && panel) + { + LLToast* toast = (*it).toast; + LLPanel* old_panel = toast->getPanel(); + toast->removeChild(old_panel); + delete old_panel; + toast->insertPanel(panel); + toast->resetTimer(); + showToasts(); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::showToasts() +{ + if(mToastList.size() == 0 || mIsHovering) + return; + + hideToastsFromScreen(); + + switch(mToastAlignment) + { + case NA_TOP : + showToastsTop(); + break; + + case NA_CENTRE : + showToastsCentre(); + break; + + case NA_BOTTOM : + showToastsBottom(); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::showToastsBottom() +{ + LLRect toast_rect; + S32 bottom = getRect().mBottom; + std::vector::reverse_iterator it; + + for(it = mToastList.rbegin(); it != mToastList.rend(); ++it) + { + if(it != mToastList.rbegin()) + { + bottom = (*(it-1)).toast->getRect().mTop; + } + + toast_rect = (*it).toast->getRect(); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight()); + (*it).toast->setRect(toast_rect); + + bool stop_showing_toasts = (*it).toast->getRect().mTop > getRect().getHeight(); + + if(!stop_showing_toasts) + { + if( it != mToastList.rend()-1) + { + stop_showing_toasts = ((*it).toast->getRect().mTop + gSavedSettings.getS32("OverflowToastHeight") + gSavedSettings.getS32("ToastMargin")) > getRect().getHeight(); + } + } + + if(stop_showing_toasts) + break; + + (*it).toast->setVisible(TRUE); + } + + if(it != mToastList.rend() && !mOverflowToastHidden) + { + mHiddenToastsNum = 0; + for(; it != mToastList.rend(); it++) + { + mHiddenToastsNum++; + } + createOverflowToast(bottom, gSavedSettings.getS32("NotificationToastTime")); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::showToastsCentre() +{ + LLRect toast_rect; + S32 bottom = (getRect().mTop - getRect().mBottom)/2 + mToastList[0].toast->getRect().getHeight()/2; + std::vector::reverse_iterator it; + + for(it = mToastList.rbegin(); it != mToastList.rend(); ++it) + { + toast_rect = (*it).toast->getRect(); + toast_rect.setLeftTopAndSize(getRect().mLeft - toast_rect.getWidth() / 2, bottom + toast_rect.getHeight() / 2 + gSavedSettings.getS32("ToastMargin"), toast_rect.getWidth() ,toast_rect.getHeight()); + (*it).toast->setRect(toast_rect); + + (*it).toast->setVisible(TRUE); + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::showToastsTop() +{ +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::createOverflowToast(S32 bottom, F32 timer) +{ + LLRect toast_rect; + LLToast::Params p; + p.timer_period = timer; + mOverflowToastPanel = new LLToast(p); + + if(!mOverflowToastPanel) + return; + + mOverflowToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onOverflowToastHide, this)); + + LLTextBox* text_box = mOverflowToastPanel->getChild("toast_text"); + LLIconCtrl* icon = mOverflowToastPanel->getChild("icon"); + std::string text = llformat(mOverflowFormatString.c_str(),mHiddenToastsNum); + if(mHiddenToastsNum == 1) + { + text += "."; + } + else + { + text += "s."; + } + + toast_rect = mOverflowToastPanel->getRect(); + mOverflowToastPanel->reshape(getRect().getWidth(), toast_rect.getHeight(), true); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), getRect().getWidth(), toast_rect.getHeight()); + mOverflowToastPanel->setRect(toast_rect); + + text_box->setValue(text); + text_box->setVisible(TRUE); + icon->setVisible(TRUE); + + mOverflowToastPanel->setVisible(TRUE); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onOverflowToastHide() +{ + mOverflowToastHidden = true; +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::closeOverflowToastPanel() +{ + if(mOverflowToastPanel != NULL) + { + mOverflowToastPanel->closeFloater(); + mOverflowToastPanel = NULL; + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::createStartUpToast(S32 notif_num, S32 bottom, F32 timer) +{ + LLRect toast_rect; + LLToast::Params p; + p.timer_period = timer; + mStartUpToastPanel = new LLToast(p); + + if(!mStartUpToastPanel) + return; + + mStartUpToastPanel->setOnFadeCallback(boost::bind(&LLScreenChannel::onStartUpToastHide, this)); + + LLTextBox* text_box = mStartUpToastPanel->getChild("toast_text"); + LLIconCtrl* icon = mStartUpToastPanel->getChild("icon"); + + std::string mStartUpFormatString; + + if(notif_num == 1) + { + mStartUpFormatString = LLTrans::getString("StartUpNotification"); + } + else + { + mStartUpFormatString = LLTrans::getString("StartUpNotifications"); + } + + + std::string text = llformat(mStartUpFormatString.c_str(), notif_num); + + toast_rect = mStartUpToastPanel->getRect(); + mStartUpToastPanel->reshape(getRect().getWidth(), toast_rect.getHeight(), true); + toast_rect.setLeftTopAndSize(getRect().mLeft, bottom + toast_rect.getHeight()+gSavedSettings.getS32("ToastMargin"), getRect().getWidth(), toast_rect.getHeight()); + mStartUpToastPanel->setRect(toast_rect); + + text_box->setValue(text); + text_box->setVisible(TRUE); + icon->setVisible(TRUE); + + mStartUpToastPanel->setVisible(TRUE); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::updateStartUpString(S32 num) +{ + // *TODO: update string if notifications are arriving while the StartUp toast is on a screen +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onStartUpToastHide() +{ + onCommit(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::closeStartUpToast() +{ + if(mStartUpToastPanel != NULL) + { + mStartUpToastPanel->closeFloater(); + mStartUpToastPanel = NULL; + } +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::hideToastsFromScreen() +{ + closeOverflowToastPanel(); + for(std::vector::iterator it = mToastList.begin(); it != mToastList.end(); it++) + (*it).toast->setVisible(FALSE); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::removeToastsFromChannel() +{ + hideToastsFromScreen(); + for(std::vector::iterator it = mToastList.begin(); it != mToastList.end(); it++) + { + // *TODO: ivestigate mOnToastDestroy callback - change name or/and place + (*it).toast->mOnToastDestroy((*it).toast); + } + mToastList.clear(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::removeAndStoreAllVisibleToasts() +{ + if(mToastList.size() == 0) + return; + + hideToastsFromScreen(); + for(std::vector::iterator it = mToastList.begin(); it != mToastList.end(); it++) + { + if((*it).toast->getCanBeStored()) + { + mStoredToastList.push_back(*it); + mOnStoreToast((*it).toast->getPanel(), (*it).id); + (*it).toast->stopTimer(); + } + (*it).toast->setVisible(FALSE); + } + + mToastList.clear(); +} + +//-------------------------------------------------------------------------- +void LLScreenChannel::onToastHover(LLToast* toast, bool mouse_enter) +{ + // because of LLViewerWindow::updateUI() that ALWAYS calls onMouseEnter BEFORE onMouseLeave + // we must check this to prevent incorrect setting for hovering in a channel + std::map::iterator it_first, it_second; + S32 stack_size = mToastEventStack.size(); + mIsHovering = mouse_enter; + + switch(stack_size) + { + case 0: + mToastEventStack.insert(std::pair(toast, mouse_enter)); + break; + case 1: + it_first = mToastEventStack.begin(); + if((*it_first).second && !mouse_enter && ((*it_first).first != toast) ) + { + mToastEventStack.clear(); + mIsHovering = true; + } + else + { + mToastEventStack.clear(); + mToastEventStack.insert(std::pair(toast, mouse_enter)); + } + break; + default: + LL_ERRS ("LLScreenChannel::onToastHover: stack size error " ) << stack_size << llendl; + } + + if(!mIsHovering) + showToasts(); +} + +//-------------------------------------------------------------------------- + + + + diff --git a/indra/newview/llscreenchannel.h b/indra/newview/llscreenchannel.h new file mode 100644 index 0000000000..746580b574 --- /dev/null +++ b/indra/newview/llscreenchannel.h @@ -0,0 +1,216 @@ +/** + * @file llscreenchannel.h + * @brief Class implements a channel on a screen in which appropriate toasts may appear. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSCREENCHANNEL_H +#define LL_LLSCREENCHANNEL_H + +#include "lltoast.h" + +#include +#include + +namespace LLNotificationsUI +{ + +typedef enum e_notification_toast_alignment +{ + NA_TOP, + NA_CENTRE, + NA_BOTTOM, +} EToastAlignment; + + +/** + * Screen channel manages toasts visibility and positioning on the screen. + */ +class LLScreenChannel : public LLUICtrl +{ + friend class LLChannelManager; +public: + LLScreenChannel(LLUUID& id); + virtual ~LLScreenChannel(); + + // Channel's outfit-functions + // classic reshape + void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE); + // initialization of channel's shape and position + void init(S32 channel_left, S32 channel_right); + // set allignment of toasts inside a channel + void setToastAlignment(e_notification_toast_alignment align) {mToastAlignment = align;} + // set a template for a string in the OverflowToast + void setOverflowFormatString ( std::string str) { mOverflowFormatString = str; } + + // Operating with toasts + // add a toast to a channel + void addToast(LLToast::Params p); + // kill or modify a toast by its ID + void killToastByNotificationID(LLUUID id); + void modifyToastByNotificationID(LLUUID id, LLPanel* panel); + // hide all toasts from screen, but not remove them from a channel + void hideToastsFromScreen(); + // removes all toasts from a channel + void removeToastsFromChannel(); + // show all toasts in a channel + void showToasts(); + // + void loadStoredToastsToChannel(); + // finds a toast among stored by its ID and throws it on a screen to a channel + void loadStoredToastByIDToChannel(LLUUID id); + // removes a toast from stored finding it by its ID + void removeStoredToastByID(LLUUID id); + // remove all toasts from screen and store them + void removeAndStoreAllVisibleToasts(); + // close the Overflow Toast + void closeOverflowToastPanel(); + // close the StartUp Toast + void closeStartUpToast(); + + // Channel's behavior-functions + // set whether a channel will control hovering inside itself or not + void setControlHovering(bool control) { mControlHovering = control; } + // set Hovering flag for a channel + void setHovering(bool hovering) { mIsHovering = hovering; } + // set whether a channel will store faded toasts or not + void setCanStoreToasts(bool store) { mCanStoreToasts = store; } + // tell all channels that the StartUp toast was shown and allow them showing of toasts + static void setStartUpToastShown() { mWasStartUpToastShown = true; } + // get StartUp Toast's state + static bool getStartUpToastShown() { return mWasStartUpToastShown; } + // set mode for dislaying of toasts + void setDisplayToastsAlways(bool display_toasts) { mDisplayToastsAlways = display_toasts; } + // get mode for dislaying of toasts + bool getDisplayToastsAlways() { return mDisplayToastsAlways; } + // tell a channel to show toasts or not + void setShowToasts(bool show) { mShowToasts = show; } + // determine whether channel shows toasts or not + bool getShowToasts() { return mShowToasts; } + + // Channel's other interface functions functions + // get number of hidden notifications from a channel + S32 getNumberOfHiddenToasts() { return mHiddenToastsNum;} + // update number of notifications in the StartUp Toast + void updateStartUpString(S32 num); + // get toast allignment preset for a channel + e_notification_toast_alignment getToastAlignment() {return mToastAlignment;} + // get ID of a channel + LLUUID getChannelID() { return mID; } + + // Channel's callbacks + // callback for storing of faded toasts + typedef boost::function store_tost_callback_t; + typedef boost::signals2::signal store_tost_signal_t; + store_tost_signal_t mOnStoreToast; + boost::signals2::connection setOnStoreToastCallback(store_tost_callback_t cb) { return mOnStoreToast.connect(cb); } + // callback for discarding of a rejected toast + typedef boost::function reject_tost_callback_t; + typedef boost::signals2::signal reject_tost_signal_t; + reject_tost_signal_t mOnRejectToast; + boost::signals2::connection setOnRejectToastCallback(reject_tost_callback_t cb) { return mOnRejectToast.connect(cb); } + +private: + struct ToastElem + { + LLUUID id; + LLToast* toast; + + ToastElem(LLToast::Params p) : id(p.id) + { + toast = new LLToast(p); + } + + ToastElem(const ToastElem& toast_elem) + { + id = toast_elem.id; + toast = toast_elem.toast; + } + + bool operator == (const LLUUID &id_op) const + { + return (id == id_op); + } + + bool operator == (LLPanel* panel_op) const + { + return (toast == panel_op); + } + }; + + // Channel's handlers + void onToastHover(LLToast* toast, bool mouse_enter); + void onToastFade(LLToast* toast); + void onOverflowToastHide(); + void onStartUpToastHide(); + + // + void storeToast(ToastElem& toast_elem); + + // show-functions depending on allignment of toasts + void showToastsBottom(); + void showToastsCentre(); + void showToastsTop(); + + // create the Overflow Toast + void createOverflowToast(S32 bottom, F32 timer); + + // create the StartUp Toast + void createStartUpToast(S32 notif_num, S32 bottom, F32 timer); + + // Channel's flags + static bool mWasStartUpToastShown; + bool mControlHovering; + bool mIsHovering; + bool mCanStoreToasts; + bool mDisplayToastsAlways; + bool mOverflowToastHidden; + // controls whether a channel shows toasts or not + bool mShowToasts; + // + e_notification_toast_alignment mToastAlignment; + + // attributes for the Overflow Toast + S32 mHiddenToastsNum; + LLToast* mOverflowToastPanel; + std::string mOverflowFormatString; + + // attributes for the StartUp Toast + LLToast* mStartUpToastPanel; + + // channel's ID + LLUUID mID; + + std::vector mToastList; + std::vector mStoredToastList; + std::map mToastEventStack; +}; + +} +#endif diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 0c6b2980dc..32fe996125 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -57,8 +57,10 @@ #include "llfloaterinspect.h" #include "llfloaterproperties.h" #include "llfloaterreporter.h" +#include "llfloaterreg.h" #include "llfloatertools.h" #include "llframetimer.h" +#include "llfocusmgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llinventorymodel.h" @@ -73,13 +75,15 @@ #include "llui.h" #include "llviewercamera.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" #include "llviewermenu.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerstats.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvovolume.h" #include "pipeline.h" @@ -100,10 +104,10 @@ const S32 MAX_OBJECTS_PER_PACKET = 254; // Globals // -BOOL gDebugSelectMgr = FALSE; +//BOOL gDebugSelectMgr = FALSE; -BOOL gHideSelectedObjects = FALSE; -BOOL gAllowSelectAvatar = FALSE; +//BOOL gHideSelectedObjects = FALSE; +//BOOL gAllowSelectAvatar = FALSE; BOOL LLSelectMgr::sRectSelectInclusive = TRUE; BOOL LLSelectMgr::sRenderHiddenSelections = TRUE; @@ -172,6 +176,9 @@ LLObjectSelection *get_null_object_selection() // LLSelectMgr() //----------------------------------------------------------------------------- LLSelectMgr::LLSelectMgr() + : mHideSelectedObjects(LLCachedControl(gSavedSettings, "HideSelectedObjects", FALSE)), + mAllowSelectAvatar( LLCachedControl(gSavedSettings, "AllowSelectAvatar", FALSE)), + mDebugSelectMgr(LLCachedControl(gSavedSettings, "DebugSelectMgr", FALSE)) { mTEMode = FALSE; mLastCameraPos.clearVec(); @@ -184,12 +191,12 @@ LLSelectMgr::LLSelectMgr() sHighlightUAnim = gSavedSettings.getF32("SelectionHighlightUAnim"); sHighlightVAnim = gSavedSettings.getF32("SelectionHighlightVAnim"); - sSilhouetteParentColor = gColors.getColor("SilhouetteParentColor"); - sSilhouetteChildColor = gColors.getColor("SilhouetteChildColor"); - sHighlightParentColor = gColors.getColor("HighlightParentColor"); - sHighlightChildColor = gColors.getColor("HighlightChildColor"); - sHighlightInspectColor = gColors.getColor("HighlightInspectColor"); - sContextSilhouetteColor = gColors.getColor("ContextSilhouetteColor")*0.5f; + sSilhouetteParentColor =LLUIColorTable::instance().getColor("SilhouetteParentColor"); + sSilhouetteChildColor = LLUIColorTable::instance().getColor("SilhouetteChildColor"); + sHighlightParentColor = LLUIColorTable::instance().getColor("HighlightParentColor"); + sHighlightChildColor = LLUIColorTable::instance().getColor("HighlightChildColor"); + sHighlightInspectColor = LLUIColorTable::instance().getColor("HighlightInspectColor"); + sContextSilhouetteColor = LLUIColorTable::instance().getColor("ContextSilhouetteColor")*0.5f; sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius"); @@ -202,6 +209,8 @@ LLSelectMgr::LLSelectMgr() mSelectedObjects = new LLObjectSelection(); mHoverObjects = new LLObjectSelection(); mHighlightedObjects = new LLObjectSelection(); + + } @@ -673,7 +682,7 @@ void LLSelectMgr::addAsFamily(std::vector& objects, BOOL add_to // Can't select yourself if (objectp->mID == gAgentID - && !gAllowSelectAvatar) + && !LLSelectMgr::getInstance()->mAllowSelectAvatar) { continue; } @@ -768,7 +777,7 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab } -LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp) +LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp, S32 face) { // Always blitz hover list when setting mHoverObjects->deleteAllNodes(); @@ -800,6 +809,7 @@ LLObjectSelectionHandle LLSelectMgr::setHoverObject(LLViewerObject *objectp) { LLViewerObject* cur_objectp = *iter; LLSelectNode* nodep = new LLSelectNode(cur_objectp, FALSE); + nodep->selectTE(face, TRUE); mHoverObjects->addNodeAtEnd(nodep); } @@ -824,8 +834,8 @@ void LLSelectMgr::highlightObjectOnly(LLViewerObject* objectp) return; } - if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) || - (gSavedSettings.getBOOL("SelectMovableOnly") && !objectp->permMove())) + if ((gSavedSettings.getBOOL("SelectOwnedOnly") && !objectp->permYouOwner()) + || (gSavedSettings.getBOOL("SelectMovableOnly") && !objectp->permMove())) { // only select my own objects return; @@ -1419,7 +1429,7 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid) // Texture picker defaults aren't inventory items // * Don't need to worry about permissions for them // * Can just apply the texture and be done with it. - objectp->setTEImage(te, gImageList.getImage(mImageID, TRUE, FALSE)); + objectp->setTEImage(te, LLViewerTextureManager::getFetchedTexture(mImageID, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE)); } return true; } @@ -1575,7 +1585,7 @@ BOOL LLSelectMgr::selectionRevertTextures() } else { - object->setTEImage(te, gImageList.getImage(id)); + object->setTEImage(te, LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE)); } } } @@ -2691,7 +2701,7 @@ void LLSelectMgr::selectDelete() } LLNotification::Params params("ConfirmObjectDeleteLock"); - params.functor(boost::bind(&LLSelectMgr::confirmDelete, _1, _2, getSelection())); + params.functor.function(boost::bind(&LLSelectMgr::confirmDelete, _1, _2, getSelection())); if(locked_but_deleteable_object || no_copy_but_deleteable_object || @@ -3443,7 +3453,7 @@ void LLSelectMgr::deselectAllIfTooFar() if (select_dist_sq > deselect_dist_sq) { - if (gDebugSelectMgr) + if (mDebugSelectMgr) { llinfos << "Selection manager: auto-deselecting, select_dist = " << fsqrtf(select_dist_sq) << llendl; llinfos << "agent pos global = " << gAgent.getPositionGlobal() << llendl; @@ -4444,10 +4454,9 @@ void LLSelectMgr::processObjectPropertiesFamily(LLMessageSystem* msg, void** use msg->getStringFast(_PREHASH_ObjectData, _PREHASH_Description, desc); // the reporter widget askes the server for info about picked objects - if (request_flags & (COMPLAINT_REPORT_REQUEST | BUG_REPORT_REQUEST)) + if (request_flags & COMPLAINT_REPORT_REQUEST ) { - EReportType report_type = (COMPLAINT_REPORT_REQUEST & request_flags) ? COMPLAINT_REPORT : BUG_REPORT; - LLFloaterReporter *reporterp = LLFloaterReporter::getReporter(report_type); + LLFloaterReporter *reporterp = LLFloaterReg::findTypedInstance("reporter"); if (reporterp) { std::string fullname; @@ -4538,7 +4547,7 @@ void LLSelectMgr::updateSilhouettes() if (!mSilhouetteImagep) { - mSilhouetteImagep = gImageList.getImageFromFile("silhouette.j2c", TRUE, TRUE); + mSilhouetteImagep = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", TRUE, TRUE); } mHighlightedObjects->cleanupNodes(); @@ -4560,54 +4569,7 @@ void LLSelectMgr::updateSilhouettes() std::vector changed_objects; - if (mSelectedObjects->getNumNodes()) - { - //gGLSPipelineSelection.set(); - - //mSilhouetteImagep->bindTexture(); - //glAlphaFunc(GL_GREATER, sHighlightAlphaTest); - - for (S32 pass = 0; pass < 2; pass++) - { - for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); - iter != mSelectedObjects->end(); iter++) - { - LLSelectNode* node = *iter; - LLViewerObject* objectp = node->getObject(); - if (!objectp) - continue; - // do roots first, then children so that root flags are cleared ASAP - BOOL roots_only = (pass == 0); - BOOL is_root = (objectp->isRootEdit()); - if (roots_only != is_root || objectp->mDrawable.isNull()) - { - continue; - } - - if (!node->mSilhouetteExists - || objectp->isChanged(LLXform::SILHOUETTE) - || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE))) - { - if (num_sils_genned++ < MAX_SILS_PER_FRAME)// && objectp->mDrawable->isVisible()) - { - generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin()); - changed_objects.push_back(objectp); - } - else if (objectp->isAttachment()) - { - //RN: hack for orthogonal projection of HUD attachments - LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent(); - if (attachment_pt && attachment_pt->getIsHUDAttachment()) - { - LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f); - generateSilhouette(node, camera_pos); - } - } - } - } - } - } - + updateSelectionSilhouette(mSelectedObjects, num_sils_genned, changed_objects); if (mRectSelectedObjects.size() > 0) { //gGLSPipelineSelection.set(); @@ -4801,6 +4763,56 @@ void LLSelectMgr::updateSilhouettes() //gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } +void LLSelectMgr::updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector& changed_objects) +{ + if (object_handle->getNumNodes()) + { + //gGLSPipelineSelection.set(); + + //mSilhouetteImagep->bindTexture(); + //glAlphaFunc(GL_GREATER, sHighlightAlphaTest); + + for (S32 pass = 0; pass < 2; pass++) + { + for (LLObjectSelection::iterator iter = object_handle->begin(); + iter != object_handle->end(); iter++) + { + LLSelectNode* node = *iter; + LLViewerObject* objectp = node->getObject(); + if (!objectp) + continue; + // do roots first, then children so that root flags are cleared ASAP + BOOL roots_only = (pass == 0); + BOOL is_root = (objectp->isRootEdit()); + if (roots_only != is_root || objectp->mDrawable.isNull()) + { + continue; + } + + if (!node->mSilhouetteExists + || objectp->isChanged(LLXform::SILHOUETTE) + || (objectp->getParent() && objectp->getParent()->isChanged(LLXform::SILHOUETTE))) + { + if (num_sils_genned++ < MAX_SILS_PER_FRAME)// && objectp->mDrawable->isVisible()) + { + generateSilhouette(node, LLViewerCamera::getInstance()->getOrigin()); + changed_objects.push_back(objectp); + } + else if (objectp->isAttachment()) + { + //RN: hack for orthogonal projection of HUD attachments + LLViewerJointAttachment* attachment_pt = (LLViewerJointAttachment*)objectp->getRootEdit()->mDrawable->getParent(); + if (attachment_pt && attachment_pt->getIsHUDAttachment()) + { + LLVector3 camera_pos = LLVector3(-10000.f, 0.f, 0.f); + generateSilhouette(node, camera_pos); + } + } + } + } + } + } +} void LLSelectMgr::renderSilhouettes(BOOL for_hud) { if (!mRenderSilhouettes) @@ -4808,7 +4820,7 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) return; } - gGL.getTexUnit(0)->bind(mSilhouetteImagep.get()); + gGL.getTexUnit(0)->bind(mSilhouetteImagep); LLGLSPipelineSelection gls_select; gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.f); LLGLEnable blend(GL_BLEND); @@ -4837,8 +4849,13 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) } if (mSelectedObjects->getNumNodes()) { - LLUUID inspect_item_id = LLFloaterInspect::getSelectedUUID(); - + LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance("inspect"); + LLUUID inspect_item_id= LLUUID::null; + if(inspect_instance) + { + inspect_item_id = inspect_instance->getSelectedUUID(); + } + LLUUID focus_item_id = LLViewerMediaFocus::getInstance()->getSelectedUUID(); for (S32 pass = 0; pass < 2; pass++) { for (LLObjectSelection::iterator iter = mSelectedObjects->begin(); @@ -4852,7 +4869,11 @@ void LLSelectMgr::renderSilhouettes(BOOL for_hud) { continue; } - if(objectp->getID() == inspect_item_id) + if (objectp->getID() == focus_item_id) + { + node->renderOneSilhouette(gFocusMgr.getFocusColor()); + } + else if(objectp->getID() == inspect_item_id) { node->renderOneSilhouette(sHighlightInspectColor); } @@ -4934,6 +4955,16 @@ void LLSelectMgr::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_ // Utility classes // LLSelectNode::LLSelectNode(LLViewerObject* object, BOOL glow) +: mObject(object), + mIndividualSelection(FALSE), + mTransient(FALSE), + mValid(FALSE), + mPermissions(new LLPermissions()), + mInventorySerial(0), + mSilhouetteExists(FALSE), + mDuplicated(FALSE), + mTESelectMask(0), + mLastTESelected(0) { mObject = object; selectAllTEs(FALSE); @@ -4955,11 +4986,7 @@ LLSelectNode::LLSelectNode(LLViewerObject* object, BOOL glow) LLSelectNode::LLSelectNode(const LLSelectNode& nodep) { - S32 i; - for (i = 0; i < SELECT_MAX_TES; i++) - { - mTESelected[i] = nodep.mTESelected[i]; - } + mTESelectMask = nodep.mTESelectMask; mLastTESelected = nodep.mLastTESelected; mIndividualSelection = nodep.mIndividualSelection; @@ -5012,10 +5039,7 @@ LLSelectNode::~LLSelectNode() void LLSelectNode::selectAllTEs(BOOL b) { - for (S32 i = 0; i < SELECT_MAX_TES; i++) - { - mTESelected[i] = b; - } + mTESelectMask = b ? 0xFFFFFFFF : 0x0; mLastTESelected = 0; } @@ -5025,7 +5049,7 @@ void LLSelectNode::selectTE(S32 te_index, BOOL selected) { return; } - mTESelected[te_index] = selected; + mTESelectMask |= 0x1 << te_index; mLastTESelected = te_index; } @@ -5035,7 +5059,7 @@ BOOL LLSelectNode::isTESelected(S32 te_index) { return FALSE; } - return mTESelected[te_index]; + return (mTESelectMask & (0x1 << te_index)) != 0; } S32 LLSelectNode::getLastSelectedTE() @@ -5387,10 +5411,7 @@ void dialog_refresh_all() gFloaterTools->dirty(); - if( gPieObject->getVisible() ) - { - gPieObject->arrange(); - } + gPieObject->needsArrange(); if( gPieAttachment->getVisible() ) { @@ -5398,7 +5419,12 @@ void dialog_refresh_all() } LLFloaterProperties::dirtyAll(); - LLFloaterInspect::dirty(); + + LLFloaterInspect* inspect_instance = LLFloaterReg::getTypedInstance("inspect"); + if(inspect_instance) + { + inspect_instance->dirty(); + } } S32 get_family_count(LLViewerObject *parent) diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index d6c4b5485d..c41a86e355 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -38,7 +38,8 @@ #include "llstring.h" #include "llundo.h" #include "lluuid.h" -#include "llmemory.h" +#include "llpointer.h" +#include "llsafehandle.h" #include "llsaleinfo.h" #include "llcategory.h" #include "v3dmath.h" @@ -48,12 +49,12 @@ #include "llbbox.h" #include "llpermissions.h" #include "llviewerobject.h" - +#include "llcontrol.h" #include #include "boost/iterator/filter_iterator.hpp" class LLMessageSystem; -class LLViewerImage; +class LLViewerTexture; class LLViewerObject; class LLColor4; class LLVector3; @@ -138,6 +139,7 @@ public: void selectTE(S32 te_index, BOOL selected); BOOL isTESelected(S32 te_index); S32 getLastSelectedTE(); + S32 getTESelectMask() { return mTESelectMask; } void renderOneSilhouette(const LLColor4 &color); void setTransient(BOOL transient) { mTransient = transient; } BOOL isTransient() { return mTransient; } @@ -190,7 +192,7 @@ public: protected: LLPointer mObject; - BOOL mTESelected[SELECT_MAX_TES]; + S32 mTESelectMask; S32 mLastTESelected; }; @@ -338,6 +340,7 @@ public: static BOOL sRectSelectInclusive; // do we need to surround an object to pick it? static BOOL sRenderHiddenSelections; // do we show selection silhouettes that are occluded? static BOOL sRenderLightRadius; // do we show the radius of selected lights? + static F32 sHighlightThickness; static F32 sHighlightUScale; static F32 sHighlightVScale; @@ -352,6 +355,10 @@ public: static LLColor4 sHighlightInspectColor; static LLColor4 sContextSilhouetteColor; + LLCachedControl mHideSelectedObjects; + LLCachedControl mAllowSelectAvatar; + LLCachedControl mDebugSelectMgr; + public: LLSelectMgr(); ~LLSelectMgr(); @@ -403,7 +410,7 @@ public: // converts all objects currently highlighted to a selection, and returns it LLObjectSelectionHandle selectHighlightedObjects(); - LLObjectSelectionHandle setHoverObject(LLViewerObject *objectp); + LLObjectSelectionHandle setHoverObject(LLViewerObject *objectp, S32 face = -1); void highlightObjectOnly(LLViewerObject *objectp); void highlightObjectAndFamily(LLViewerObject *objectp); @@ -643,6 +650,7 @@ private: ESelectType getSelectTypeForObject(LLViewerObject* object); void addAsFamily(std::vector& objects, BOOL add_to_end = FALSE); void generateSilhouette(LLSelectNode *nodep, const LLVector3& view_point); + void updateSelectionSilhouette(LLObjectSelectionHandle object_handle, S32& num_sils_genned, std::vector& changed_objects); // Send one message to each region containing an object on selection list. void sendListToRegions( const std::string& message_name, void (*pack_header)(void *user_data), @@ -650,6 +658,7 @@ private: void *user_data, ESendType send_type); + static void packAgentID( void *); static void packAgentAndSessionID(void* user_data); static void packAgentAndGroupID(void* user_data); @@ -684,7 +693,7 @@ private: static bool confirmDelete(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle); private: - LLPointer mSilhouetteImagep; + LLPointer mSilhouetteImagep; LLObjectSelectionHandle mSelectedObjects; LLObjectSelectionHandle mHoverObjects; LLObjectSelectionHandle mHighlightedObjects; diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp new file mode 100644 index 0000000000..afa8e5f072 --- /dev/null +++ b/indra/newview/llsidetray.cpp @@ -0,0 +1,687 @@ +/** + * @file llsidetray.cpp + * @brief SideBar implementation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltextbox.h" + +#include "llbottomtray.h" +#include "llsidetray.h" +#include "llviewerwindow.h" +#include "llaccordionctrl.h" +#include "llfocusmgr.h" +#include "llrootview.h" +#include "llnavigationbar.h" + +#include "llaccordionctrltab.h" + +#include "llfloater.h" //for gFloaterView +#include "lliconctrl.h"//for Home tab icon +#include "llsidetraypanelcontainer.h" +#include "llwindow.h"//for SetCursor + +//#include "llscrollcontainer.h" + +using namespace std; + +static LLRootViewRegistry::Register t1("side_tray"); +static LLDefaultChildRegistry::Register t2("sidetray_tab"); + +static const std::string COLLAPSED_NAME = "<<"; +static const std::string EXPANDED_NAME = ">>"; + +static const std::string TAB_PANEL_CAPTION_NAME = "sidetray_tab_panel"; +static const std::string TAB_PANEL_CAPTION_TITLE_BOX = "sidetray_tab_title"; + +LLSideTray* LLSideTray::sInstance = 0; + +class LLSideTrayInfoPanel: public LLPanel +{ + +public: + LLSideTrayInfoPanel():LLPanel() + { + setBorderVisible(true); + } + + BOOL handleHover(S32 x, S32 y, MASK mask) + { + getWindow()->setCursor(UI_CURSOR_HAND); + return TRUE; + } + + BOOL handleMouseUp(S32 x, S32 y, MASK mask) + { + std::string name = getName(); + onCommit(); + LLSideTray::getInstance()->selectTabByName(name); + return LLPanel::handleMouseUp(x,y,mask); + } + void reshape (S32 width, S32 height, BOOL called_from_parent ) + { + return LLPanel::reshape(width, height, called_from_parent); + } + +}; + +static LLRegisterPanelClassWrapper t_people("panel_sidetray_home_info"); + +LLSideTray* LLSideTray::getInstance() +{ + if (!sInstance) + { + sInstance = LLUICtrlFactory::createFromFile("panel_side_tray.xml",gViewerWindow->getRootView(), LLRootView::child_registry_t::instance()); + } + + return sInstance; +} + +bool LLSideTray::instanceCreated () +{ + return sInstance!=0; +} + +LLSideTrayTab::LLSideTrayTab(const Params& params):mMainPanel(0) +{ + mImagePath = params.image_path; + mTabTitle = params.tab_title; + mDescription = params.description; + + // Necessary for focus movement among child controls + setFocusRoot(TRUE); +} + +LLSideTrayTab::~LLSideTrayTab() +{ +} + +bool LLSideTrayTab::addChild(LLView* view, S32 tab_group) +{ + if(mMainPanel == 0 && TAB_PANEL_CAPTION_NAME != view->getName())//skip our caption panel + mMainPanel = view; + return LLPanel::addChild(view,tab_group); + //return res; +} + + + +//virtual +BOOL LLSideTrayTab::postBuild() +{ + LLPanel* title_panel = LLUICtrlFactory::getInstance()->createFromFile("panel_side_tray_tab_caption.xml",this, child_registry_t::instance()); + string name = title_panel->getName(); + LLPanel::addChild(title_panel); + + title_panel->getChild(TAB_PANEL_CAPTION_TITLE_BOX)->setValue(mTabTitle); + + static LLUIColor default_background_color = LLUIColorTable::instance().getColor("FloaterDefaultBackgroundColor"); + static LLUIColor focus_background_color = LLUIColorTable::instance().getColor("FloaterFocusBackgroundColor"); + + setTransparentColor(default_background_color); + setBackgroundColor(focus_background_color); + + return true; +} + +static const S32 splitter_margin = 1; + +//virtual +void LLSideTrayTab::arrange(S32 width, S32 height ) +{ + if(!mMainPanel) + return; + + S32 offset = 0; + + LLView* title_panel = findChildView(TAB_PANEL_CAPTION_NAME, true); + + if(title_panel) + { + title_panel->setOrigin( 0, height - title_panel->getRect().getHeight() ); + offset = title_panel->getRect().getHeight(); + } + + LLRect sRect = mMainPanel->getRect(); + sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); + mMainPanel->reshape(sRect.getWidth(),sRect.getHeight()); + mMainPanel->setRect(sRect); + + + +} + +void LLSideTrayTab::reshape (S32 width, S32 height, BOOL called_from_parent ) +{ + if(!mMainPanel) + return; + S32 offset = 0; + + LLView* title_panel = findChildView(TAB_PANEL_CAPTION_NAME, true); + + if(title_panel) + { + title_panel->setOrigin( 0, height - title_panel->getRect().getHeight() ); + title_panel->reshape(width,title_panel->getRect().getHeight()); + offset = title_panel->getRect().getHeight(); + } + + + + LLRect sRect = mMainPanel->getRect(); + sRect.setLeftTopAndSize( splitter_margin, height - offset - splitter_margin, width - 2*splitter_margin, height - offset - 2*splitter_margin); + //mMainPanel->setMaxWidth(sRect.getWidth()); + mMainPanel->reshape(sRect.getWidth(), sRect.getHeight()); + + mMainPanel->setRect(sRect); + +} + +void LLSideTrayTab::draw() +{ + LLPanel::draw(); + + //border + gl_rect_2d(0,0,getRect().getWidth() - 1,getRect().getHeight() - 1,LLColor4::black,false); + + +} + +void LLSideTrayTab::onOpen (const LLSD& key) +{ + LLPanel* panel = dynamic_cast(mMainPanel); + if(panel) + panel->onOpen(key); +} + +LLSideTrayTab* LLSideTrayTab::createInstance () +{ + LLSideTrayTab::Params tab_params; + tab_params.tab_title("Home"); + + LLSideTrayTab* tab = LLUICtrlFactory::create(tab_params); + return tab; +} + + +//virtual +LLSideTray::LLSideTray(Params& params) + : LLPanel(params) + ,mActiveTab(0) + ,mCollapsed(false) + ,mCollapseButton(0) + ,mMaxBarWidth(params.rect.width) +{ + mCollapsed=params.collapsed; +} + + +BOOL LLSideTray::postBuild() +{ + createButtons(); + + arrange(); + selectTabByName("sidebar_home"); + + if(mCollapsed) + collapseSideBar(); + + setMouseOpaque(false); + return true; +} + +/** + * add new panel to tab with tab_name name + * @param tab_name - name of sidebar tab to add new panel + * @param panel - pointer to panel + */ +bool LLSideTray::addPanel ( const std::string& tab_name + ,LLPanel* panel ) +{ + return false; +} +/** + * Add new tab to side bar + * @param tab_name - name of the new tab + * @param image - image for new sidebar button + * @param title - title for new tab + */ +bool LLSideTray::addTab ( const std::string& tab_name + ,const std::string& image + ,const std::string& title) +{ + LLSideTrayTab::Params params; + params.image_path = image; + params.tab_title = title; + LLSideTrayTab* tab = LLUICtrlFactory::create (params); + addChild(tab,1); + return true; +} + + +LLSideTrayTab* LLSideTray::getTab(const std::string& name) +{ + return getChild(name,false); +} + + + +void LLSideTray::toggleTabButton (LLSideTrayTab* tab) +{ + if(tab == NULL) + return; + string name = tab->getName(); + std::map::iterator tIt = mTabButtons.find(name); + if(tIt!=mTabButtons.end()) + tIt->second->setToggleState(!tIt->second->getToggleState()); +} + +bool LLSideTray::selectTabByIndex(size_t index) +{ + if(index>=mTabs.size()) + return false; + + LLSideTrayTab* sidebar_tab = dynamic_cast(mTabs[index]); + if(sidebar_tab == NULL) + return false; + return selectTabByName(sidebar_tab->getName()); +} + +bool LLSideTray::selectTabByName (const std::string& name) +{ + LLSideTrayTab* side_bar = getTab(name); + + if(side_bar == mActiveTab) + return false; + //deselect old tab + toggleTabButton(mActiveTab); + if(mActiveTab) + mActiveTab->setVisible(false); + + //select new tab + mActiveTab = side_bar; + toggleTabButton(mActiveTab); + LLSD key;//empty + mActiveTab->onOpen(key); + + mActiveTab->setVisible(true); + + //arrange(); + + //hide all tabs - show active tab + child_vector_const_iter_t child_it; + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + sidebar_tab->setVisible(sidebar_tab == mActiveTab); + } + return true; +} + +LLButton* LLSideTray::createButton (const std::string& name,const std::string& image,LLUICtrl::commit_callback_t callback) +{ + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + + LLButton::Params bparams; + + LLRect rect; + rect.setOriginAndSize(0, 0, sidetray_params.default_button_width, sidetray_params.default_button_height); + + bparams.name(name); + bparams.follows.flags (FOLLOWS_LEFT | FOLLOWS_BOTTOM); + bparams.rect (rect); + bparams.tab_stop(false); + bparams.image_unselected.name(sidetray_params.tab_btn_image_normal); + bparams.image_selected.name(sidetray_params.tab_btn_image_selected); + bparams.image_disabled.name(sidetray_params.tab_btn_image_normal); + bparams.image_disabled_selected.name(sidetray_params.tab_btn_image_selected); + + LLButton* button = LLUICtrlFactory::create (bparams); + button->setLabel(name); + button->setClickedCallback(callback); + + if(image.length()) + { + button->setImageOverlay(image); + } + + addChildInBack(button); + + return button; +} + +bool LLSideTray::addChild(LLView* view, S32 tab_group) +{ + LLSideTrayTab* tab_panel = dynamic_cast(view); + + if (tab_panel) + { + mTabs.push_back(tab_panel); + } + + return LLUICtrl::addChild(view, tab_group); +} + + +void LLSideTray::createButtons () +{ + //create show/hide button + mCollapseButton = createButton(EXPANDED_NAME,"",boost::bind(&LLSideTray::onToggleCollapse, this)); + + //create buttons for tabs + child_vector_const_iter_t child_it = mTabs.begin(); + ++child_it; + + for ( ; child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + + string name = sidebar_tab->getName(); + + LLButton* button = createButton("",sidebar_tab->mImagePath,boost::bind(&LLSideTray::onTabButtonClick, this, sidebar_tab->getName())); + mTabButtons[sidebar_tab->getName()] = button; + } + +} + +void LLSideTray::onTabButtonClick(string name) +{ + + selectTabByName (name); + if(mCollapsed) + expandSideBar(); +} + +void LLSideTray::onToggleCollapse() +{ + if(mCollapsed) + { + expandSideBar(); + selectTabByName("sidebar_home"); + } + else + collapseSideBar(); +} + + +void LLSideTray::reflectCollapseChange() +{ + setPanelRect(); + + if(mCollapsed) + gFloaterView->setSnapOffsetRight(0); + else + gFloaterView->setSnapOffsetRight(mMaxBarWidth); + + gFloaterView->refresh(); + + setFocus( FALSE ); +} + +void LLSideTray::arrange () +{ + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + + setPanelRect(); + + LLRect ctrl_rect; + ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-sidetray_params.default_button_width + ,sidetray_params.default_button_width + ,sidetray_params.default_button_height); + + mCollapseButton->setRect(ctrl_rect); + + //arrange tab buttons + //arrange tab buttons + child_vector_const_iter_t child_it; + int offset = (sidetray_params.default_button_height+sidetray_params.default_button_margin)*2; + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + + ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-offset + ,sidetray_params.default_button_width + ,sidetray_params.default_button_height); + + if(mTabButtons.find(sidebar_tab->getName()) == mTabButtons.end()) + continue; + + LLButton* btn = mTabButtons[sidebar_tab->getName()]; + + btn->setRect(ctrl_rect); + offset+=sidetray_params.default_button_height; + offset+=sidetray_params.default_button_margin; + + btn->setVisible(ctrl_rect.mBottom > 0); + } + + ctrl_rect.setLeftTopAndSize(sidetray_params.default_button_width,getRect().getHeight(),mMaxBarWidth,getRect().getHeight()); + + //arrange tabs + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + + sidebar_tab->setRect(ctrl_rect); + sidebar_tab->arrange(mMaxBarWidth,getRect().getHeight()); + } +} + +void LLSideTray::collapseSideBar () +{ + mCollapsed = true; + mCollapseButton->setLabel(COLLAPSED_NAME); + mActiveTab->setVisible(FALSE); + reflectCollapseChange(); + setFocus( FALSE ); + +} +void LLSideTray::expandSideBar () +{ + mCollapsed = false; + mCollapseButton->setLabel(EXPANDED_NAME); + LLSD key;//empty + mActiveTab->onOpen(key); + mActiveTab->setVisible(TRUE); + + reflectCollapseChange(); + +} + +void LLSideTray::highlightFocused() +{ + if(!mActiveTab) + return; + /* uncomment in case something change + BOOL dependent_has_focus = gFocusMgr.childHasKeyboardFocus(this); + setBackgroundOpaque( dependent_has_focus ); + mActiveTab->setBackgroundOpaque( dependent_has_focus ); + */ + mActiveTab->setBackgroundOpaque( true ); + + +} +//virtual +BOOL LLSideTray::handleMouseDown (S32 x, S32 y, MASK mask) +{ + BOOL ret = LLPanel::handleMouseDown(x,y,mask); + if(ret) + setFocus(true); + return ret; +} +void LLSideTray::reshape (S32 width, S32 height, BOOL called_from_parent) +{ + + LLPanel::reshape(width, height, called_from_parent); + if(!mActiveTab) + return; + + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + + setPanelRect(); + + LLRect ctrl_rect; + ctrl_rect.setLeftTopAndSize(0 + ,getRect().getHeight()-sidetray_params.default_button_width + ,sidetray_params.default_button_width + ,sidetray_params.default_button_height); + + mCollapseButton->setRect(ctrl_rect); + + //arrange tab buttons + child_vector_const_iter_t child_it; + int offset = (sidetray_params.default_button_height+sidetray_params.default_button_margin)*2; + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + + ctrl_rect.setLeftTopAndSize(0,getRect().getHeight()-offset + ,sidetray_params.default_button_width + ,sidetray_params.default_button_height); + + if(mTabButtons.find(sidebar_tab->getName()) == mTabButtons.end()) + continue; + + LLButton* btn = mTabButtons[sidebar_tab->getName()]; + + btn->setRect(ctrl_rect); + offset+=sidetray_params.default_button_height; + offset+=sidetray_params.default_button_margin; + + btn->setVisible(ctrl_rect.mBottom > 0); + } + + //arrange tabs + + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLSideTrayTab* sidebar_tab = dynamic_cast(*child_it); + if(sidebar_tab == NULL) + continue; + sidebar_tab->reshape(mMaxBarWidth,getRect().getHeight()); + ctrl_rect.setLeftTopAndSize(sidetray_params.default_button_width,getRect().getHeight(),mMaxBarWidth,getRect().getHeight()); + sidebar_tab->setRect(ctrl_rect); + + } +} + +/** + * Activate tab with "panel_name" panel + * if no such tab - return false, otherwise true. + * TODO* In some cases a pointer to a panel of + * a specific class may be needed so this method + * would need to use templates. + */ +LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& params) +{ + //arrange tabs + child_vector_const_iter_t child_it; + for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it) + { + LLView* view = (*child_it)->findChildView(panel_name,true); + if(view) + { + onTabButtonClick((*child_it)->getName()); + + LLSideTrayPanelContainer* container = dynamic_cast(view->getParent()); + if(container) + { + LLSD new_params = params; + new_params[LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME] = panel_name; + container->onOpen(new_params); + + return container->getCurrentPanel(); + } + + LLPanel* panel = dynamic_cast(view); + if(panel) + { + panel->onOpen(params); + } + return panel; + } + } + return NULL; +} + +// *TODO: Eliminate magic constants. +static const S32 fake_offset = 132; +static const S32 fake_top_offset = 18; + +void LLSideTray::resetPanelRect () +{ + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + + S32 panel_width = sidetray_params.default_button_width; + panel_width += mCollapsed ? sidetray_params.default_button_margin : mMaxBarWidth; + + S32 panel_height = parent_rect.getHeight()-fake_top_offset; + + reshape(panel_width,panel_height); +} + +void LLSideTray::setPanelRect () +{ + LLNavigationBar* nav_bar = LLNavigationBar::getInstance(); + LLRect nav_rect = nav_bar->getRect(); + + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + + const LLRect& parent_rect = gViewerWindow->getRootView()->getRect(); + + S32 panel_width = sidetray_params.default_button_width; + panel_width += mCollapsed ? sidetray_params.default_button_margin : mMaxBarWidth; + + S32 panel_height = parent_rect.getHeight()-fake_top_offset - nav_rect.getHeight(); + S32 panel_top = parent_rect.mTop-fake_top_offset - nav_rect.getHeight(); + + LLRect panel_rect; + panel_rect.setLeftTopAndSize( parent_rect.mRight-panel_width, panel_top, panel_width, panel_height); + setRect(panel_rect); +} + +S32 LLSideTray::getTrayWidth() +{ + static LLSideTray::Params sidetray_params(LLUICtrlFactory::getDefaultParams()); + return getRect().getWidth() - (sidetray_params.default_button_width + sidetray_params.default_button_margin); +} diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h new file mode 100644 index 0000000000..13acbbb659 --- /dev/null +++ b/indra/newview/llsidetray.h @@ -0,0 +1,252 @@ +/** + * @file LLSideTray.h + * @brief SideBar header file + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSIDETRAY_H_ +#define LL_LLSIDETRAY_H_ + +#include "llpanel.h" +#include "string" + +class LLSideTray; +class LLAccordionCtrl; + +class LLSideTrayTab: public LLPanel +{ + friend class LLUICtrlFactory; + friend class LLSideTray; +public: + + struct Params + : public LLInitParam::Block + { + // image name + Optional image_path; + Optional tab_title; + Optional description; + Params() + : image_path("image"), + tab_title("tab_title","no title"), + description("description","no description") + {}; + }; +protected: + LLSideTrayTab(const Params& params); + + +public: + virtual ~LLSideTrayTab(); + + /*virtual*/ BOOL postBuild (); + /*virtual*/ bool addChild (LLView* view, S32 tab_group); + + + void arrange (S32 width, S32 height); + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + + static LLSideTrayTab* createInstance (); + + const std::string& getDescription () const { return mDescription;} + const std::string& getTabTitle() const { return mTabTitle;} + + void draw(); + + void onOpen (const LLSD& key); + +private: + std::string mTabTitle; + std::string mImagePath; + std::string mDescription; + + LLView* mMainPanel; +}; + +// added inheritance from LLDestroyClass to enable Side Tray perform necessary actions +// while disconnecting viewer in LLAppViewer::disconnectViewer(). +// LLDestroyClassList::instance().fireCallbacks() calls destroyClass method. See EXT-245. +class LLSideTray : public LLPanel, private LLDestroyClass +{ + friend class LLUICtrlFactory; + friend class LLDestroyClass; +public: + + LOG_CLASS(LLSideTray); + + struct Params + : public LLInitParam::Block + { + // initial state + Optional collapsed; + Optional tab_btn_image_normal; + Optional tab_btn_image_selected; + + Optional default_button_width; + Optional default_button_height; + Optional default_button_margin; + + Params() + : collapsed("collapsed",false), + tab_btn_image_normal("tab_btn_image","sidebar_tab_left.tga"), + tab_btn_image_selected("tab_btn_image_selected","button_enabled_selected_32x128.tga"), + default_button_width("tab_btn_width",32), + default_button_height("tab_btn_height",32), + default_button_margin("tab_btn_margin",0) + {}; + }; + + static LLSideTray* getInstance (); + static bool instanceCreated (); +protected: + LLSideTray(Params& params); + typedef std::vector child_vector_t; + typedef child_vector_t::iterator child_vector_iter_t; + typedef child_vector_t::const_iterator child_vector_const_iter_t; + typedef child_vector_t::reverse_iterator child_vector_reverse_iter_t; + typedef child_vector_t::const_reverse_iterator child_vector_const_reverse_iter_t; + +public: + + // interface functions + + /** + * Select tab with specific name and set it active + */ + bool selectTabByName (const std::string& name); + + /** + * Select tab with specific index and set it active + */ + bool selectTabByIndex(size_t index); + + /** + * add new panel to tab with tab_name name + * @param tab_name - name of sidebar tab to add new panel + * @param panel - pointer to panel + */ + bool addPanel ( const std::string& tab_name + ,LLPanel* panel ); + /** + * Add new tab to side bar + * @param tab_name - name of the new tab + * @param image - image for new sidebar button + * @param title - title for new tab + */ + bool addTab ( const std::string& tab_name + ,const std::string& image + ,const std::string& title); + + /** + * Activate tab with "panel_name" panel + * if no such tab - return NULL, otherwise a pointer to the panel + * Pass params as array, or they may be overwritten(example - params["name"]="nearby") + */ + LLPanel* showPanel (const std::string& panel_name, const LLSD& params); + + /* + * collapse SideBar, hiding visible tab and moving tab buttons + * to the right corner of the screen + */ + void collapseSideBar (); + + /* + * expand SideBar + */ + void expandSideBar (); + + + /** + *hightlight if focused. manly copypaste from highlightFocusedFloater + */ + void highlightFocused(); + + void setVisible(BOOL visible) + { + LLPanel::setVisible(visible); + } + +public: + virtual ~LLSideTray(){}; + + virtual BOOL postBuild(); + + void onTabButtonClick(std::string name); + void onToggleCollapse(); + + bool addChild (LLView* view, S32 tab_group); + + BOOL handleMouseDown (S32 x, S32 y, MASK mask); + + void reshape (S32 width, S32 height, BOOL called_from_parent = TRUE); + S32 getTrayWidth(); + + void resetPanelRect (); + + +protected: + LLSideTrayTab* getTab (const std::string& name); + + void createButtons (); + LLButton* createButton (const std::string& name,const std::string& image,LLUICtrl::commit_callback_t callback); + void arrange (); + void reflectCollapseChange(); + + void toggleTabButton (LLSideTrayTab* tab); + + void setPanelRect (); + + + +private: + // Implementation of LLDestroyClass + static void destroyClass() + { + // Disable SideTray to avoid crashes. EXT-245 + if (LLSideTray::instanceCreated()) + LLSideTray::getInstance()->setEnabled(FALSE); + } + + +private: + + std::map mTabButtons; + child_vector_t mTabs; + LLSideTrayTab* mActiveTab; + + LLButton* mCollapseButton; + bool mCollapsed; + + S32 mMaxBarWidth; + + static LLSideTray* sInstance; +}; + +#endif + diff --git a/indra/newview/llsidetraypanelcontainer.cpp b/indra/newview/llsidetraypanelcontainer.cpp new file mode 100644 index 0000000000..3024492ab9 --- /dev/null +++ b/indra/newview/llsidetraypanelcontainer.cpp @@ -0,0 +1,93 @@ +/** +* @file llsidetraypanelcontainer.cpp +* @brief LLSideTrayPanelContainer implementation +* +* $LicenseInfo:firstyear=2001&license=viewergpl$ +* +* Copyright (c) 2001-2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#include "llviewerprecompiledheaders.h" +#include "llsidetraypanelcontainer.h" + +static LLDefaultChildRegistry::Register r2("panel_container"); + +std::string LLSideTrayPanelContainer::PARAM_SUB_PANEL_NAME = "sub_panel_name"; + +LLSideTrayPanelContainer::Params::Params() +{ + // Always hide tabs. + hide_tabs(true); +} + +LLSideTrayPanelContainer::LLSideTrayPanelContainer(const Params& p) + : LLTabContainer(p) +{ +} + +void LLSideTrayPanelContainer::onOpen(const LLSD& key) +{ + // Select specified panel and save navigation history. + if(key.has(PARAM_SUB_PANEL_NAME)) + { + // Save panel navigation history + std::string panel_name = key[PARAM_SUB_PANEL_NAME]; + S32 old_index = getCurrentPanelIndex(); + + selectTabByName(panel_name); + + S32 new_index = getCurrentPanelIndex(); + + // Don't update navigation history if we are opening same panel again. + if(old_index != new_index) + { + mPanelHistory[panel_name] = old_index; + } + } + // Will reopen current panel if no panel name was passed. + getCurrentPanel()->onOpen(key); +} + +void LLSideTrayPanelContainer::openPreviousPanel() +{ + std::string current_panel_name = getCurrentPanel()->getName(); + panel_navigation_history_t::const_iterator it = mPanelHistory.find(current_panel_name); + if(mPanelHistory.end() != it) + { + selectTab(it->second); + } +} + +BOOL LLSideTrayPanelContainer::handleKeyHere(KEY key, MASK mask) +{ + // No key press handling code for Panel Container - this disables + // Tab Container's Alt + Left/Right Button tab switching. + + // Let default handler process key presses, don't simply return TRUE or FALSE + // as this may brake some functionality as it did with Copy/Paste for + // text_editor (ticket EXT-642). + return LLPanel::handleKeyHere(key, mask); +} diff --git a/indra/newview/llsidetraypanelcontainer.h b/indra/newview/llsidetraypanelcontainer.h new file mode 100644 index 0000000000..3f3cb552f8 --- /dev/null +++ b/indra/newview/llsidetraypanelcontainer.h @@ -0,0 +1,95 @@ +/** +* @file llsidetraypanelcontainer.h +* @brief LLSideTrayPanelContainer class declaration +* +* $LicenseInfo:firstyear=2009&license=viewergpl$ +* +* Copyright (c) 2009, Linden Research, Inc. +* +* Second Life Viewer Source Code +* The source code in this file ("Source Code") is provided by Linden Lab +* to you under the terms of the GNU General Public License, version 2.0 +* ("GPL"), unless you have obtained a separate licensing agreement +* ("Other License"), formally executed by you and Linden Lab. Terms of +* the GPL can be found in doc/GPL-license.txt in this distribution, or +* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 +* +* There are special exceptions to the terms and conditions of the GPL as +* it is applied to this Source Code. View the full text of the exception +* in the file doc/FLOSS-exception.txt in this software distribution, or +* online at +* http://secondlifegrid.net/programs/open_source/licensing/flossexception +* +* By copying, modifying or distributing this software, you acknowledge +* that you have read and understood your obligations described above, +* and agree to abide by those obligations. +* +* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO +* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, +* COMPLETENESS OR PERFORMANCE. +* $/LicenseInfo$ +*/ + +#ifndef LL_LLSIDETRAY_PANEL_CONTAINER_H +#define LL_LLSIDETRAY_PANEL_CONTAINER_H + +#include "lltabcontainer.h" + +/** +* LLSideTrayPanelContainer class acts like LLTabContainer with invisible tabs. +* It is designed to make panel switching easier, avoid setVisible(TRUE) setVisible(FALSE) +* calls and related workarounds. +* use onOpen to open sub panel, pass the name of panel to open +* in key[PARAM_SUB_PANEL_NAME]. +* LLSideTrayPanelContainer also implements panel navigation history - it allows to +* open previous or next panel if navigation history is available(after user +* has opened two or more panels). *NOTE - only back navigation is implemented so far. +*/ +class LLSideTrayPanelContainer : public LLTabContainer +{ +public: + + struct Params : public LLInitParam::Block + { + Params(); + }; + + /** + * Opens sub panel + * @param key - params to be passed to panel, use key[PARAM_SUB_PANEL_NAME] + * to specify panel name to be opened. + */ + /*virtual*/ void onOpen(const LLSD& key); + + /** + * Opens previous panel from panel navigation history. + */ + void openPreviousPanel(); + + /** + * Overrides LLTabContainer::handleKeyHere to disable panel switch on + * Alt + Left/Right button press. + */ + BOOL handleKeyHere(KEY key, MASK mask); + + /** + * Name of parameter that stores panel name to open. + */ + static std::string PARAM_SUB_PANEL_NAME; + +protected: + LLSideTrayPanelContainer(const Params& p); + friend class LLUICtrlFactory; + + /** + * std::string - name of panel + * S32 - index of previous panel + * *NOTE - no forward navigation implemented yet + */ + typedef std::map panel_navigation_history_t; + + // Navigation history + panel_navigation_history_t mPanelHistory; +}; + +#endif //LL_LLSIDETRAY_PANEL_CONTAINER_H diff --git a/indra/newview/llsky.cpp b/indra/newview/llsky.cpp index ac7e865de0..a49b07c5d9 100644 --- a/indra/newview/llsky.cpp +++ b/indra/newview/llsky.cpp @@ -52,7 +52,6 @@ #include "llviewerobject.h" #include "llviewercamera.h" #include "pipeline.h" -#include "llagent.h" #include "lldrawpool.h" #include "llvosky.h" diff --git a/indra/newview/llslurl.cpp b/indra/newview/llslurl.cpp new file mode 100644 index 0000000000..836fe9729d --- /dev/null +++ b/indra/newview/llslurl.cpp @@ -0,0 +1,145 @@ +/** + * @file llslurl.cpp + * @brief SLURL manipulation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llslurl.h" + +#include "llweb.h" + +const std::string LLSLURL::PREFIX_SL_HELP = "secondlife://app."; +const std::string LLSLURL::PREFIX_SL = "sl://"; +const std::string LLSLURL::PREFIX_SECONDLIFE = "secondlife://"; +const std::string LLSLURL::PREFIX_SLURL = "http://slurl.com/secondlife/"; + +const std::string LLSLURL::APP_TOKEN = "app/"; + +// static +std::string LLSLURL::stripProtocol(const std::string& url) +{ + std::string stripped = url; + if (matchPrefix(stripped, PREFIX_SL_HELP)) + { + stripped.erase(0, PREFIX_SL_HELP.length()); + } + else if (matchPrefix(stripped, PREFIX_SL)) + { + stripped.erase(0, PREFIX_SL.length()); + } + else if (matchPrefix(stripped, PREFIX_SECONDLIFE)) + { + stripped.erase(0, PREFIX_SECONDLIFE.length()); + } + else if (matchPrefix(stripped, PREFIX_SLURL)) + { + stripped.erase(0, PREFIX_SLURL.length()); + } + + return stripped; +} + +// static +bool LLSLURL::isSLURL(const std::string& url) +{ + if (matchPrefix(url, PREFIX_SL_HELP)) return true; + if (matchPrefix(url, PREFIX_SL)) return true; + if (matchPrefix(url, PREFIX_SECONDLIFE)) return true; + if (matchPrefix(url, PREFIX_SLURL)) return true; + + return false; +} + +// static +bool LLSLURL::isSLURLCommand(const std::string& url) +{ + if (matchPrefix(url, PREFIX_SL + APP_TOKEN) || + matchPrefix(url, PREFIX_SECONDLIFE + "/" + APP_TOKEN) || + matchPrefix(url, PREFIX_SLURL + APP_TOKEN) ) + { + return true; + } + + return false; +} + +// static +bool LLSLURL::isSLURLHelp(const std::string& url) +{ + return matchPrefix(url, PREFIX_SL_HELP); +} + +// static +std::string LLSLURL::buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z) +{ + std::string slurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z); + slurl = LLWeb::escapeURL( slurl ); + return slurl; +} + +// static +std::string LLSLURL::buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z) +{ + std::string unescapedslurl = PREFIX_SLURL + regionname + llformat("/%d/%d/%d",x,y,z); + return unescapedslurl; +} + +// static +std::string LLSLURL::buildSLURLfromPosGlobal(const std::string& regionname, + const LLVector3d& global_pos, + bool escaped /*= true*/) +{ + S32 x, y, z; + globalPosToXYZ(global_pos, x, y, z); + if(escaped) + { + return buildSLURL(regionname, x, y, z); + } + else + { + return buildUnescapedSLURL(regionname, x, y, z); + } +} + +// static +bool LLSLURL::matchPrefix(const std::string& url, const std::string& prefix) +{ + std::string test_prefix = url.substr(0, prefix.length()); + LLStringUtil::toLower(test_prefix); + return test_prefix == prefix; +} + +void LLSLURL::globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z) +{ + x = llround((F32)fmod(pos.mdV[VX], (F64)REGION_WIDTH_METERS)); + y = llround((F32)fmod(pos.mdV[VY], (F64)REGION_WIDTH_METERS)); + z = llround((F32)pos.mdV[VZ]); +} diff --git a/indra/newview/llslurl.h b/indra/newview/llslurl.h new file mode 100644 index 0000000000..8af2bdfb83 --- /dev/null +++ b/indra/newview/llslurl.h @@ -0,0 +1,103 @@ +/** + * @file llslurl.h + * @brief SLURL manipulation + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_SLURL_H +#define LL_SLURL_H + +#include + +// IAN BUG: where should this live? +// IAN BUG: are static utility functions right? See LLUUID. +// question of whether to have a LLSLURL object or a +// some of this was moved from LLURLDispatcher + +/** + * SLURL manipulation + */ +class LLSLURL +{ +public: + static const std::string PREFIX_SL_HELP; + static const std::string PREFIX_SL; + static const std::string PREFIX_SECONDLIFE; + static const std::string PREFIX_SLURL; + + static const std::string APP_TOKEN; + + /** + * Is this any sort of secondlife:// or sl:// URL? + */ + static bool isSLURL(const std::string& url); + + /** + * Is this a special secondlife://app/ URL? + */ + static bool isSLURLCommand(const std::string& url); + + /** + * Not sure what it is. + */ + static bool isSLURLHelp(const std::string& url); + + /** + * builds: http://slurl.com/secondlife/Region%20Name/x/y/z/ escaping result url. + */ + static std::string buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z); + + /** + * builds: http://slurl.com/secondlife/Region Name/x/y/z/ without escaping result url. + */ + static std::string buildUnescapedSLURL(const std::string& regionname, S32 x, S32 y, S32 z); + + /** + * builds SLURL from global position. Returns escaped or unescaped url. + * Returns escaped url by default. + */ + static std::string buildSLURLfromPosGlobal(const std::string& regionname, + const LLVector3d& global_pos, + bool escaped = true); + /** + * Strip protocol part from the URL. + */ + static std::string stripProtocol(const std::string& url); + + /** + * Convert global position to X, Y Z + */ + static void globalPosToXYZ(const LLVector3d& pos, S32& x, S32& y, S32& z); + +private: + static bool matchPrefix(const std::string& url, const std::string& prefix); + +}; + +#endif diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index f8b824732f..dea9af0657 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -41,7 +41,6 @@ #include "llviewercamera.h" #include "llface.h" #include "llviewercontrol.h" -#include "llagent.h" #include "llviewerregion.h" #include "llcamera.h" #include "pipeline.h" @@ -49,6 +48,9 @@ #include "lloctree.h" #include "llvoavatar.h" +static LLFastTimer::DeclareTimer FTM_FRUSTUM_CULL("Frustum Culling"); +static LLFastTimer::DeclareTimer FTM_CULL_REBOUND("Cull Rebound"); + const F32 SG_OCCLUSION_FUDGE = 0.25f; #define SG_DISCARD_TOLERANCE 0.01f @@ -570,6 +572,8 @@ void LLSpatialGroup::rebuildMesh() } } +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) { if (!gPipeline.hasRenderType(mDrawableType)) @@ -577,7 +581,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) return; } - if (group->changeLOD()) + if (!LLPipeline::sSkipUpdate && group->changeLOD()) { group->mLastUpdateDistance = group->mDistance; group->mLastUpdateViewAngle = group->mViewAngle; @@ -588,7 +592,7 @@ void LLSpatialPartition::rebuildGeom(LLSpatialGroup* group) return; } - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + LLFastTimer ftm(FTM_REBUILD_VBO); group->clearDrawMap(); @@ -826,7 +830,7 @@ class LLSpatialSetStateDiff : public LLSpatialSetState public: LLSpatialSetStateDiff(U32 state) : LLSpatialSetState(state) { } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -885,7 +889,7 @@ class LLSpatialClearStateDiff : public LLSpatialClearState public: LLSpatialClearStateDiff(U32 state) : LLSpatialClearState(state) { } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -1256,6 +1260,7 @@ BOOL LLSpatialGroup::rebound() return TRUE; } +static LLFastTimer::DeclareTimer FTM_OCCLUSION_READBACK("Readback Occlusion"); void LLSpatialGroup::checkOcclusion() { if (LLPipeline::sUseOcclusion > 1) @@ -1267,7 +1272,7 @@ void LLSpatialGroup::checkOcclusion() } else if (isState(QUERY_PENDING)) { //otherwise, if a query is pending, read it back - LLFastTimer t(LLFastTimer::FTM_OCCLUSION_READBACK); + LLFastTimer t(FTM_OCCLUSION_READBACK); GLuint res = 1; if (!isState(DISCARD_QUERY) && mOcclusionQuery) { @@ -1312,7 +1317,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera) else { { - LLFastTimer t(LLFastTimer::FTM_RENDER_OCCLUSION); + LLFastTimer t(FTM_RENDER_OCCLUSION); if (!mOcclusionQuery) { @@ -1498,7 +1503,7 @@ public: return false; } - virtual void traverse(const LLSpatialGroup::TreeNode* n) + virtual void traverse(const LLSpatialGroup::OctreeNode* n) { LLSpatialGroup* group = (LLSpatialGroup*) n->getListener(0); @@ -1873,7 +1878,7 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result { BOOL temp = sFreezeState; sFreezeState = FALSE; - LLFastTimer ftm(LLFastTimer::FTM_CULL_REBOUND); + LLFastTimer ftm(FTM_CULL_REBOUND); LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0); group->rebound(); sFreezeState = temp; @@ -1891,19 +1896,19 @@ S32 LLSpatialPartition::cull(LLCamera &camera, std::vector* result } else if (LLPipeline::sShadowRender) { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCullShadow culler(&camera); culler.traverse(mOctree); } else if (mInfiniteFarClip || !LLPipeline::sUseFarClip) { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCullNoFarClip culler(&camera); culler.traverse(mOctree); } else { - LLFastTimer ftm(LLFastTimer::FTM_FRUSTUM_CULL); + LLFastTimer ftm(FTM_FRUSTUM_CULL); LLOctreeCull culler(&camera); culler.traverse(mOctree); } @@ -2356,7 +2361,7 @@ void renderTexturePriority(LLDrawable* drawable) LLGLDisable blend(GL_BLEND); - //LLViewerImage* imagep = facep->getTexture(); + //LLViewerTexture* imagep = facep->getTexture(); //if (imagep) { @@ -2386,7 +2391,7 @@ void renderTexturePriority(LLDrawable* drawable) /*S32 boost = imagep->getBoostLevel(); if (boost) { - F32 t = (F32) boost / (F32) (LLViewerImage::BOOST_MAX_LEVEL-1); + F32 t = (F32) boost / (F32) (LLViewerTexture::BOOST_MAX_LEVEL-1); LLVector4 col = lerp(boost_cold, boost_hot, t); LLGLEnable blend_on(GL_BLEND); gGL.blendFunc(GL_SRC_ALPHA, GL_ONE); @@ -2896,7 +2901,7 @@ LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, con } LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, - LLViewerImage* texture, LLVertexBuffer* buffer, + LLViewerTexture* texture, LLVertexBuffer* buffer, BOOL fullbright, U8 bump, BOOL particle, F32 part_size) : mVertexBuffer(buffer), diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h index df96152dfe..13ab35402c 100644 --- a/indra/newview/llspatialpartition.h +++ b/indra/newview/llspatialpartition.h @@ -35,9 +35,10 @@ #define SG_MIN_DIST_RATIO 0.00001f -#include "llmemory.h" #include "lldrawable.h" #include "lloctree.h" +#include "llpointer.h" +#include "llrefcount.h" #include "llvertexbuffer.h" #include "llgltypes.h" #include "llcubemap.h" @@ -66,12 +67,12 @@ protected: public: LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, - LLViewerImage* image, LLVertexBuffer* buffer, + LLViewerTexture* image, LLVertexBuffer* buffer, BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0); LLPointer mVertexBuffer; - LLPointer mTexture; + LLPointer mTexture; LLColor4U mGlowColor; S32 mDebugColor; const LLMatrix4* mTextureMatrix; @@ -163,7 +164,7 @@ public: typedef std::vector > drawmap_elem_t; typedef std::map draw_map_t; typedef std::vector > buffer_list_t; - typedef std::map, buffer_list_t> buffer_texture_map_t; + typedef std::map, buffer_list_t> buffer_texture_map_t; typedef std::map buffer_map_t; typedef LLOctreeListener BaseType; diff --git a/indra/newview/llsplitbutton.cpp b/indra/newview/llsplitbutton.cpp new file mode 100644 index 0000000000..ffd9bc7624 --- /dev/null +++ b/indra/newview/llsplitbutton.cpp @@ -0,0 +1,275 @@ +/** + * @file llsplitbutton.cpp + * @brief LLSplitButton base class + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// A control that consolidates several buttons as options + +#include "llviewerprecompiledheaders.h" + +#include "llsplitbutton.h" + +#include "llinitparam.h" +#include "llpanel.h" +#include "llfocusmgr.h" +#include "llviewerwindow.h" +#include "llrootview.h" + + +S32 BUTTON_PAD = 2; //pad between buttons on an items panel + + +static LLDefaultChildRegistry::Register split_button("split_button"); + +void LLSplitButton::ArrowPositionValues::declareValues() +{ + declare("left", LEFT); + declare("right", RIGHT); +} + +LLSplitButton::ItemParams::ItemParams() +{ +} + +LLSplitButton::Params::Params() +: arrow_position("arrow_position", LEFT), + items("item"), + arrow_button("arrow_button"), + items_panel("items_panel") +{ +} + + +void LLSplitButton::onFocusLost() +{ + hideButtons(); + LLUICtrl::onFocusLost(); +} + +void LLSplitButton::setFocus(BOOL b) +{ + LLUICtrl::setFocus(b); + + if (b) + { + if (mItemsPanel && mItemsPanel->getVisible()) + { + mItemsPanel->setFocus(TRUE); + } + } +} + +void LLSplitButton::setEnabled(BOOL enabled) +{ + LLView::setEnabled(enabled); + mArrowBtn->setEnabled(enabled); +} + + +void LLSplitButton::onArrowBtnDown() +{ + if (!mItemsPanel->getVisible()) + { + showButtons(); + + setFocus(TRUE); + + if (mArrowBtn->hasMouseCapture() || mShownItem->hasMouseCapture()) + { + gFocusMgr.setMouseCapture(this); + } + } + else + { + hideButtons(); + } +} + +void LLSplitButton::onHeldDownShownButton() +{ + if (!mItemsPanel->getVisible()) onArrowBtnDown(); +} + +void LLSplitButton::onItemSelected(LLUICtrl* ctrl) +{ + if (!ctrl) return; + + hideButtons(); + + // call the callback if it exists + if(!mSelectionCallback.empty()) + { + mSelectionCallback(this, ctrl->getName()); + } + + gFocusMgr.setKeyboardFocus(NULL); +} + +BOOL LLSplitButton::handleMouseUp(S32 x, S32 y, MASK mask) +{ + gFocusMgr.setMouseCapture(NULL); + + if (mShownItem->parentPointInView(x, y)) + { + onItemSelected(mShownItem); + return TRUE; + } + + for (std::list::const_iterator it = mHidenItems.begin(); it != mHidenItems.end(); ++it) + { + LLButton* item = *it; + + S32 panel_x = 0; + S32 panel_y = 0; + localPointToOtherView(x, y, &panel_x, &panel_y, mItemsPanel); + + if (item->parentPointInView(panel_x, panel_y)) + { + onItemSelected(item); + return TRUE; + } + } + return TRUE; +} + +void LLSplitButton::showButtons() +{ + mItemsPanel->setOrigin(0, getRect().getHeight()); + + // register ourselves as a "top" control + // effectively putting us into a special draw layer + gFocusMgr.setTopCtrl(this); + + mItemsPanel->setFocus(TRUE); + + //push arrow button down and show the item buttons + mArrowBtn->setToggleState(TRUE); + mItemsPanel->setVisible(TRUE); + + setUseBoundingRect(TRUE); +} + +void LLSplitButton::hideButtons() +{ + mItemsPanel->setVisible(FALSE); + mArrowBtn->setToggleState(FALSE); + + setUseBoundingRect(FALSE); + if(gFocusMgr.getTopCtrl() == this) + { + gFocusMgr.setTopCtrl(NULL); + } +} + + +// protected/private + +LLSplitButton::LLSplitButton(const LLSplitButton::Params& p) +: LLUICtrl(p), + mArrowBtn(NULL), + mShownItem(NULL), + mItemsPanel(NULL), + mArrowPosition(p.arrow_position) +{ + LLRect rc(p.rect); + + LLButton::Params arrow_params = p.arrow_button; + S32 arrow_width = p.arrow_button.rect.width; + + //Default arrow rect values for LEFT arrow position + S32 arrow_left = 0; + S32 arrow_right = arrow_width; + S32 btn_left = arrow_width; + S32 btn_right = rc.getWidth(); + + if (mArrowPosition == RIGHT) + { + arrow_left = rc.getWidth()- arrow_width; + arrow_right = rc.getWidth(); + btn_left = 0; + btn_right = arrow_left; + } + + arrow_params.rect(LLRect(arrow_left, rc.getHeight(), arrow_right, 0)); + arrow_params.label(""); + arrow_params.mouse_down_callback.function(boost::bind(&LLSplitButton::onArrowBtnDown, this)); + mArrowBtn = LLUICtrlFactory::create(arrow_params); + addChild(mArrowBtn); + + //a panel for hidden item buttons + LLPanel::Params panel_params = p.items_panel; + mItemsPanel= prepareItemsPanel(panel_params, p.items.numValidElements()); + addChild(mItemsPanel); + + + LLInitParam::ParamIterator::const_iterator it = p.items().begin(); + + //processing shown item button + mShownItem = prepareItemButton(*it); + mShownItem->setHeldDownCallback(boost::bind(&LLSplitButton::onHeldDownShownButton, this)); + mShownItem->setMouseUpCallback(boost::bind(&LLSplitButton::onItemSelected, this, _1)); + mShownItem->setRect(LLRect(btn_left, rc.getHeight(), btn_right, 0)); + addChild(mShownItem); + + //processing hidden item buttons + S32 item_top = mItemsPanel->getRect().getHeight(); + for (++it; it != p.items().end(); ++it) + { + LLButton* hidden_button = prepareItemButton(*it); + hidden_button->setRect(LLRect(btn_left, item_top, btn_right, item_top - rc.getHeight())); + hidden_button->setMouseDownCallback(boost::bind(&LLSplitButton::onItemSelected, this, _1)); + mHidenItems.push_back(hidden_button); + mItemsPanel->addChild(hidden_button); + + //calculate next button's top + item_top -= (rc.getHeight() + BUTTON_PAD); + } + + setTopLostCallback(boost::bind(&LLSplitButton::hideButtons, this)); +} + + +LLButton* LLSplitButton::prepareItemButton(LLButton::Params params) +{ + params.label(""); + params.is_toggle(false); + return LLUICtrlFactory::create(params); +} + +LLPanel* LLSplitButton::prepareItemsPanel(LLPanel::Params params, S32 items_count) +{ + S32 num_hiden_btns = items_count - 1; + S32 panel_height = num_hiden_btns * (getRect().getHeight() + BUTTON_PAD); + params.visible(false); + params.rect.width(getRect().getWidth()); + params.rect.height(panel_height); + return LLUICtrlFactory::create(params); +} + diff --git a/indra/newview/llsplitbutton.h b/indra/newview/llsplitbutton.h new file mode 100644 index 0000000000..0fb5f6594e --- /dev/null +++ b/indra/newview/llsplitbutton.h @@ -0,0 +1,112 @@ +/** + * @file llsplitbutton.h + * @brief LLSplitButton base class + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +// A control that displays the name of the chosen item, which when clicked +// shows a scrolling box of choices. + + +#include "llbutton.h" +#include "llpanel.h" +#include "lluictrl.h" + + +#ifndef LL_LLSPLITBUTTON_H +#define LL_LLSPLITBUTTON_H + +class LLSplitButton + : public LLUICtrl +{ +public: + typedef enum e_arrow_position + { + LEFT, + RIGHT + } EArrowPosition; + + struct ArrowPositionValues : public LLInitParam::TypeValuesHelper + { + static void declareValues(); + }; + + struct ItemParams : public LLInitParam::Block + { + ItemParams(); + }; + + struct Params : public LLInitParam::Block + { + Optional arrow_position; + Optional arrow_button; + Optional items_panel; + Multiple items; + + Params(); + }; + + + virtual ~LLSplitButton() {}; + + //Overridden + virtual void onFocusLost(); + virtual void setFocus(BOOL b); + virtual void setEnabled(BOOL enabled); + + //Callbacks + void onArrowBtnDown(); + void onHeldDownShownButton(); + void onItemSelected(LLUICtrl* ctrl); + void setSelectionCallback(commit_callback_t cb) { mSelectionCallback = cb; } + + virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask); + + virtual void showButtons(); + virtual void hideButtons(); + + +protected: + friend class LLUICtrlFactory; + LLSplitButton(const LLSplitButton::Params& p); + + LLButton* prepareItemButton(LLButton::Params params); + LLPanel* prepareItemsPanel(LLPanel::Params params, S32 items_count); + + LLPanel* mItemsPanel; + std::list mHidenItems; + LLButton* mArrowBtn; + LLButton* mShownItem; + EArrowPosition mArrowPosition; + + commit_callback_t mSelectionCallback; +}; + + +#endif diff --git a/indra/newview/llsprite.cpp b/indra/newview/llsprite.cpp index 893ed22297..dce4e9d144 100644 --- a/indra/newview/llsprite.cpp +++ b/indra/newview/llsprite.cpp @@ -48,7 +48,7 @@ #include "lldrawable.h" #include "llface.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" LLVector3 LLSprite::sCameraUp(0.0f,0.0f,1.0f); LLVector3 LLSprite::sCameraRight(1.0f,0.0f,0.0f); diff --git a/indra/newview/llsprite.h b/indra/newview/llsprite.h index 28f4ec5d03..eefe2a2386 100644 --- a/indra/newview/llsprite.h +++ b/indra/newview/llsprite.h @@ -40,7 +40,7 @@ #include "v4color.h" #include "lluuid.h" #include "llgl.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLViewerCamera; @@ -82,7 +82,7 @@ public: public: LLUUID mImageID; - LLPointer mImagep; + LLPointer mImagep; private: F32 mWidth; F32 mHeight; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 2c0d11baab..6c0481feaa 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -40,26 +40,27 @@ # include // mkdir() #endif -#include "audioengine.h" +#include "llviewermedia_streamingaudio.h" +#include "llaudioengine.h" #ifdef LL_FMOD -# include "audioengine_fmod.h" +# include "llaudioengine_fmod.h" #endif #ifdef LL_OPENAL -#include "audioengine_openal.h" +#include "llaudioengine_openal.h" #endif #include "llares.h" +#include "lllandmark.h" #include "llcachename.h" -#include "llviewercontrol.h" #include "lldir.h" #include "llerrorcontrol.h" #include "llfiltersd2xmlrpc.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llhttpsender.h" -#include "imageids.h" -#include "lllandmark.h" +#include "lllocationhistory.h" #include "llloginflags.h" #include "llmd5.h" #include "llmemorystream.h" @@ -73,53 +74,52 @@ #include "llstring.h" #include "lluserrelations.h" #include "llversionviewer.h" +#include "llviewercontrol.h" #include "llvfs.h" #include "llxorcipher.h" // saved password, MAC address +#include "llwindow.h" +#include "imageids.h" #include "message.h" #include "v3math.h" #include "llagent.h" +#include "llagentwearables.h" #include "llagentpilot.h" #include "llfloateravatarpicker.h" #include "llcallbacklist.h" #include "llcallingcard.h" -#include "llcolorscheme.h" #include "llconsole.h" #include "llcontainerview.h" -#include "llfloaterstats.h" #include "lldebugview.h" #include "lldrawable.h" #include "lleventnotifier.h" #include "llface.h" #include "llfeaturemanager.h" #include "llfirstuse.h" -#include "llfloateractivespeakers.h" -#include "llfloaterbeacons.h" -#include "llfloatercamera.h" #include "llfloaterchat.h" #include "llfloatergesture.h" #include "llfloaterhud.h" #include "llfloaterland.h" +#include "llfloaterpreference.h" #include "llfloatertopobjects.h" #include "llfloatertos.h" #include "llfloaterworldmap.h" -#include "llframestats.h" -#include "llframestatview.h" #include "llgesturemgr.h" #include "llgroupmgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llhttpclient.h" #include "llimagebmp.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfriendcard.h" #include "llkeyboard.h" #include "llloginhandler.h" // gLoginHandler, SLURL support #include "llpanellogin.h" -#include "llprefsim.h" #include "llmutelist.h" #include "llnotify.h" #include "llpanelavatar.h" +#include "llavatarpropertiesprocessor.h" #include "llpaneldirbrowser.h" #include "llpaneldirland.h" #include "llpanelevent.h" @@ -154,7 +154,7 @@ #include "llviewerdisplay.h" #include "llviewergenericmessage.h" #include "llviewergesture.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewermedia.h" #include "llviewermenu.h" #include "llviewermessage.h" @@ -167,6 +167,7 @@ #include "llviewerthrottle.h" #include "llviewerwindow.h" #include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvoclouds.h" #include "llweb.h" #include "llworld.h" @@ -185,10 +186,8 @@ #include "llwlparammanager.h" #include "llwaterparammanager.h" #include "llagentlanguage.h" - -#if LL_LIBXUL_ENABLED -#include "llmozlib.h" -#endif // LL_LIBXUL_ENABLED +#include "llwearable.h" +#include "llinventorybridge.h" #if LL_WINDOWS #include "llwindebug.h" @@ -215,7 +214,7 @@ extern S32 gStartImageHeight; // local globals // -LLPointer gStartImageGL; +LLPointer gStartTexture; static LLHost gAgentSimHost; static BOOL gSkipOptionalUpdate = FALSE; @@ -245,7 +244,6 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response); void login_packet_failed(void**, S32 result); void use_circuit_callback(void**, S32 result); void register_viewer_callbacks(LLMessageSystem* msg); -void init_stat_view(); void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32); bool callback_choose_gender(const LLSD& notification, const LLSD& response); void init_start_screen(S32 location_id); @@ -253,7 +251,7 @@ void release_start_screen(); void reset_login(); void apply_udp_blacklist(const std::string& csv); -void callback_cache_name(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group, void* data) +void callback_cache_name(const LLUUID& id, const std::string& firstname, const std::string& lastname, BOOL is_group) { LLNameListCtrl::refreshAll(id, firstname, lastname, is_group); LLNameBox::refreshAll(id, firstname, lastname, is_group); @@ -293,8 +291,11 @@ public: virtual void done() { // we've downloaded all the items, so repaint the dialog - LLFloaterGesture::refreshAll(); - + LLFloaterGesture* floater = LLFloaterReg::findTypedInstance("gestures"); + if (floater) + { + floater->refreshAll(); + } gInventory.removeObserver(this); delete this; } @@ -305,12 +306,65 @@ void update_texture_fetch() LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread - gImageList.updateImages(0.10f); + gTextureList.updateImages(0.10f); } static std::vector sAuthUris; static S32 sAuthUriNum = -1; +//Copies landmarks from the "Library" to "My Favorites" +void populate_favorites_bar() +{ + //*TODO consider extending LLInventoryModel::findCategoryUUIDForType(...) to support both root's + LLInventoryModel::cat_array_t* lib_cats = NULL; + LLInventoryModel::item_array_t* lib_items = NULL; + gInventory.getDirectDescendentsOf(gInventory.getLibraryRootFolderID(), lib_cats, lib_items); + if (!lib_cats) return; + + LLUUID lib_landmarks(LLUUID::null); + S32 count = lib_cats->count(); + for(S32 i = 0; i < count; ++i) + { + if(lib_cats->get(i)->getPreferredType() == LLAssetType::AT_LANDMARK) + { + lib_landmarks = lib_cats->get(i)->getUUID(); + break; + } + } + if (lib_landmarks.isNull()) + { + llerror("Library inventory is missing Landmarks", 0); + return; + } + + LLInventoryModel::cat_array_t* lm_cats = NULL; + LLInventoryModel::item_array_t* lm_items = NULL; + gInventory.getDirectDescendentsOf(lib_landmarks, lm_cats, lm_items); + if (!lm_items) return; + + LLUUID favorites_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE); + if (favorites_id.isNull()) + { + llerror("My Inventory is missing My Favorites", 0); + return; + } + + S32 lm_count = lm_items->count(); + for (S32 i = 0; i < lm_count; ++i) + { + LLInventoryItem* item = lm_items->get(i); + if (item->getUUID().isNull()) continue; + + copy_inventory_item(gAgent.getID(), + item->getPermissions().getOwner(), + item->getUUID(), + favorites_id, + std::string(), + LLPointer(NULL)); + } +} + + // Returns false to skip other idle processing. Should only return // true when all initialization done. bool idle_startup() @@ -355,15 +409,25 @@ bool idle_startup() static bool stipend_since_login = false; - static bool samename = false; - // HACK: These are things from the main loop that usually aren't done // until initialization is complete, but need to be done here for things // to work. gIdleCallbacks.callFunctions(); - gViewerWindow->handlePerFrameHover(); + gViewerWindow->updateUI(); LLMortician::updateClass(); + const std::string delims (" "); + std::string system; + int begIdx, endIdx; + std::string osString = LLAppViewer::instance()->getOSInfo().getOSStringSimple(); + + begIdx = osString.find_first_not_of (delims); + endIdx = osString.find_first_of (delims, begIdx); + system = osString.substr (begIdx, endIdx - begIdx); + system += "Locale"; + + LLStringUtil::setLocale (LLTrans::getString(system)); + if (gNoRender) { // HACK, skip optional updates if you're running drones @@ -372,7 +436,7 @@ bool idle_startup() else { // Update images? - gImageList.updateImages(0.01f); + gTextureList.updateImages(0.01f); } if ( STATE_FIRST == LLStartUp::getStartupState() ) @@ -431,8 +495,6 @@ bool idle_startup() // Load autopilot and stats stuff gAgentPilot.load(gSavedSettings.getString("StatsPilotFile")); - gFrameStats.setFilename(gSavedSettings.getString("StatsFile")); - gFrameStats.setSummaryFilename(gSavedSettings.getString("StatsSummaryFile")); //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps")); @@ -458,13 +520,24 @@ bool idle_startup() #if LL_WINDOWS // On the windows dev builds, unpackaged, the message_template.msg - // file will be located in - // indra/build-vc**/newview//app_settings. + // file will be located in: + // build-vc**/newview//app_settings if (!found_template) { message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg"); found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ } + #elif LL_DARWIN + // On Mac dev builds, message_template.msg lives in: + // indra/build-*/newview//Second Life/Contents/Resources/app_settings + if (!found_template) + { + message_template_path = + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, + "../Resources/app_settings", + "message_template.msg"); + found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */ + } #endif if (found_template) @@ -643,6 +716,16 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; } + + if (gAudiop) + { + // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins + if (NULL == gAudiop->getStreamingAudioImpl()) + { + LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL; + gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins()); + } + } } } @@ -728,8 +811,7 @@ bool idle_startup() std::string msg = LLTrans::getString("LoginInitializingBrowser"); set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - LLViewerMedia::initBrowser(); - + // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); return FALSE; } @@ -780,15 +862,11 @@ bool idle_startup() // *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance(). - // Initialize UI - if (!gNoRender) + // Login screen needs menus for preferences, but we can enter + // this startup phase more than once. + if (gLoginMenuBarView == NULL) { - // Initialize all our tools. Must be done after saved settings loaded. - // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. - LLToolMgr::getInstance()->initTools(); - - // Quickly get something onscreen to look at. - gViewerWindow->initWorldUI(); + init_menus(); } gViewerWindow->setNormalControlsVisible( FALSE ); @@ -857,10 +935,10 @@ bool idle_startup() // Set PerAccountSettingsFile to the default value. gSavedSettings.setString("PerAccountSettingsFile", gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, - LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount") - ) - ); + LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount"))); + // Note: can't store warnings files per account because some come up before login + // Overwrite default user settings with user settings LLAppViewer::instance()->loadSettingsFromDirectory("Account"); @@ -872,10 +950,13 @@ bool idle_startup() } //Default the path if one isn't set. - if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty()) + if (gSavedPerAccountSettings.getString("InstantMessageLogFolder").empty()) { gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir()); - gSavedPerAccountSettings.setString("InstantMessageLogPath",gDirUtilp->getChatLogsDir()); + std::string chat_log_dir = gDirUtilp->getChatLogsDir(); + std::string chat_log_top_folder=gDirUtilp->getBaseFileName(chat_log_dir); + gSavedPerAccountSettings.setString("InstantMessageLogPath",chat_log_dir); + gSavedPerAccountSettings.setString("InstantMessageLogFolder",chat_log_top_folder); } else { @@ -915,15 +996,14 @@ bool idle_startup() LLURLSimString::setString( location ); // END TODO - LLPanelLogin::close(); + LLPanelLogin::closePanel(); } - //For HTML parsing in text boxes. - LLTextEditor::setLinkColor( gSavedSettings.getColor4("HTMLLinkColor") ); - // Load URL History File LLURLHistory::loadFile("url_history.xml"); + // Load location history + LLLocationHistory::getInstance()->load(); //------------------------------------------------- // Handle startup progress screen @@ -943,7 +1023,7 @@ bool idle_startup() // UserLoginLocationReply arrives location_which = START_LOCATION_ID_LAST; } - else if (gSavedSettings.getBOOL("LoginLastLocation")) + else if (gSavedSettings.getString("LoginLocation") == "last" ) { agent_location_id = START_LOCATION_ID_LAST; // last location location_which = START_LOCATION_ID_LAST; @@ -963,7 +1043,7 @@ bool idle_startup() // Display the startup progress bar. gViewerWindow->setShowProgress(TRUE); - gViewerWindow->setProgressCancelButtonVisible(TRUE, std::string("Quit")); // *TODO: Translate + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); // Poke the VFS, which could potentially block for a while if // Windows XP is acting up @@ -972,9 +1052,6 @@ bool idle_startup() gVFS->pokeFiles(); - // color init must be after saved settings loaded - init_colors(); - // skipping over STATE_UPDATE_CHECK because that just waits for input LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT ); @@ -1012,6 +1089,7 @@ bool idle_startup() requested_options.push_back("event_categories"); requested_options.push_back("event_notifications"); requested_options.push_back("classified_categories"); + requested_options.push_back("adult_compliant"); //requested_options.push_back("inventory-targets"); requested_options.push_back("buddy-list"); requested_options.push_back("ui-config"); @@ -1037,9 +1115,7 @@ bool idle_startup() sAuthUriNum = 0; auth_method = "login_to_simulator"; - LLStringUtil::format_map_t args; - args["[APP_NAME]"] = LLAppViewer::instance()->getSecondLifeTitle(); - auth_desc = LLTrans::getString("LoginInProgress", args); + auth_desc = LLTrans::getString("LoginInProgress"); LLStartUp::setStartupState( STATE_LOGIN_AUTHENTICATE ); } @@ -1063,13 +1139,9 @@ bool idle_startup() start << xml_escape_string(unescaped_start.str()); } - else if (gSavedSettings.getBOOL("LoginLastLocation")) - { - start << "last"; - } else { - start << "home"; + start << gSavedSettings.getString("LoginLocation"); } char hashed_mac_string[MD5HEX_STR_SIZE]; /* Flawfinder: ignore */ @@ -1107,7 +1179,7 @@ bool idle_startup() LL_DEBUGS("AppInit") << "STATE_LOGIN_NO_DATA_YET" << LL_ENDL; // If we get here we have gotten past the potential stall // in curl, so take "may appear frozen" out of progress bar. JC - auth_desc = "Logging in..."; + auth_desc = LLTrans::getString("LoginInProgressNoFrozen"); set_startup_status(progress, auth_desc, auth_message); // Process messages to keep from dropping circuit. LLMessageSystem* msg = gMessageSystem; @@ -1218,9 +1290,7 @@ bool idle_startup() { LL_DEBUGS("AppInit") << "Need tos agreement" << LL_ENDL; LLStartUp::setStartupState( STATE_UPDATE_CHECK ); - LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_TOS, - message_response); - tos_dialog->startModal(); + LLFloaterReg::showInstance("message_tos", LLSD(message_response)); // LLFloaterTOS deletes itself. return false; } @@ -1235,9 +1305,7 @@ bool idle_startup() { LL_DEBUGS("AppInit") << "Need critical message" << LL_ENDL; LLStartUp::setStartupState( STATE_UPDATE_CHECK ); - LLFloaterTOS* tos_dialog = LLFloaterTOS::show(LLFloaterTOS::TOS_CRITICAL_MESSAGE, - message_response); - tos_dialog->startModal(); + LLFloaterReg::showInstance("message_critical", LLSD(message_response)); // LLFloaterTOS deletes itself. return false; } @@ -1455,8 +1523,7 @@ bool idle_startup() it = options[0].find("folder_id"); if(it != options[0].end()) { - gAgent.mInventoryRootID.set((*it).second); - //gInventory.mock(gAgent.getInventoryRootID()); + gInventory.setRootFolderID( LLUUID( (*it).second ) ); } } @@ -1487,6 +1554,9 @@ bool idle_startup() if((*it).second == "Y") gPacificDaylightTime = TRUE; else gPacificDaylightTime = FALSE; } + + //setup map of datetime strings to codes and slt & local time offset from utc + LLStringOps::setupDatetimeInfo (gPacificDaylightTime); } options.clear(); if (LLUserAuth::getInstance()->getOptions("initial-outfit", options) @@ -1541,7 +1611,7 @@ bool idle_startup() && gAgentSessionID.notNull() && gMessageSystem->mOurCircuitCode && first_sim.isOk() - && gAgent.mInventoryRootID.notNull()) + && gInventory.getRootFolderID().notNull()) { LLStartUp::setStartupState( STATE_WORLD_INIT ); } @@ -1589,7 +1659,7 @@ bool idle_startup() //--------------------------------------------------------------------- if (STATE_WORLD_INIT == LLStartUp::getStartupState()) { - set_startup_status(0.40f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); + set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD); display_startup(); // We should have an agent id by this point. llassert(!(gAgentID == LLUUID::null)); @@ -1601,11 +1671,12 @@ bool idle_startup() // Since we connected, save off the settings so the user doesn't have to // type the name/password again if we crash. gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); + LLUIColorTable::instance().saveUserSettings(); // // Initialize classes w/graphics stuff. // - gImageList.doPrefetchImages(); + gTextureList.doPrefetchImages(); LLSurface::initClasses(); LLFace::initClass(); @@ -1617,9 +1688,16 @@ bool idle_startup() LLWLParamManager::initClass(); LLWaterParamManager::initClass(); - // RN: don't initialize VO classes in drone mode, they are too closely tied to rendering LLViewerObject::initVOClasses(); + // Initialize all our tools. Must be done after saved settings loaded. + // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton. + LLToolMgr::getInstance()->initTools(); + + // Pre-load floaters, like the world map, that are slow to spawn + // due to XML complexity. + gViewerWindow->initWorldUI(); + display_startup(); // This is where we used to initialize gWorldp. Original comment said: @@ -1662,6 +1740,14 @@ bool idle_startup() if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState()) { LLStartUp::multimediaInit(); + LLStartUp::setStartupState( STATE_FONT_INIT ); + return FALSE; + } + + // Loading fonts takes several seconds + if (STATE_FONT_INIT == LLStartUp::getStartupState()) + { + LLStartUp::fontInit(); LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT ); return FALSE; } @@ -1690,33 +1776,6 @@ bool idle_startup() gLoginMenuBarView->setVisible( FALSE ); gLoginMenuBarView->setEnabled( FALSE ); - LLRect window(0, gViewerWindow->getWindowHeight(), gViewerWindow->getWindowWidth(), 0); - gViewerWindow->adjustControlRectanglesForFirstUse(window); - - if(gSavedSettings.getBOOL("ShowMiniMap")) - { - LLFloaterMap::showInstance(); - } - - if (gSavedSettings.getBOOL("ShowCameraControls")) - { - LLFloaterCamera::showInstance(); - } - if (gSavedSettings.getBOOL("ShowMovementControls")) - { - LLFloaterMove::showInstance(); - } - - if (gSavedSettings.getBOOL("ShowActiveSpeakers")) - { - LLFloaterActiveSpeakers::showInstance(); - } - - if (gSavedSettings.getBOOL("BeaconAlwaysOn")) - { - LLFloaterBeacons::showInstance(); - } - if (!gNoRender) { // Move the progress view in front of the UI @@ -1725,10 +1784,6 @@ bool idle_startup() LLError::logToFixedBuffer(gDebugView->mDebugConsolep); // set initial visibility of debug console gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole")); - if (gSavedSettings.getBOOL("ShowDebugStats")) - { - LLFloaterStats::showInstance(); - } } // @@ -1752,8 +1807,10 @@ bool idle_startup() if ( gCacheName == NULL ) { gCacheName = new LLCacheName(gMessageSystem); - gCacheName->addObserver(callback_cache_name); - + gCacheName->addObserver(&callback_cache_name); + gCacheName->LocalizeCacheName("waiting", LLTrans::getString("CacheWaiting")); + gCacheName->LocalizeCacheName("nobody", LLTrans::getString("CacheNobody")); + gCacheName->LocalizeCacheName("none", LLTrans::getString("CacheNone")); // Load stored cache if possible LLAppViewer::instance()->loadNameCache(); } @@ -1767,14 +1824,6 @@ bool idle_startup() //reset statistics LLViewerStats::getInstance()->resetStats(); - if (!gNoRender) - { - // - // Set up all of our statistics UI stuff. - // - init_stat_view(); - } - display_startup(); // // Set up region and surface defaults @@ -1796,15 +1845,8 @@ bool idle_startup() // Make sure agent knows correct aspect ratio // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below - LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWindowDisplayHeight()); - if (gViewerWindow->mWindow->getFullscreen()) - { - LLViewerCamera::getInstance()->setAspect(gViewerWindow->getDisplayAspectRatio()); - } - else - { - LLViewerCamera::getInstance()->setAspect( (F32) gViewerWindow->getWindowWidth() / (F32) gViewerWindow->getWindowHeight()); - } + LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeight()); + LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio()); // Initialize FOV LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle")); @@ -1841,7 +1883,7 @@ bool idle_startup() F32 frac = (F32)i / (F32)DECODE_TIME_SEC; set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD); display_startup(); - gImageList.decodeAllImages(1.f); + gTextureList.decodeAllImages(1.f); } LLStartUp::setStartupState( STATE_WORLD_WAIT ); @@ -1987,7 +2029,7 @@ bool idle_startup() it = options[0].find("folder_id"); if(it != options[0].end()) { - gInventoryLibraryRoot.set((*it).second); + gInventory.setLibraryRootFolderID( LLUUID( (*it).second ) ); } } options.clear(); @@ -1999,14 +2041,14 @@ bool idle_startup() it = options[0].find("agent_id"); if(it != options[0].end()) { - gInventoryLibraryOwner.set((*it).second); + gInventory.setLibraryOwnerID( LLUUID( (*it).second ) ); } } options.clear(); if(LLUserAuth::getInstance()->getOptions("inventory-skel-lib", options) - && gInventoryLibraryOwner.notNull()) + && gInventory.getLibraryOwnerID().notNull()) { - if(!gInventory.loadSkeleton(options, gInventoryLibraryOwner)) + if(!gInventory.loadSkeleton(options, gInventory.getLibraryOwnerID())) { LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL; } @@ -2052,24 +2094,7 @@ bool idle_startup() } options.clear(); - if(LLUserAuth::getInstance()->getOptions("ui-config", options)) - { - LLUserAuth::options_t::iterator it = options.begin(); - LLUserAuth::options_t::iterator end = options.end(); - for (; it != end; ++it) - { - LLUserAuth::response_t::const_iterator option_it; - option_it = (*it).find("allow_first_life"); - if(option_it != (*it).end()) - { - if (option_it->second == "Y") - { - LLPanelAvatar::sAllowFirstLife = TRUE; - } - } - } - } - options.clear(); + bool show_hud = false; if(LLUserAuth::getInstance()->getOptions("tutorial_setting", options)) { @@ -2097,10 +2122,9 @@ bool idle_startup() // Either we want to show tutorial because this is the first login // to a Linden Help Island or the user quit with the tutorial // visible. JC - if (show_hud - || gSavedSettings.getBOOL("ShowTutorial")) + if (show_hud || gSavedSettings.getBOOL("ShowTutorial")) { - LLFloaterHUD::showHUD(); + LLFloaterReg::showInstance("hud", LLSD(), FALSE); } options.clear(); @@ -2117,8 +2141,18 @@ bool idle_startup() { LLClassifiedInfo::loadCategories(options); } + + + // This method MUST be called before gInventory.findCategoryUUIDForType because of + // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap. gInventory.buildParentChildMap(); + //all categories loaded. lets create "My Favorites" category + gInventory.findCategoryUUIDForType(LLAssetType::AT_FAVORITE,true); + + // lets create "Friends" and "Friends/All" in the Inventory "Calling Cards" and fill it with buddies + LLFriendCardsManager::instance().syncFriendsFolder(); + llinfos << "Setting Inventory changed mask and notifying observers" << llendl; gInventory.addChangedMask(LLInventoryObserver::ALL, LLUUID::null); gInventory.notifyObservers(); @@ -2145,16 +2179,14 @@ bool idle_startup() llinfos << "Requesting Agent Data" << llendl; gAgent.sendAgentDataUpdateRequest(); - bool shown_at_exit = gSavedSettings.getBOOL("ShowInventory"); - // Create the inventory views llinfos << "Creating Inventory Views" << llendl; - LLInventoryView::showAgentInventory(); + LLFloaterReg::getInstance("inventory"); - // Hide the inventory if it wasn't shown at exit - if(!shown_at_exit) + //default initial content for Favorites Bar + if (gAgent.isFirstLogin()) { - LLInventoryView::toggleVisibility(NULL); + populate_favorites_bar(); } LLStartUp::setStartupState( STATE_MISC ); @@ -2200,6 +2232,7 @@ bool idle_startup() // We're successfully logged in. gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE); + LLFloaterReg::showInitialVisibleInstances(); // based on the comments, we've successfully logged in so we can delete the 'forced' // URL that the updater set in settings.ini (in a mostly paranoid fashion) @@ -2211,6 +2244,7 @@ bool idle_startup() // and make sure it's saved gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); }; if (!gNoRender) @@ -2255,7 +2289,7 @@ bool idle_startup() // Could schedule and delay these for later. const BOOL no_inform_server = FALSE; const BOOL no_deactivate_similar = FALSE; - gGestureManager.activateGestureWithAsset(item_id, asset_id, + LLGestureManager::instance().activateGestureWithAsset(item_id, asset_id, no_inform_server, no_deactivate_similar); // We need to fetch the inventory items for these gestures @@ -2296,38 +2330,20 @@ bool idle_startup() //{ //} + // The reason we show the alert is because we want to + // reduce confusion for when you log in and your provided + // location is not your expected location. So, if this is + // your first login, then you do not have an expectation, + // thus, do not show this alert. if (!gAgent.isFirstLogin()) { bool url_ok = LLURLSimString::sInstance.parse(); - if (!((agent_start_location == "url" && url_ok) || - (!url_ok && ((agent_start_location == "last" && gSavedSettings.getBOOL("LoginLastLocation")) || - (agent_start_location == "home" && !gSavedSettings.getBOOL("LoginLastLocation")))))) - { - // The reason we show the alert is because we want to - // reduce confusion for when you log in and your provided - // location is not your expected location. So, if this is - // your first login, then you do not have an expectation, - // thus, do not show this alert. - LLSD args; - if (url_ok) - { - args["TYPE"] = "desired"; - args["HELP"] = ""; - } - else if (gSavedSettings.getBOOL("LoginLastLocation")) - { - args["TYPE"] = "last"; - args["HELP"] = ""; - } - else - { - args["TYPE"] = "home"; - args["HELP"] = "You may want to set a new home location."; - } - LLNotifications::instance().add("AvatarMoved", args); - } - else + if ((url_ok && agent_start_location == "url") || + (!url_ok && ((agent_start_location == gSavedSettings.getString("LoginLocation"))))) { + // Start location is OK + // Disabled code to restore camera location and focus if logging in to default location + static bool samename = false; if (samename) { // restore old camera pos @@ -2342,13 +2358,30 @@ bool idle_startup() gAgent.stopCameraAnimation(); } } + else + { + std::string msg; + if (url_ok) + { + msg = "AvatarMovedDesired"; + } + else if (gSavedSettings.getString("LoginLocation") == "home") + { + msg = "AvatarMovedHome"; + } + else + { + msg = "AvatarMovedLast"; + } + LLNotifications::instance().add(msg); + } } //DEV-17797. get null folder. Any items found here moved to Lost and Found LLInventoryModel::findLostItems(); //DEV-10530. do cleanup. remove at some later date. jan-2009 - LLPrefsIM::cleanupBadSetting(); + LLFloaterPreference::cleanupBadSetting(); LLStartUp::setStartupState( STATE_PRECACHE ); timeout.reset(); @@ -2456,7 +2489,7 @@ bool idle_startup() else { // OK to just get the wearables - if ( gAgent.areWearablesLoaded() ) + if ( gAgentWearables.areWearablesLoaded() ) { // We have our clothing, proceed. //llinfos << "wearables loaded" << llendl; @@ -2477,12 +2510,12 @@ bool idle_startup() set_startup_status(1.0, "", ""); // Let the map know about the inventory. - if(gFloaterWorldMap) + LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance(); + if(floater_world_map) { - gFloaterWorldMap->observeInventory(&gInventory); - gFloaterWorldMap->observeFriends(); + floater_world_map->observeInventory(&gInventory); + floater_world_map->observeFriends(); } - gViewerWindow->showCursor(); gViewerWindow->getWindow()->resetBusyCount(); gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); @@ -2502,13 +2535,15 @@ bool idle_startup() } // Start automatic replay if the flag is set. - if (gSavedSettings.getBOOL("StatsAutoRun")) + if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession) { LLUUID id; LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL; gAgentPilot.startPlayback(); } + show_debug_menus(); // Debug menu visiblity and First Use trigger + // If we've got a startup URL, dispatch it LLStartUp::dispatchURL(); @@ -2539,6 +2574,11 @@ bool idle_startup() LLAppViewer::instance()->handleLoginComplete(); + // reset timers now that we are running "logged in" logic + LLFastTimer::reset(); + + + return TRUE; } @@ -2597,6 +2637,7 @@ void login_callback(S32 option, void *userdata) { // turn off the setting and write out to disk gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE ); + LLUIColorTable::instance().saveUserSettings(); } // Next iteration through main loop should shut down the app cleanly. @@ -2604,7 +2645,7 @@ void login_callback(S32 option, void *userdata) if (LLAppViewer::instance()->quitRequested()) { - LLPanelLogin::close(); + LLPanelLogin::closePanel(); } return; } @@ -2761,7 +2802,7 @@ bool first_run_dialog_callback(const LLSD& notification, const LLSD& response) if (0 == option) { LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL; - LLWeb::loadURL( CREATE_ACCOUNT_URL ); + LLWeb::loadURLExternal(LLTrans::getString("create_account_url") ); } LLPanelLogin::giveFocus(); @@ -2786,12 +2827,12 @@ bool login_alert_status(const LLSD& notification, const LLSD& response) { case 0: // OK break; - case 1: // Help - LLWeb::loadURL( SUPPORT_URL ); - break; + // case 1: // Help + // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") ); + // break; case 2: // Teleport // Restart the login process, starting at our home locaton - LLURLSimString::setString(LLURLSimString::sLocationStringHome); + LLURLSimString::setString("home"); LLStartUp::setStartupState( STATE_LOGIN_CLEANUP ); break; default: @@ -2806,14 +2847,13 @@ void update_app(BOOL mandatory, const std::string& auth_msg) { // store off config state, as we might quit soon gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE); - + LLUIColorTable::instance().saveUserSettings(); std::ostringstream message; - //*TODO:translate std::string msg; if (!auth_msg.empty()) { - msg = "(" + auth_msg + ") \n"; + msg = "("+ auth_msg + ") \n"; } LLSD args; @@ -2842,10 +2882,12 @@ void update_app(BOOL mandatory, const std::string& auth_msg) #if LL_WINDOWS notification_name += "Windows"; -#else +#elif LL_DARWIN notification_name += "Mac"; +#else + notification_name += "Linux"; #endif - + if (mandatory) { notification_name += "Mandatory"; @@ -2858,7 +2900,6 @@ void update_app(BOOL mandatory, const std::string& auth_msg) } LLNotifications::instance().add(notification_name, args, payload, update_dialog_callback); - } bool update_dialog_callback(const LLSD& notification, const LLSD& response) @@ -2890,6 +2931,13 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response) } return false; } + + // if a sim name was passed in via command line parameter (typically through a SLURL) + if ( LLURLSimString::sInstance.mSimString.length() ) + { + // record the location to start at next time + gSavedSettings.setString("NextLoginLocation", LLURLSimString::sInstance.mSimString); + } LLSD query_map = LLSD::emptyMap(); // *TODO place os string in a global constant @@ -2950,13 +2998,6 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response) return false; } - // if a sim name was passed in via command line parameter (typically through a SLURL) - if ( LLURLSimString::sInstance.mSimString.length() ) - { - // record the location to start at next time - gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); - }; - LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\""; LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL; @@ -2965,13 +3006,6 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response) LLAppViewer::instance()->removeMarkerFile(); // In case updater fails #elif LL_DARWIN - // if a sim name was passed in via command line parameter (typically through a SLURL) - if ( LLURLSimString::sInstance.mSimString.length() ) - { - // record the location to start at next time - gSavedSettings.setString( "NextLoginLocation", LLURLSimString::sInstance.mSimString ); - }; - LLAppViewer::sUpdaterInfo->mUpdateExePath = "'"; LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir(); LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \""; @@ -2985,10 +3019,50 @@ bool update_dialog_callback(const LLSD& notification, const LLSD& response) // Run the auto-updater. system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */ -#elif LL_LINUX || LL_SOLARIS - OSMessageBox("Automatic updating is not yet implemented for Linux.\n" - "Please download the latest version from www.secondlife.com.", - LLStringUtil::null, OSMB_OK); +#elif (LL_LINUX || LL_SOLARIS) && LL_GTK + // we tell the updater where to find the xml containing string + // translations which it can use for its own UI + std::string xml_strings_file = "strings.xml"; + std::vector xui_path_vec = LLUI::getXUIPaths(); + std::string xml_search_paths; + std::vector::const_iterator iter; + // build comma-delimited list of xml paths to pass to updater + for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); ) + { + std::string this_skin_dir = gDirUtilp->getDefaultSkinDir() + + gDirUtilp->getDirDelimiter() + + (*iter); + llinfos << "Got a XUI path: " << this_skin_dir << llendl; + xml_search_paths.append(this_skin_dir); + ++iter; + if (iter != xui_path_vec.end()) + xml_search_paths.append(","); // comma-delimit + } + // build the overall command-line to run the updater correctly + update_exe_path = + gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" + + " --url \"" + update_url.asString() + "\"" + + " --name \"" + LLAppViewer::instance()->getSecondLifeTitle() + "\"" + + " --dest \"" + gDirUtilp->getAppRODataDir() + "\"" + + " --stringsdir \"" + xml_search_paths + "\"" + + " --stringsfile \"" + xml_strings_file + "\""; + + LL_INFOS("AppInit") << "Calling updater: " + << update_exe_path << LL_ENDL; + + // *TODO: we could use the gdk equivilant to ensure the updater + // gets started on the same screen. + GError *error = NULL; + if (!g_spawn_command_line_async(update_exe_path.c_str(), &error)) + { + llerrs << "Failed to launch updater: " + << error->message + << llendl; + } + if (error) + g_error_free(error); +#else + OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK); #endif LLAppViewer::instance()->forceQuit(); return false; @@ -3018,8 +3092,8 @@ void use_circuit_callback(void**, S32 result) void register_viewer_callbacks(LLMessageSystem* msg) { msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data ); - msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerImageList::receiveImageHeader ); - msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerImageList::receiveImagePacket ); + msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader ); + msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket ); msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update ); msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update ); msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update ); @@ -3049,7 +3123,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation); msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance); msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse); - msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatar::processRebakeAvatarTextures); + msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures); msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint); msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response); msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties); @@ -3093,20 +3167,20 @@ void register_viewer_callbacks(LLMessageSystem* msg) LLViewerParcelMgr::processParcelDwellReply); msg->setHandlerFunc("AvatarPropertiesReply", - LLPanelAvatar::processAvatarPropertiesReply); + &LLAvatarPropertiesProcessor::processAvatarPropertiesReply); msg->setHandlerFunc("AvatarInterestsReply", - LLPanelAvatar::processAvatarInterestsReply); + &LLAvatarPropertiesProcessor::processAvatarInterestsReply); msg->setHandlerFunc("AvatarGroupsReply", - LLPanelAvatar::processAvatarGroupsReply); + &LLAvatarPropertiesProcessor::processAvatarGroupsReply); // ratings deprecated //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply, // LLPanelAvatar::processAvatarStatisticsReply); msg->setHandlerFunc("AvatarNotesReply", - LLPanelAvatar::processAvatarNotesReply); + &LLAvatarPropertiesProcessor::processAvatarNotesReply); msg->setHandlerFunc("AvatarPicksReply", - LLPanelAvatar::processAvatarPicksReply); - msg->setHandlerFunc("AvatarClassifiedReply", - LLPanelAvatar::processAvatarClassifiedReply); + &LLAvatarPropertiesProcessor::processAvatarPicksReply); + msg->setHandlerFunc("AvatarClassifiedReply", + &LLAvatarPropertiesProcessor::processAvatarClassifiedReply); msg->setHandlerFuncFast(_PREHASH_CreateGroupReply, LLGroupMgr::processCreateGroupReply); @@ -3124,7 +3198,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) // LLFloaterRate::processReputationIndividualReply); msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate, - LLAgent::processAgentInitialWearablesUpdate ); + LLAgentWearables::processAgentInitialWearablesUpdate ); msg->setHandlerFunc("ScriptControlChange", LLAgent::processScriptControlChange ); @@ -3150,7 +3224,7 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL); msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL); - msg->setHandlerFunc("ImageNotInDatabase", LLViewerImageList::processImageNotInDatabase, NULL); + msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL); msg->setHandlerFuncFast(_PREHASH_GroupMembersReply, LLGroupMgr::processGroupMembersReply); @@ -3180,9 +3254,9 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("MapItemReply", LLWorldMap::processMapItemReply); msg->setHandlerFunc("EventInfoReply", LLPanelEvent::processEventInfoReply); - msg->setHandlerFunc("PickInfoReply", LLPanelPick::processPickInfoReply); + msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply); msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply); - msg->setHandlerFunc("ParcelInfoReply", LLPanelPlace::processParcelInfoReply); + msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply); msg->setHandlerFunc("ScriptDialog", process_script_dialog); msg->setHandlerFunc("LoadURL", process_load_url); msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request); @@ -3202,14 +3276,6 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message); } - -void init_stat_view() -{ - LLFrameStatView *frameviewp = gDebugView->mFrameStatView; - frameviewp->setup(gFrameStats); - frameviewp->mShowPercent = FALSE; -} - void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32) { // nothing @@ -3271,7 +3337,7 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, has_name); if (0 == cat_array.count()) { - gAgent.createStandardWearables(gender); + gAgentWearables.createStandardWearables(gender); } else { @@ -3287,13 +3353,11 @@ void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name, } // Loads a bitmap to display during load -// location_id = 0 => last position -// location_id = 1 => home position void init_start_screen(S32 location_id) { - if (gStartImageGL.notNull()) + if (gStartTexture.notNull()) { - gStartImageGL = NULL; + gStartTexture = NULL; LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; } @@ -3325,7 +3389,6 @@ void init_start_screen(S32 location_id) return; } - gStartImageGL = new LLImageGL(FALSE); gStartImageWidth = start_image_bmp->getWidth(); gStartImageHeight = start_image_bmp->getHeight(); @@ -3333,12 +3396,12 @@ void init_start_screen(S32 location_id) if (!start_image_bmp->decode(raw, 0.0f)) { LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; - gStartImageGL = NULL; + gStartTexture = NULL; return; } raw->expandToPowerOfTwo(); - gStartImageGL->createGLTexture(0, raw); + gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ; } @@ -3346,7 +3409,7 @@ void init_start_screen(S32 location_id) void release_start_screen() { LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL; - gStartImageGL = NULL; + gStartTexture = NULL; } @@ -3406,7 +3469,7 @@ void reset_login() } // Hide any other stuff - LLFloaterMap::hideInstance(); + LLFloaterReg::hideVisibleInstances(); } //--------------------------------------------------------------------------- @@ -3427,16 +3490,26 @@ void LLStartUp::multimediaInit() set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str()); display_startup(); - LLViewerMedia::initClass(); + // LLViewerMedia::initClass(); LLViewerParcelMedia::initClass(); } +void LLStartUp::fontInit() +{ + LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL; + std::string msg = LLTrans::getString("LoginInitializingFonts"); + set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str()); + display_startup(); + + LLFontGL::loadDefaultFonts(); +} + bool LLStartUp::dispatchURL() { // ok, if we've gotten this far and have a startup URL if (!sSLURLCommand.empty()) { - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(sSLURLCommand, web, trusted_browser); } @@ -3454,7 +3527,7 @@ bool LLStartUp::dispatchURL() || (dy*dy > SLOP*SLOP) ) { std::string url = LLURLSimString::getURL(); - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; LLURLDispatcher::dispatch(url, web, trusted_browser); } diff --git a/indra/newview/llstartup.h b/indra/newview/llstartup.h index fe347e9efe..4532c5e586 100644 --- a/indra/newview/llstartup.h +++ b/indra/newview/llstartup.h @@ -33,7 +33,7 @@ #ifndef LL_LLSTARTUP_H #define LL_LLSTARTUP_H -#include "llimagegl.h" +class LLViewerTexture ; // functions bool idle_startup(); @@ -58,6 +58,7 @@ typedef enum { STATE_LOGIN_PROCESS_RESPONSE, // Check authentication reply STATE_WORLD_INIT, // Start building the world STATE_MULTIMEDIA_INIT, // Init the rest of multimedia library + STATE_FONT_INIT, // Load default fonts STATE_SEED_GRANTED_WAIT, // Wait for seed cap grant STATE_SEED_CAP_GRANTED, // Have seed cap grant STATE_WORLD_WAIT, // Waiting for simulator @@ -73,7 +74,7 @@ typedef enum { // exported symbols extern bool gAgentMovementCompleted; -extern LLPointer gStartImageGL; +extern LLPointer gStartTexture; extern std::string gInitialOutfit; extern std::string gInitialOutfitGender; // "male" or "female" @@ -92,6 +93,9 @@ public: static void multimediaInit(); // Initialize LLViewerMedia multimedia engine. + // Load default fonts not already loaded at start screen + static void fontInit(); + // outfit_folder_name can be a folder anywhere in your inventory, // but the name must be a case-sensitive exact match. // gender_name is either "male" or "female" diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index f36d12d638..c724fb5315 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -43,16 +43,16 @@ #include "llfloaterchat.h" #include "llfloaterdirectory.h" // to spawn search #include "llfloaterlagmeter.h" -#include "llfloaterland.h" #include "llfloaterregioninfo.h" #include "llfloaterscriptdebug.h" #include "llhudicon.h" -#include "llinventoryview.h" +#include "llnavigationbar.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llnotify.h" #include "llimview.h" +#include "llsd.h" #include "lltextbox.h" #include "llui.h" #include "llviewerparceloverlay.h" @@ -60,7 +60,7 @@ #include "llviewerstats.h" #include "llviewerwindow.h" #include "llframetimer.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llresmgr.h" #include "llworld.h" #include "llstatgraph.h" @@ -68,14 +68,14 @@ #include "llviewerparcelmgr.h" #include "llviewerthrottle.h" #include "lluictrlfactory.h" -#include "llvoiceclient.h" // for gVoiceClient #include "lltoolmgr.h" #include "llfocusmgr.h" #include "llappviewer.h" - +#include "lltrans.h" // library includes #include "imageids.h" +#include "llfloaterreg.h" #include "llfontgl.h" #include "llrect.h" #include "llerror.h" @@ -91,7 +91,7 @@ // Globals // LLStatusBar *gStatusBar = NULL; -S32 STATUS_BAR_HEIGHT = 0; +S32 STATUS_BAR_HEIGHT = 26; extern S32 MENU_BAR_HEIGHT; @@ -107,29 +107,23 @@ const F32 ICON_TIMER_EXPIRY = 3.f; // How long the balance and health icons sho const F32 ICON_FLASH_FREQUENCY = 2.f; const S32 TEXT_HEIGHT = 18; -static void onClickParcelInfo(void*); -static void onClickBalance(void*); static void onClickBuyCurrency(void*); static void onClickHealth(void*); -static void onClickFly(void*); -static void onClickPush(void*); -static void onClickVoice(void*); -static void onClickBuild(void*); -static void onClickScripts(void*); -static void onClickBuyLand(void*); static void onClickScriptDebug(void*); std::vector LLStatusBar::sDays; std::vector LLStatusBar::sMonths; const U32 LLStatusBar::MAX_DATE_STRING_LENGTH = 2000; -LLStatusBar::LLStatusBar(const std::string& name, const LLRect& rect) -: LLPanel(name, LLRect(), FALSE), // not mouse opaque -mBalance(0), -mHealth(100), -mSquareMetersCredit(0), -mSquareMetersCommitted(0) +LLStatusBar::LLStatusBar(const LLRect& rect) +: LLPanel(), + mBalance(0), + mHealth(100), + mSquareMetersCredit(0), + mSquareMetersCommitted(0) { + setRect(rect); + // status bar can possible overlay menus? setMouseOpaque(FALSE); setIsChrome(TRUE); @@ -149,56 +143,42 @@ mSquareMetersCommitted(0) // build date necessary data (must do after panel built) setupDate(); - mTextParcelName = getChild("ParcelNameText" ); - mTextBalance = getChild("BalanceText" ); - mTextHealth = getChild("HealthText" ); mTextTime = getChild("TimeText" ); + + mBtnBuyCurrency = getChild( "buycurrency" ); + mBtnBuyCurrency->setClickedCallback( onClickBuyCurrency, this ); childSetAction("scriptout", onClickScriptDebug, this); childSetAction("health", onClickHealth, this); - childSetAction("no_fly", onClickFly, this); - childSetAction("buyland", onClickBuyLand, this ); - childSetAction("buycurrency", onClickBuyCurrency, this ); - childSetAction("no_build", onClickBuild, this ); - childSetAction("no_scripts", onClickScripts, this ); - childSetAction("restrictpush", onClickPush, this ); - childSetAction("status_no_voice", onClickVoice, this ); - - childSetCommitCallback("search_editor", onCommitSearch, this); - childSetAction("search_btn", onClickSearch, this); - - childSetVisible("search_editor", gSavedSettings.getBOOL("ShowSearchBar")); - childSetVisible("search_btn", gSavedSettings.getBOOL("ShowSearchBar")); - childSetVisible("menubar_search_bevel_bg", gSavedSettings.getBOOL("ShowSearchBar")); - - childSetActionTextbox("ParcelNameText", onClickParcelInfo ); - childSetActionTextbox("BalanceText", onClickBalance ); // Adding Net Stat Graph S32 x = getRect().getWidth() - 2; S32 y = 0; LLRect r; r.set( x-SIM_STAT_WIDTH, y+MENU_BAR_HEIGHT-1, x, y+1); - mSGBandwidth = new LLStatGraph("BandwidthGraph", r); - mSGBandwidth->setFollows(FOLLOWS_BOTTOM | FOLLOWS_RIGHT); + LLStatGraph::Params sgp; + sgp.name("BandwidthGraph"); + sgp.rect(r); + sgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT); + sgp.mouse_opaque(false); + mSGBandwidth = LLUICtrlFactory::create(sgp); mSGBandwidth->setStat(&LLViewerStats::getInstance()->mKBitStat); - std::string text = childGetText("bandwidth_tooltip") + " "; - LLUIString bandwidth_tooltip = text; // get the text from XML until this widget is XML driven - mSGBandwidth->setLabel(bandwidth_tooltip.getString()); mSGBandwidth->setUnits("Kbps"); mSGBandwidth->setPrecision(0); - mSGBandwidth->setMouseOpaque(FALSE); addChild(mSGBandwidth); x -= SIM_STAT_WIDTH + 2; r.set( x-SIM_STAT_WIDTH, y+MENU_BAR_HEIGHT-1, x, y+1); - mSGPacketLoss = new LLStatGraph("PacketLossPercent", r); - mSGPacketLoss->setFollows(FOLLOWS_BOTTOM | FOLLOWS_RIGHT); + //these don't seem to like being reused + LLStatGraph::Params pgp; + pgp.name("PacketLossPercent"); + pgp.rect(r); + pgp.follows.flags(FOLLOWS_BOTTOM | FOLLOWS_RIGHT); + pgp.mouse_opaque(false); + + mSGPacketLoss = LLUICtrlFactory::create(pgp); mSGPacketLoss->setStat(&LLViewerStats::getInstance()->mPacketsLostPercentStat); - text = childGetText("packet_loss_tooltip") + " "; - LLUIString packet_loss_tooltip = text; // get the text from XML until this widget is XML driven - mSGPacketLoss->setLabel(packet_loss_tooltip.getString()); mSGPacketLoss->setUnits("%"); mSGPacketLoss->setMin(0.f); mSGPacketLoss->setMax(5.f); @@ -206,7 +186,6 @@ mSquareMetersCommitted(0) mSGPacketLoss->setThreshold(1, 1.f); mSGPacketLoss->setThreshold(2, 3.f); mSGPacketLoss->setPrecision(1); - mSGPacketLoss->setMouseOpaque(FALSE); mSGPacketLoss->mPerSec = FALSE; addChild(mSGPacketLoss); @@ -236,77 +215,76 @@ void LLStatusBar::draw() if (isBackgroundVisible()) { + static LLUICachedControl drop_shadow_floater ("DropShadowFloater", 0); + static LLUIColor color_drop_shadow = LLUIColorTable::instance().getColor("ColorDropShadow"); gl_drop_shadow(0, getRect().getHeight(), getRect().getWidth(), 0, - LLUI::sColorsGroup->getColor("ColorDropShadow"), - LLUI::sConfigGroup->getS32("DropShadowFloater") ); + color_drop_shadow, drop_shadow_floater ); } LLPanel::draw(); } +BOOL LLStatusBar::handleRightMouseDown(S32 x, S32 y, MASK mask) +{ + if (mHideNavbarContextMenu) + { + mHideNavbarContextMenu->buildDrawLabels(); + mHideNavbarContextMenu->updateParent(LLMenuGL::sMenuContainer); + LLMenuGL::showPopup(this, mHideNavbarContextMenu, x, y); + } + + return TRUE; +} + +BOOL LLStatusBar::postBuild() +{ + mCommitCallbackRegistrar.add("HideNavbarMenu.Action", boost::bind(&LLStatusBar::onHideNavbarContextMenuItemClicked, this, _2)); + mEnableCallbackRegistrar.add("HideNavbarMenu.EnableMenuItem", boost::bind(&LLStatusBar::onHideNavbarContextMenuItemEnabled, this, _2)); + + mHideNavbarContextMenu = LLUICtrlFactory::getInstance()->createFromFile("menu_hide_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gMenuHolder->addChild(mHideNavbarContextMenu); + + gMenuBarView->setRightMouseDownCallback(boost::bind(&LLStatusBar::onMainMenuRightClicked, this, _1, _2, _3, _4)); + + return TRUE; +} // Per-frame updates of visibility void LLStatusBar::refresh() { - // Adding Net Stat Meter back in - F32 bwtotal = gViewerThrottle.getMaxBandwidth() / 1000.f; - mSGBandwidth->setMin(0.f); - mSGBandwidth->setMax(bwtotal*1.25f); - mSGBandwidth->setThreshold(0, bwtotal*0.75f); - mSGBandwidth->setThreshold(1, bwtotal); - mSGBandwidth->setThreshold(2, bwtotal); - - // *TODO: Localize / translate time - + bool net_stats_visible = gSavedSettings.getBOOL("ShowNetStats"); + + if (net_stats_visible) + { + // Adding Net Stat Meter back in + F32 bwtotal = gViewerThrottle.getMaxBandwidth() / 1000.f; + mSGBandwidth->setMin(0.f); + mSGBandwidth->setMax(bwtotal*1.25f); + mSGBandwidth->setThreshold(0, bwtotal*0.75f); + mSGBandwidth->setThreshold(1, bwtotal); + mSGBandwidth->setThreshold(2, bwtotal); + } + // Get current UTC time, adjusted for the user's clock // being off. time_t utc_time; utc_time = time_corrected(); - // There's only one internal tm buffer. - struct tm* internal_time; + std::string timeStr = getString("time"); + LLSD substitution; + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + mTextTime->setText(timeStr); - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - internal_time = utc_to_pacific_time(utc_time, gPacificDaylightTime); - - S32 hour = internal_time->tm_hour; - S32 min = internal_time->tm_min; - - std::string am_pm = "AM"; - if (hour > 11) - { - hour -= 12; - am_pm = "PM"; - } - - std::string tz = "PST"; - if (gPacificDaylightTime) - { - tz = "PDT"; - } - // Zero hour is 12 AM - if (hour == 0) hour = 12; - std::ostringstream t; - t << std::setfill(' ') << std::setw(2) << hour << ":" - << std::setfill('0') << std::setw(2) << min - << " " << am_pm << " " << tz; - mTextTime->setText(t.str()); - - // Year starts at 1900, set the tooltip to have the date - std::ostringstream date; - date << sDays[internal_time->tm_wday] << ", " - << std::setfill('0') << std::setw(2) << internal_time->tm_mday << " " - << sMonths[internal_time->tm_mon] << " " - << internal_time->tm_year + 1900; - mTextTime->setToolTip(date.str()); + // set the tooltip to have the date + std::string dtStr = getString("timeTooltip"); + LLStringUtil::format (dtStr, substitution); + mTextTime->setToolTip (dtStr); LLRect r; const S32 MENU_RIGHT = gMenuBarView->getRightmostMenuEdge(); S32 x = MENU_RIGHT + MENU_PARCEL_SPACING; S32 y = 0; - bool search_visible = gSavedSettings.getBOOL("ShowSearchBar"); - // reshape menu bar to its content's width if (MENU_RIGHT != gMenuBarView->getRect().getWidth()) { @@ -331,8 +309,8 @@ void LLStatusBar::refresh() childSetVisible("scriptout", false); } - if ((region && region->getAllowDamage()) || - (parcel && parcel->getAllowDamage()) ) + if (gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK && + ((region && region->getAllowDamage()) || (parcel && parcel->getAllowDamage()))) { // set visibility based on flashing if( mHealthTimer->hasExpired() ) @@ -364,293 +342,15 @@ void LLStatusBar::refresh() mTextHealth->setVisible(FALSE); } - if ((region && region->getBlockFly()) || - (parcel && !parcel->getAllowFly()) ) - { - // No Fly Zone - childGetRect( "no_fly", buttonRect ); - childSetVisible( "no_fly", true ); - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_fly", r ); - x += buttonRect.getWidth(); - } - else - { - // Fly Zone - childSetVisible("no_fly", false); - } - - BOOL no_build = parcel && !parcel->getAllowModify(); - if (no_build) - { - childSetVisible("no_build", TRUE); - childGetRect( "no_build", buttonRect ); - // No Build Zone - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_build", r ); - x += buttonRect.getWidth(); - } - else - { - childSetVisible("no_build", FALSE); - } - - BOOL no_scripts = FALSE; - if((region - && ((region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) - || (region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS))) - || (parcel && !parcel->getAllowOtherScripts())) - { - no_scripts = TRUE; - } - if (no_scripts) - { - // No scripts - childSetVisible("no_scripts", TRUE); - childGetRect( "no_scripts", buttonRect ); - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "no_scripts", r ); - x += buttonRect.getWidth(); - } - else - { - // Yes scripts - childSetVisible("no_scripts", FALSE); - } - - BOOL no_region_push = (region && region->getRestrictPushObject()); - BOOL no_push = no_region_push || (parcel && parcel->getRestrictPushObject()); - if (no_push) - { - childSetVisible("restrictpush", TRUE); - childGetRect( "restrictpush", buttonRect ); - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "restrictpush", r ); - x += buttonRect.getWidth(); - } - else - { - childSetVisible("restrictpush", FALSE); - } - - BOOL have_voice = parcel && parcel->getParcelFlagAllowVoice(); - if (have_voice) - { - childSetVisible("status_no_voice", FALSE); - } - else - { - childSetVisible("status_no_voice", TRUE); - childGetRect( "status_no_voice", buttonRect ); - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "status_no_voice", r ); - x += buttonRect.getWidth(); - } - - BOOL canBuyLand = parcel - && !parcel->isPublic() - && LLViewerParcelMgr::getInstance()->canAgentBuyParcel(parcel, false); - childSetVisible("buyland", canBuyLand); - if (canBuyLand) - { - //HACK: layout tweak until this is all xml - x += 9; - childGetRect( "buyland", buttonRect ); - r.setOriginAndSize( x, y, buttonRect.getWidth(), buttonRect.getHeight()); - childSetRect( "buyland", r ); - x += buttonRect.getWidth(); - } - - std::string location_name; - if (region) - { - const LLVector3& agent_pos_region = gAgent.getPositionAgent(); - S32 pos_x = lltrunc( agent_pos_region.mV[VX] ); - S32 pos_y = lltrunc( agent_pos_region.mV[VY] ); - S32 pos_z = lltrunc( agent_pos_region.mV[VZ] ); - - // Round the numbers based on the velocity - LLVector3 agent_velocity = gAgent.getVelocity(); - F32 velocity_mag_sq = agent_velocity.magVecSquared(); - - const F32 FLY_CUTOFF = 6.f; // meters/sec - const F32 FLY_CUTOFF_SQ = FLY_CUTOFF * FLY_CUTOFF; - const F32 WALK_CUTOFF = 1.5f; // meters/sec - const F32 WALK_CUTOFF_SQ = WALK_CUTOFF * WALK_CUTOFF; - - if (velocity_mag_sq > FLY_CUTOFF_SQ) - { - pos_x -= pos_x % 4; - pos_y -= pos_y % 4; - } - else if (velocity_mag_sq > WALK_CUTOFF_SQ) - { - pos_x -= pos_x % 2; - pos_y -= pos_y % 2; - } - - mRegionDetails.mTime = mTextTime->getText(); - mRegionDetails.mBalance = mBalance; - mRegionDetails.mAccessString = region->getSimAccessString(); - mRegionDetails.mPing = region->getNetDetailsForLCD(); - if (parcel) - { - location_name = region->getName() - + llformat(" %d, %d, %d (%s) - %s", - pos_x, pos_y, pos_z, - region->getSimAccessString().c_str(), - parcel->getName().c_str()); - - // keep these around for the LCD to use - mRegionDetails.mRegionName = region->getName(); - mRegionDetails.mParcelName = parcel->getName(); - mRegionDetails.mX = pos_x; - mRegionDetails.mY = pos_y; - mRegionDetails.mZ = pos_z; - - mRegionDetails.mArea = parcel->getArea(); - mRegionDetails.mForSale = parcel->getForSale(); - mRegionDetails.mTraffic = LLViewerParcelMgr::getInstance()->getDwelling(); - - if (parcel->isPublic()) - { - mRegionDetails.mOwner = "Public"; - } - else - { - if (parcel->getIsGroupOwned()) - { - if(!parcel->getGroupID().isNull()) - { - gCacheName->getGroupName(parcel->getGroupID(), mRegionDetails.mOwner); - } - else - { - mRegionDetails.mOwner = "Group Owned"; - } - } - else - { - // Figure out the owner's name - gCacheName->getFullName(parcel->getOwnerID(), mRegionDetails.mOwner); - } - } - } - else - { - location_name = region->getName() - + llformat(" %d, %d, %d (%s)", - pos_x, pos_y, pos_z, - region->getSimAccessString().c_str()); - // keep these around for the LCD to use - mRegionDetails.mRegionName = region->getName(); - mRegionDetails.mParcelName = "Unknown"; - - mRegionDetails.mX = pos_x; - mRegionDetails.mY = pos_y; - mRegionDetails.mZ = pos_z; - mRegionDetails.mArea = 0; - mRegionDetails.mForSale = FALSE; - mRegionDetails.mOwner = "Unknown"; - mRegionDetails.mTraffic = 0.0f; - } - } - else - { - // no region - location_name = "(Unknown)"; - // keep these around for the LCD to use - mRegionDetails.mRegionName = "Unknown"; - mRegionDetails.mParcelName = "Unknown"; - mRegionDetails.mAccessString = "Unknown"; - mRegionDetails.mX = 0; - mRegionDetails.mY = 0; - mRegionDetails.mZ = 0; - mRegionDetails.mArea = 0; - mRegionDetails.mForSale = FALSE; - mRegionDetails.mOwner = "Unknown"; - mRegionDetails.mTraffic = 0.0f; - } - - mTextParcelName->setText(location_name); - - - - // x = right edge - // loop through: stat graphs, search btn, search text editor, money, buy money, clock - // adjust rect - // finally adjust parcel name rect - - S32 new_right = getRect().getWidth(); - if (search_visible) - { - childGetRect("search_btn", r); - //r.translate( new_right - r.mRight, 0); - //childSetRect("search_btn", r); - new_right -= r.getWidth(); - - childGetRect("search_editor", r); - //r.translate( new_right - r.mRight, 0); - //childSetRect("search_editor", r); - new_right -= r.getWidth() + 6; - } - else - { - childGetRect("stat_btn", r); - r.translate( new_right - r.mRight, 0); - childSetRect("stat_btn", r); - new_right -= r.getWidth() + 6; - } - - // Set rects of money, buy money, time - childGetRect("BalanceText", r); - r.translate( new_right - r.mRight, 0); - childSetRect("BalanceText", r); - new_right -= r.getWidth() - 18; - - childGetRect("buycurrency", r); - r.translate( new_right - r.mRight, 0); - childSetRect("buycurrency", r); - new_right -= r.getWidth() + 6; - - childGetRect("TimeText", r); - // mTextTime->getTextPixelWidth(); - r.translate( new_right - r.mRight, 0); - childSetRect("TimeText", r); - // new_right -= r.getWidth() + MENU_PARCEL_SPACING; - - - // Adjust region name and parcel name - x += 8; - - const S32 PARCEL_RIGHT = llmin(mTextTime->getRect().mLeft, mTextParcelName->getTextPixelWidth() + x + 5); - r.set(x+4, getRect().getHeight() - 2, PARCEL_RIGHT, 0); - mTextParcelName->setRect(r); - - // Set search bar visibility - - if (gAgent.getCameraMode() != CAMERA_MODE_MOUSELOOK) - { - // don't monkey with search visibility in mouselook - it will be set - // with setVisibleForMouselook() below - childSetVisible("search_editor", search_visible); - childSetVisible("search_btn", search_visible); - childSetVisible("menubar_search_bevel_bg", search_visible); - } - - mSGBandwidth->setVisible(! search_visible); - mSGPacketLoss->setVisible(! search_visible); - childSetEnabled("stat_btn", ! search_visible); + mSGBandwidth->setVisible(net_stats_visible); + mSGPacketLoss->setVisible(net_stats_visible); + childSetEnabled("stat_btn", net_stats_visible); } void LLStatusBar::setVisibleForMouselook(bool visible) { - mTextBalance->setVisible(visible); mTextTime->setVisible(visible); - childSetVisible("buycurrency", visible); - childSetVisible("search_editor", visible); - childSetVisible("search_btn", visible); - childSetVisible("menubar_search_bevel_bg", visible); + mBtnBuyCurrency->setVisible(visible); mSGBandwidth->setVisible(visible); mSGPacketLoss->setVisible(visible); setBackgroundVisible(visible); @@ -669,9 +369,19 @@ void LLStatusBar::creditBalance(S32 credit) void LLStatusBar::setBalance(S32 balance) { std::string money_str = LLResMgr::getInstance()->getMonetaryString( balance ); - std::string balance_str = "L$"; - balance_str += money_str; - mTextBalance->setText( balance_str ); + + LLStringUtil::format_map_t string_args; + string_args["[AMT]"] = llformat("%s", money_str.c_str()); + std::string labe_str = getString("buycurrencylabel", string_args); + mBtnBuyCurrency->setLabel(labe_str); + + // Resize the balance button so that the label fits it, and the button expands to the left. + // *TODO: LLButton should have an option where to expand. + { + S32 saved_right = mBtnBuyCurrency->getRect().mRight; + mBtnBuyCurrency->autoResize(); + mBtnBuyCurrency->translate(saved_right - mBtnBuyCurrency->getRect().mRight, 0); + } if (mBalance && (fabs((F32)(mBalance - balance)) > gSavedSettings.getF32("UISndMoneyChangeThreshold"))) { @@ -775,18 +485,6 @@ S32 LLStatusBar::getSquareMetersLeft() const return mSquareMetersCredit - mSquareMetersCommitted; } -static void onClickParcelInfo(void* data) -{ - LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - - LLFloaterLand::showInstance(); -} - -static void onClickBalance(void* data) -{ - onClickBuyCurrency(data); -} - static void onClickBuyCurrency(void* data) { LLFloaterBuyCurrency::buyCurrency(); @@ -802,49 +500,6 @@ static void onClickScriptDebug(void*) LLFloaterScriptDebug::show(LLUUID::null); } -static void onClickFly(void* ) -{ - LLNotifications::instance().add("NoFly"); -} - -static void onClickPush(void* ) -{ - LLNotifications::instance().add("PushRestricted"); -} - -static void onClickVoice(void* ) -{ - LLNotifications::instance().add("NoVoice"); -} - -static void onClickBuild(void*) -{ - LLNotifications::instance().add("NoBuild"); -} - -static void onClickScripts(void*) -{ - LLViewerRegion* region = gAgent.getRegion(); - if(region && region->getRegionFlags() & REGION_FLAGS_ESTATE_SKIP_SCRIPTS) - { - LLNotifications::instance().add("ScriptsStopped"); - } - else if(region && region->getRegionFlags() & REGION_FLAGS_SKIP_SCRIPTS) - { - LLNotifications::instance().add("ScriptsNotRunning"); - } - else - { - LLNotifications::instance().add("NoOutsideScripts"); - } -} - -static void onClickBuyLand(void*) -{ - LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - LLViewerParcelMgr::getInstance()->startBuyLand(); -} - // sets the static variables necessary for the date void LLStatusBar::setupDate() { @@ -908,25 +563,52 @@ void LLStatusBar::setupDate() } } -// static -void LLStatusBar::onCommitSearch(LLUICtrl*, void* data) +bool LLStatusBar::onHideNavbarContextMenuItemEnabled(const LLSD& userdata) { - // committing is the same as clicking "search" - onClickSearch(data); + std::string item = userdata.asString(); + + if (item == "show_navbar_navigation_panel") + { + return gSavedSettings.getBOOL("ShowNavbarNavigationPanel"); + } + else if (item == "show_navbar_favorites_panel") + { + return gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"); + } + + return FALSE; } -// static -void LLStatusBar::onClickSearch(void* data) +void LLStatusBar::onHideNavbarContextMenuItemClicked(const LLSD& userdata) { - LLStatusBar* self = (LLStatusBar*)data; - std::string search_text = self->childGetText("search_editor"); - LLFloaterDirectory::showFindAll(search_text); + std::string item = userdata.asString(); + + if (item == "show_navbar_navigation_panel") + { + BOOL state = !gSavedSettings.getBOOL("ShowNavbarNavigationPanel"); + + LLNavigationBar::getInstance()->showNavigationPanel(state); + gSavedSettings.setBOOL("ShowNavbarNavigationPanel", state); + } + else if (item == "show_navbar_favorites_panel") + { + BOOL state = !gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"); + + LLNavigationBar::getInstance()->showFavoritesPanel(state); + gSavedSettings.setBOOL("ShowNavbarFavoritesPanel", state); + } +} + + +void LLStatusBar::onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask) +{ + handleRightMouseDown(x, y, mask); } // static void LLStatusBar::onClickStatGraph(void* data) { - LLFloaterLagMeter::showInstance(); + LLFloaterReg::showInstance("lagmeter"); } BOOL can_afford_transaction(S32 cost) @@ -942,7 +624,7 @@ class LLBalanceHandler : public LLCommandHandler public: // Requires "trusted" browser/URL source LLBalanceHandler() : LLCommandHandler("balance", true) { } - bool handle(const LLSD& tokens, const LLSD& query_map, LLWebBrowserCtrl* web) + bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web) { if (tokens.size() == 1 && tokens[0].asString() == "request") diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index c5b4be035a..b77db2c525 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -34,6 +34,7 @@ #define LL_LLSTATUSBAR_H #include "llpanel.h" +#include // "Constants" loaded from settings.xml at start time extern S32 STATUS_BAR_HEIGHT; @@ -48,49 +49,18 @@ class LLUUID; class LLFrameTimer; class LLStatGraph; -// used by LCD screen -class LLRegionDetails -{ -public: - LLRegionDetails() : - mRegionName("Unknown"), - mParcelName("Unknown"), - mAccessString("Unknown"), - mX(0), - mY(0), - mZ(0), - mArea (0), - mForSale(FALSE), - mOwner("Unknown"), - mTraffic(0), - mBalance(0), - mPing(0) - { - } - std::string mRegionName; - std::string mParcelName; - std::string mAccessString; - S32 mX; - S32 mY; - S32 mZ; - S32 mArea; - BOOL mForSale; - std::string mOwner; - F32 mTraffic; - S32 mBalance; - std::string mTime; - U32 mPing; -}; - class LLStatusBar : public LLPanel { public: - LLStatusBar(const std::string& name, const LLRect& rect ); + LLStatusBar(const LLRect& rect ); /*virtual*/ ~LLStatusBar(); /*virtual*/ void draw(); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + /*virtual*/ BOOL postBuild(); + // MANIPULATORS void setBalance(S32 balance); void debitBalance(S32 debit); @@ -116,23 +86,23 @@ public: S32 getSquareMetersCredit() const; S32 getSquareMetersCommitted() const; S32 getSquareMetersLeft() const; - LLRegionDetails mRegionDetails; private: // simple method to setup the part that holds the date void setupDate(); + bool onHideNavbarContextMenuItemEnabled(const LLSD& userdata); + void onHideNavbarContextMenuItemClicked(const LLSD& userdata); + + void onMainMenuRightClicked(LLUICtrl* ctrl, S32 x, S32 y, MASK mask); static void onCommitSearch(LLUICtrl*, void* data); static void onClickSearch(void* data); static void onClickStatGraph(void* data); private: - LLTextBox *mTextBalance; LLTextBox *mTextHealth; LLTextBox *mTextTime; - LLTextBox* mTextParcelName; - LLStatGraph *mSGBandwidth; LLStatGraph *mSGPacketLoss; @@ -144,6 +114,7 @@ private: S32 mSquareMetersCommitted; LLFrameTimer* mBalanceTimer; LLFrameTimer* mHealthTimer; + LLMenuGL* mHideNavbarContextMenu; static std::vector sDays; static std::vector sMonths; diff --git a/indra/newview/llstylemap.cpp b/indra/newview/llstylemap.cpp index a34b4b83f3..fc125dcf9c 100644 --- a/indra/newview/llstylemap.cpp +++ b/indra/newview/llstylemap.cpp @@ -38,83 +38,53 @@ #include "llviewercontrol.h" #include "llagent.h" -LLStyleMap::LLStyleMap() -{ -} - -LLStyleMap::~LLStyleMap() -{ -} - -LLStyleMap &LLStyleMap::instance() -{ - static LLStyleMap style_map; - return style_map; -} - -// This is similar to the [] accessor except that if the entry doesn't already exist, -// then this will create the entry. -const LLStyleSP &LLStyleMap::lookupAgent(const LLUUID &source) +const LLStyle::Params &LLStyleMap::lookupAgent(const LLUUID &source) { // Find this style in the map or add it if not. This map holds links to residents' profiles. - if (find(source) == end()) + if (mMap.find(source) == mMap.end()) { - LLStyleSP style(new LLStyle); - style->setVisible(true); - style->setFontName(LLStringUtil::null); + LLStyle::Params style_params; if (source != LLUUID::null && source != gAgent.getID() ) { - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - std::string link = llformat("secondlife:///app/agent/%s/about",source.asString().c_str()); - style->setLinkHREF(link); + style_params.color.control = "HTMLLinkColor"; + style_params.link_href = llformat("secondlife:///app/agent/%s/about",source.asString().c_str()); } else { // Make the resident's own name white and don't make the name clickable. - style->setColor(LLColor4::white); + style_params.color = LLColor4::white; } - (*this)[source] = style; + + mMap[source] = LLStyle::Params(); } - return (*this)[source]; + return mMap[source]; } // This is similar to lookupAgent for any generic URL encoded style. -const LLStyleSP &LLStyleMap::lookup(const LLUUID& id, const std::string& link) +const LLStyle::Params &LLStyleMap::lookup(const LLUUID& id, const std::string& link) { // Find this style in the map or add it if not. - iterator iter = find(id); - if (iter == end()) + style_map_t::iterator iter = mMap.find(id); + if (iter == mMap.end()) { - LLStyleSP style(new LLStyle); - style->setVisible(true); - style->setFontName(LLStringUtil::null); + LLStyle::Params style_params; + if (id != LLUUID::null && !link.empty()) { - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - style->setLinkHREF(link); + style_params.color.control = "HTMLLinkColor"; + style_params.link_href = link; } else - style->setColor(LLColor4::white); - (*this)[id] = style; + { + style_params.color = LLColor4::white; + } + mMap[id] = style_params; } else { - LLStyleSP style = (*iter).second; - if ( style->getLinkHREF() != link ) - { - style->setLinkHREF(link); - } + iter->second.link_href = link; } - return (*this)[id]; + return mMap[id]; } -void LLStyleMap::update() -{ - for (style_map_t::iterator iter = begin(); iter != end(); ++iter) - { - LLStyleSP &style = iter->second; - // Update the link color in case it has been changed. - style->setColor(gSavedSettings.getColor4("HTMLLinkColor")); - } -} diff --git a/indra/newview/llstylemap.h b/indra/newview/llstylemap.h index 254509ea1d..d29ff1ae28 100644 --- a/indra/newview/llstylemap.h +++ b/indra/newview/llstylemap.h @@ -36,24 +36,22 @@ #include "llstyle.h" #include "lluuid.h" +#include "llsingleton.h" // Lightweight class for holding and managing mappings between UUIDs and links. // Used (for example) to create clickable name links off of IM chat. -typedef std::map style_map_t; +typedef std::map style_map_t; -class LLStyleMap : public style_map_t +class LLStyleMap : public LLSingleton { public: - LLStyleMap(); - ~LLStyleMap(); // Just like the [] accessor but it will add the entry in if it doesn't exist. - const LLStyleSP &lookupAgent(const LLUUID &source); - const LLStyleSP &lookup(const LLUUID &source, const std::string& link); - static LLStyleMap &instance(); + const LLStyle::Params &lookupAgent(const LLUUID &source); + const LLStyle::Params &lookup(const LLUUID &source, const std::string& link); - // Forces refresh of the entries, call when something changes (e.g. link color). - void update(); +private: + style_map_t mMap; }; #endif // LL_LLSTYLE_MAP_H diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp index a27f0e2254..de3d80f044 100644 --- a/indra/newview/llsurface.cpp +++ b/indra/newview/llsurface.cpp @@ -36,7 +36,7 @@ #include "llrender.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llpatchvertexarray.h" #include "patch_dct.h" #include "patch_code.h" @@ -47,7 +47,7 @@ #include "llappviewer.h" #include "llworld.h" #include "llviewercontrol.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llsurfacepatch.h" #include "llvosurfacepatch.h" #include "llvowater.h" @@ -68,7 +68,6 @@ LLColor4U MAX_WATER_COLOR(0, 48, 96, 240); S32 LLSurface::sTextureSize = 256; S32 LLSurface::sTexelsUpdated = 0; F32 LLSurface::sTextureUpdateTime = 0.f; -LLStat LLSurface::sTexelsUpdatedPerSecStat; // ---------------- LLSurface:: Public Members --------------- @@ -138,12 +137,10 @@ LLSurface::~LLSurface() // Don't enable this until we blitz the draw pool for it as well. -- djs if (mSTexturep) { - gImageList.deleteImage(mSTexturep); mSTexturep = NULL; } if (mWaterTexturep) { - gImageList.deleteImage(mWaterTexturep); mWaterTexturep = NULL; } } @@ -215,18 +212,18 @@ void LLSurface::create(const S32 grids_per_edge, createPatchData(); } -LLViewerImage* LLSurface::getSTexture() +LLViewerTexture* LLSurface::getSTexture() { - if (mSTexturep.notNull() && !mSTexturep->getHasGLTexture()) + if (mSTexturep.notNull() && !mSTexturep->hasValidGLTexture()) { createSTexture(); } return mSTexturep; } -LLViewerImage* LLSurface::getWaterTexture() +LLViewerTexture* LLSurface::getWaterTexture() { - if (mWaterTexturep.notNull() && !mWaterTexturep->getHasGLTexture()) + if (mWaterTexturep.notNull() && !mWaterTexturep->hasValidGLTexture()) { createWaterTexture(); } @@ -250,11 +247,10 @@ void LLSurface::createSTexture() } } - mSTexturep = new LLViewerImage(raw, FALSE); + mSTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); mSTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mSTexturep.get()); - mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - gImageList.addImage(mSTexturep); + gGL.getTexUnit(0)->bind(mSTexturep); + mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); } } @@ -275,11 +271,10 @@ void LLSurface::createWaterTexture() *(default_texture + (i*sTextureSize/2 + j)*4 + 3) = MAX_WATER_COLOR.mV[3]; } } - mWaterTexturep = new LLViewerImage(raw, FALSE); + mWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); mWaterTexturep->dontDiscard(); - gGL.getTexUnit(0)->bind(mWaterTexturep.get()); + gGL.getTexUnit(0)->bind(mWaterTexturep); mWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - gImageList.addImage(mWaterTexturep); } } @@ -629,6 +624,7 @@ void LLSurface::updatePatchVisibilities(LLAgent &agent) BOOL LLSurface::idleUpdate(F32 max_update_time) { + LLMemType mt_ius(LLMemType::MTYPE_IDLE_UPDATE_SURFACE); if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_TERRAIN)) { return FALSE; @@ -1193,7 +1189,7 @@ F32 LLSurface::getWaterHeight() const BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y, const F32 width, const F32 height) { - if (!getWaterTexture()) + if (!getWaterTexture() || !mWaterTexturep->hasGLTexture()) { return FALSE; } diff --git a/indra/newview/llsurface.h b/indra/newview/llsurface.h index 003b2f2505..1f672d2250 100644 --- a/indra/newview/llsurface.h +++ b/indra/newview/llsurface.h @@ -46,7 +46,7 @@ #include "llvowater.h" #include "llpatchvertexarray.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLTimer; class LLUUID; @@ -133,8 +133,8 @@ public: void setWaterHeight(F32 height); F32 getWaterHeight() const; - LLViewerImage *getSTexture(); - LLViewerImage *getWaterTexture(); + LLViewerTexture *getSTexture(); + LLViewerTexture *getWaterTexture(); BOOL hasZData() const { return mHasZData; } void dirtyAllPatches(); // Use this to dirty all patches when changing terrain parameters @@ -173,7 +173,6 @@ public: static F32 sTextureUpdateTime; static S32 sTexelsUpdated; - static LLStat sTexelsUpdatedPerSecStat; protected: void createSTexture(); @@ -206,8 +205,8 @@ protected: // The textures should never be directly initialized - use the setter methods! - LLPointer mSTexturep; // Texture for surface - LLPointer mWaterTexturep; // Water texture + LLPointer mSTexturep; // Texture for surface + LLPointer mWaterTexturep; // Water texture LLPointer mWaterObjp; diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h index 7e84f7f6c5..4cac977305 100644 --- a/indra/newview/llsurfacepatch.h +++ b/indra/newview/llsurfacepatch.h @@ -35,7 +35,7 @@ #include "v3math.h" #include "v3dmath.h" -#include "llmemory.h" +#include "llpointer.h" class LLSurface; class LLVOSurfacePatch; diff --git a/indra/newview/llsyswellitem.cpp b/indra/newview/llsyswellitem.cpp new file mode 100644 index 0000000000..7d9ebc7208 --- /dev/null +++ b/indra/newview/llsyswellitem.cpp @@ -0,0 +1,109 @@ +/** + * @file llsyswellitem.cpp + * @brief // TODO + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llsyswellitem.h" + +#include "llwindow.h" +#include "v4color.h" +#include "lluicolortable.h" + +//--------------------------------------------------------------------------------- +LLSysWellItem::LLSysWellItem(const Params& p) : LLScrollingPanel(p), + mTitle(NULL), + mCloseBtn(NULL), + mIcon(NULL) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_sys_well_item.xml"); + + mTitle = getChild("title"); + mCloseBtn = getChild("close_btn"); + mIcon = getChild("icon"); + + mTitle->setValue(p.title); + mCloseBtn->setClickedCallback(boost::bind(&LLSysWellItem::onClickCloseBtn,this)); + + mID = p.notification_id; +} + +//--------------------------------------------------------------------------------- +LLSysWellItem::~LLSysWellItem() +{ +} + +//--------------------------------------------------------------------------------- +void LLSysWellItem::setTitle( std::string title ) +{ + mTitle->setValue(title); +} + +//--------------------------------------------------------------------------------- +void LLSysWellItem::onClickCloseBtn() +{ + mOnItemClose(this); +} + +//--------------------------------------------------------------------------------- +void LLSysWellItem::updatePanel(BOOL allow_modify) +{ + S32 parent_width = getParent()->getRect().getWidth(); + S32 panel_height = getRect().getHeight(); + + reshape(parent_width, panel_height, TRUE); +} + +//--------------------------------------------------------------------------------- +BOOL LLSysWellItem::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if(!mCloseBtn->getRect().pointInRect(x, y)) + mOnItemClick(this); + + return LLPanel::handleMouseDown(x, y, mask); +} + +//--------------------------------------------------------------------------------- +void LLSysWellItem::onMouseEnter(S32 x, S32 y, MASK mask) +{ + setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemSelected" )); +} + +//--------------------------------------------------------------------------------- +void LLSysWellItem::onMouseLeave(S32 x, S32 y, MASK mask) +{ + setTransparentColor(LLUIColorTable::instance().getColor( "SysWellItemUnselected" )); +} + +//--------------------------------------------------------------------------------- + + diff --git a/indra/newview/llsyswellitem.h b/indra/newview/llsyswellitem.h new file mode 100644 index 0000000000..b0761f2790 --- /dev/null +++ b/indra/newview/llsyswellitem.h @@ -0,0 +1,90 @@ +/** + * @file llsyswellitem.h + * @brief // TODO + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSYSWELLITEM_H +#define LL_LLSYSWELLITEM_H + +#include "llscrollingpanellist.h" +#include "lltextbox.h" +#include "llbutton.h" +#include "lliconctrl.h" + +#include + +class LLSysWellItem : public LLScrollingPanel +{ +public: + struct Params : public LLInitParam::Block + { + LLUUID notification_id; + std::string title; + Params() {}; + }; + + + LLSysWellItem(const Params& p); + virtual ~LLSysWellItem(); + + void updatePanel(BOOL allow_modify); + + // title + void setTitle( std::string title ); + + // get item's ID + LLUUID getID() { return mID; } + + // handlers + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + //callbacks + typedef boost::function syswell_item_callback_t; + typedef boost::signals2::signal syswell_item_signal_t; + syswell_item_signal_t mOnItemClose; + syswell_item_signal_t mOnItemClick; + boost::signals2::connection setOnItemCloseCallback(syswell_item_callback_t cb) { return mOnItemClose.connect(cb); } + boost::signals2::connection setOnItemClickCallback(syswell_item_callback_t cb) { return mOnItemClick.connect(cb); } + +private: + + void onClickCloseBtn(); + + LLTextBox* mTitle; + LLButton* mCloseBtn; + LLIconCtrl* mIcon; + LLUUID mID; +}; + +#endif // LL_LLSYSWELLITEM_H + + diff --git a/indra/newview/llsyswellwindow.cpp b/indra/newview/llsyswellwindow.cpp new file mode 100644 index 0000000000..2bbb5a2767 --- /dev/null +++ b/indra/newview/llsyswellwindow.cpp @@ -0,0 +1,213 @@ +/** + * @file llsyswellwindow.cpp + * @brief // TODO + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "llsyswellwindow.h" + +#include "llbottomtray.h" +#include "llviewercontrol.h" +#include "llviewerwindow.h" + +//--------------------------------------------------------------------------------- +LLSysWellWindow::LLSysWellWindow(const LLSD& key) : LLFloater(LLSD()), + mChannel(NULL), + mScrollContainer(NULL), + mNotificationList(NULL) +{ +} + +//--------------------------------------------------------------------------------- +BOOL LLSysWellWindow::postBuild() +{ + mScrollContainer = getChild("notification_list_container"); + mNotificationList = getChild("notification_list"); + + gViewerWindow->setOnBottomTrayWidthChanged(boost::bind(&LLSysWellWindow::adjustWindowPosition, this)); // *TODO: won't be necessary after docking is realized + mScrollContainer->setBorderVisible(FALSE); + + mDockTongue = LLUI::getUIImage("windows/Flyout_Pointer.png"); + + return TRUE; +} + +//--------------------------------------------------------------------------------- +LLSysWellWindow::~LLSysWellWindow() +{ +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::addItem(LLSysWellItem::Params p) +{ + // do not add clones + if( findItemByID(p.notification_id) >= 0 ) + return; + + LLSysWellItem* new_item = new LLSysWellItem(p); + mNotificationList->addPanel(dynamic_cast(new_item)); + reshapeWindow(); + adjustWindowPosition(); // *TODO: won't be necessary after docking is realized + + new_item->setOnItemCloseCallback(boost::bind(&LLSysWellWindow::onItemClose, this, _1)); + new_item->setOnItemClickCallback(boost::bind(&LLSysWellWindow::onItemClick, this, _1)); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::clear() +{ + // *TODO: fill later +} + +//--------------------------------------------------------------------------------- +S32 LLSysWellWindow::findItemByID(const LLUUID& id) +{ + const LLScrollingPanelList::panel_list_t list = mNotificationList->getPanelList(); + if(list.size() == 0) + return -1; + + LLScrollingPanelList::panel_list_t::const_iterator it; + S32 index = 0; + for(it = list.begin(); it != list.end(); ++it, ++index) + { + if( dynamic_cast(*it)->getID() == id ) + break; + } + + if(it == list.end()) + return -1; + else + return index; + +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::removeItemByID(const LLUUID& id) +{ + S32 index = findItemByID(id); + + if(index >= 0) + mNotificationList->removePanel(index); + else + return; + + reshapeWindow(); + adjustWindowPosition(); // *TODO: won't be necessary after docking is realized + // hide chiclet window if there are no items left + S32 items_left = mNotificationList->getPanelList().size(); + if(items_left == 0) + setVisible(FALSE); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::onItemClick(LLSysWellItem* item) +{ + LLUUID id = item->getID(); + if(mChannel) + mChannel->loadStoredToastByIDToChannel(id); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::onItemClose(LLSysWellItem* item) +{ + LLUUID id = item->getID(); + removeItemByID(id); + if(mChannel) + mChannel->killToastByNotificationID(id); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::toggleWindow() +{ + setVisible(!getVisible()); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::setVisible(BOOL visible) +{ + // on Show adjust position of SysWell chiclet's window + if(visible) + { + if(mChannel) + mChannel->removeAndStoreAllVisibleToasts(); + + adjustWindowPosition(); // *TODO: won't be necessary after docking is realized + } + + if(mChannel) + mChannel->setShowToasts(!visible); + + LLFloater::setVisible(visible); +} + +//--------------------------------------------------------------------------------- +void LLSysWellWindow::adjustWindowPosition() // *TODO: won't be necessary after docking is realized +{ + const S32 WINDOW_MARGIN = 5; + + LLRect btm_rect = LLBottomTray::getInstance()->getRect(); + LLRect this_rect = getRect(); + setOrigin(btm_rect.mRight - this_rect.getWidth() - WINDOW_MARGIN, WINDOW_MARGIN); +} +//--------------------------------------------------------------------------------- +void LLSysWellWindow::reshapeWindow() +{ + // Get size for scrollbar and floater's header + const LLUICachedControl SCROLLBAR_SIZE("UIScrollbarSize", 0); + const LLUICachedControl HEADER_SIZE("UIFloaterHeaderSize", 0); + + // Get item list + const LLScrollingPanelList::panel_list_t list = mNotificationList->getPanelList(); + + // Get height for a scrolling panel list + S32 list_height = mNotificationList->getRect().getHeight(); + + // Check that the floater doesn't exceed its parent view limits after reshape + S32 new_height = list_height + LLScrollingPanelList::GAP_BETWEEN_PANELS + HEADER_SIZE; + + if(new_height > MAX_WINDOW_HEIGHT) + { + reshape(MIN_WINDOW_WIDTH, MAX_WINDOW_HEIGHT, FALSE); + mNotificationList->reshape(MIN_PANELLIST_WIDTH - SCROLLBAR_SIZE, list_height, TRUE); + } + else + { + reshape(MIN_WINDOW_WIDTH, new_height, FALSE); + mNotificationList->reshape(MIN_PANELLIST_WIDTH, list_height, TRUE); + } + + mNotificationList->updatePanels(TRUE); +} + +//--------------------------------------------------------------------------------- + + + diff --git a/indra/newview/llsyswellwindow.h b/indra/newview/llsyswellwindow.h new file mode 100644 index 0000000000..7a107af0d1 --- /dev/null +++ b/indra/newview/llsyswellwindow.h @@ -0,0 +1,92 @@ +/** + * @file llsyswellwindow.h + * @brief // TODO + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSYSWELLWINDOW_H +#define LL_LLSYSWELLWINDOW_H + +#include "llsyswellitem.h" + +#include "llfloater.h" +#include "llbutton.h" +#include "llscreenchannel.h" +#include "llscrollcontainer.h" + +#include "boost/shared_ptr.hpp" + + + +class LLSysWellWindow : public LLFloater +{ +public: + LLSysWellWindow(const LLSD& key); + ~LLSysWellWindow(); + BOOL postBuild(); + + // change attributes + void setChannel(LLNotificationsUI::LLScreenChannel* channel) {mChannel = channel;} + + // Operating with items + void addItem(LLSysWellItem::Params p); + void clear( void ); + void removeItemByID(const LLUUID& id); + S32 findItemByID(const LLUUID& id); + + // Operating with outfit + virtual void setVisible(BOOL visible); + void adjustWindowPosition(); + void toggleWindow(); + + // Handlers + void onItemClick(LLSysWellItem* item); + void onItemClose(LLSysWellItem* item); + + // size constants for the window and for its elements + static const S32 MAX_WINDOW_HEIGHT = 200; + static const S32 MIN_WINDOW_WIDTH = 320; + static const S32 MIN_PANELLIST_WIDTH = 318; + +private: + + void reshapeWindow(); + + // pointer to a corresponding channel's instance + LLNotificationsUI::LLScreenChannel* mChannel; + + LLUIImagePtr mDockTongue; + LLScrollContainer* mScrollContainer; + LLScrollingPanelList* mNotificationList; +}; + +#endif // LL_LLSYSWELLWINDOW_H + + + diff --git a/indra/newview/llteleporthistory.cpp b/indra/newview/llteleporthistory.cpp new file mode 100644 index 0000000000..bc886d5743 --- /dev/null +++ b/indra/newview/llteleporthistory.cpp @@ -0,0 +1,199 @@ +/** + * @file llteleporthistory.cpp + * @brief Teleport history + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llteleporthistory.h" + +#include "llparcel.h" +#include "llsdserialize.h" + +#include "llagent.h" +#include "llslurl.h" +#include "llurlsimstring.h" +#include "llviewercontrol.h" // for gSavedSettings +#include "llviewerparcelmgr.h" +#include "llviewerregion.h" +#include "llworldmap.h" +#include "llagentui.h" + +////////////////////////////////////////////////////////////////////////////// +// LLTeleportHistoryItem +////////////////////////////////////////////////////////////////////////////// + +const std::string& LLTeleportHistoryItem::getTitle() const +{ + return gSavedSettings.getBOOL("ShowCoordinatesOption") ? mFullTitle : mTitle; +} + +////////////////////////////////////////////////////////////////////////////// +// LLTeleportHistory +////////////////////////////////////////////////////////////////////////////// + +LLTeleportHistory::LLTeleportHistory(): + mCurrentItem(-1), + mRequestedItem(-1), + mGotInitialUpdate(false) +{ + mTeleportFinishedConn = LLViewerParcelMgr::getInstance()-> + setTeleportFinishedCallback(boost::bind(&LLTeleportHistory::updateCurrentLocation, this, _1)); + mTeleportFailedConn = LLViewerParcelMgr::getInstance()-> + setTeleportFailedCallback(boost::bind(&LLTeleportHistory::onTeleportFailed, this)); +} + +LLTeleportHistory::~LLTeleportHistory() +{ + mTeleportFinishedConn.disconnect(); + mTeleportFailedConn.disconnect(); +} + +void LLTeleportHistory::goToItem(int idx) + +{ + // Validate specified index. + if (idx < 0 || idx >= (int)mItems.size()) + { + llwarns << "Invalid teleport history index (" << idx << ") specified" << llendl; + dump(); + return; + } + + if (idx == mCurrentItem) + { + llwarns << "Will not teleport to the same location." << llendl; + dump(); + return; + } + + // Attempt to teleport to the requested item. + gAgent.teleportViaLocation(mItems[idx].mGlobalPos); + mRequestedItem = idx; +} + +void LLTeleportHistory::onTeleportFailed() +{ + // Are we trying to teleport within the history? + if (mRequestedItem != -1) + { + // Not anymore. + mRequestedItem = -1; + } +} + +void LLTeleportHistory::updateCurrentLocation(const LLVector3d& new_pos) +{ + if (mRequestedItem != -1) // teleport within the history in progress? + { + mCurrentItem = mRequestedItem; + mRequestedItem = -1; + } + else + { + // If we're getting the initial location update + // while we already have a (loaded) non-empty history, + // there's no need to purge forward items or add a new item. + + if (mGotInitialUpdate || mItems.size() == 0) + { + // Purge forward items (if any). + if(mItems.size()) + mItems.erase (mItems.begin() + mCurrentItem + 1, mItems.end()); + + // Append an empty item to the history and make it current. + mItems.push_back(LLTeleportHistoryItem("", LLVector3d())); + mCurrentItem++; + } + + // Update current history item. + if (mCurrentItem < 0 || mCurrentItem >= (int) mItems.size()) // sanity check + { + llwarns << "Invalid current item. (this should not happen)" << llendl; + return; + } + LLVector3 new_pos_local = gAgent.getPosAgentFromGlobal(new_pos); + mItems[mCurrentItem].mFullTitle = getCurrentLocationTitle(true, new_pos_local); + mItems[mCurrentItem].mTitle = getCurrentLocationTitle(false, new_pos_local); + mItems[mCurrentItem].mGlobalPos = new_pos; + mItems[mCurrentItem].mRegionID = gAgent.getRegion()->getRegionID(); + } + + dump(); + + if (!mGotInitialUpdate) + mGotInitialUpdate = true; + + // Signal the interesting party that we've changed. + onHistoryChanged(); +} + +boost::signals2::connection LLTeleportHistory::setHistoryChangedCallback(history_callback_t cb) +{ + return mHistoryChangedSignal.connect(cb); +} + +void LLTeleportHistory::onHistoryChanged() +{ + mHistoryChangedSignal(); +} + +void LLTeleportHistory::purgeItems() +{ + mItems.erase(mItems.begin(), mItems.end()-1); + // reset the count + mRequestedItem = -1; + mCurrentItem = 0; +} + +// static +std::string LLTeleportHistory::getCurrentLocationTitle(bool full, const LLVector3& local_pos_override) +{ + std::string location_name; + LLAgentUI::ELocationFormat fmt = full ? LLAgentUI::LOCATION_FORMAT_WITHOUT_SIM : LLAgentUI::LOCATION_FORMAT_NORMAL; + + if (!LLAgentUI::buildLocationString(location_name, fmt, local_pos_override)) location_name = "Unknown"; + return location_name; +} + +void LLTeleportHistory::dump() const +{ + llinfos << "Teleport history dump (" << mItems.size() << " items):" << llendl; + + for (size_t i=0; i +#include +#include +#include + + +/** + * An item of the teleport history. + * + * Contains the location's global coordinates and its title. + */ +class LLTeleportHistoryItem +{ +public: + LLTeleportHistoryItem() + {} + + LLTeleportHistoryItem(std::string title, LLVector3d global_pos) + : mTitle(title), mGlobalPos(global_pos) + {} + + /** + * @return title formatted according to the current value of the ShowCoordinatesOption setting. + */ + const std::string& getTitle() const; + + std::string mTitle; // human-readable location title + std::string mFullTitle; // human-readable location title including coordinates + LLVector3d mGlobalPos; // global position + LLUUID mRegionID; // region ID for getting the region info +}; + +/** + * Teleport history. + * + * Along with the navigation bar "Back" and "Forward" buttons + * implements web browser-like navigation functionality. + * + * @see LLNavigationBar + */ +class LLTeleportHistory: public LLSingleton +{ + LOG_CLASS(LLTeleportHistory); + +public: + + typedef std::vector slurl_list_t; + typedef boost::function history_callback_t; + typedef boost::signals2::signal history_signal_t; + + LLTeleportHistory(); + ~LLTeleportHistory(); + + /** + * Go back in the history. + */ + void goBack() { goToItem(getCurrentItemIndex() - 1); } + + /** + * Go forward in the history. + */ + void goForward() { goToItem(getCurrentItemIndex() + 1); } + + /** + * Go to specific item in the history. + * + * The item is specified by its index (starting from 0). + */ + void goToItem(int idx); + + /** + * @return history items. + */ + const slurl_list_t& getItems() const { return mItems; } + void purgeItems(); + /** + * Is the history empty? + * + * History containing single item is treated as empty + * because the item points to the current location. + */ + bool isEmpty() const { return mItems.size() <= 1; } + + /** + * Get index of the current location in the history. + */ + int getCurrentItemIndex() const { return mCurrentItem; } + /** + * Set a callback to be called upon history changes. + * + * Multiple callbacks can be set. + */ + boost::signals2::connection setHistoryChangedCallback(history_callback_t cb); + + /** + * Save history to a file so that we can restore it on startup. + * + * @see load() + */ + void dump() const; + +private: + + /** + * Called by when a teleport fails. + * + * Called via callback set on the LLViewerParcelMgr "teleport failed" signal. + * + * @see mTeleportFailedConn + */ + void onTeleportFailed(); + + /** + * Update current location. + * + * @param new_pos Current agent global position. After local teleports we + * cannot rely on gAgent.getPositionGlobal(), + * so the new position gets passed explicitly. + * + * Called when a teleport finishes. + * Called via callback set on the LLViewerParcelMgr "teleport finished" signal. + * + * Takes mRequestedItem into consideration: if it's not -1 + * (i.e. user is teleporting to an arbitrary location, not to a history item) + * we purge forward items and append a new one, making it current. Otherwise + * we just modify mCurrentItem. + * + * @see mRequestedItem + * @see mGotInitialUpdate + */ + void updateCurrentLocation(const LLVector3d& new_pos); + + /** + * Invokes the "history changed" callback(s). + */ + void onHistoryChanged(); + + /** + * Format current agent location in a human-readable manner. + * + * @param full whether to include coordinates + * @param local_pos_override hack: see description of updateCurrentLocation() + * @return + */ + static std::string getCurrentLocationTitle(bool full, const LLVector3& local_pos_override); + + /** + * Actually, the teleport history. + */ + slurl_list_t mItems; + + /** + * Current position within the history. + */ + int mCurrentItem; + + /** + * Requested position within the history. + * + * When a teleport succeeds, this is checked by updateCurrentLocation() to tell + * if this is a teleport within the history (mRequestedItem >=0) or not (-1). + * + * Set by goToItem(); reset by onTeleportFailed() (if teleport fails). + * + * @see goToItem() + * @see updateCurrentLocation() + */ + int mRequestedItem; + + /** + * Have we received the initial location update? + * + * @see updateCurrentLocation() + */ + bool mGotInitialUpdate; + + /** + * Signal emitted when the history gets changed. + * + * Invokes callbacks set with setHistoryChangedCallback(). + */ + history_signal_t mHistoryChangedSignal; + + /** + * Teleport success notification connection. + * + * Using this connection we get notified when a teleport finishes + * or initial location update occurs. + */ + boost::signals2::connection mTeleportFinishedConn; + + /** + * Teleport failure notification connection. + * + * Using this connection we get notified when a teleport fails. + */ + boost::signals2::connection mTeleportFailedConn; +}; + +#endif diff --git a/indra/newview/llteleporthistorystorage.cpp b/indra/newview/llteleporthistorystorage.cpp new file mode 100644 index 0000000000..b31edf1e5d --- /dev/null +++ b/indra/newview/llteleporthistorystorage.cpp @@ -0,0 +1,164 @@ +/** + * @file llteleporthistorystorage.cpp + * @brief Teleport history + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llteleporthistorystorage.h" + +#include "llsd.h" +#include "llsdserialize.h" +#include "lldir.h" + +static LLTeleportHistoryStorage tpstorage; + +LLTeleportHistoryPersistentItem::LLTeleportHistoryPersistentItem(const LLSD& val) +{ + mTitle = val["title"].asString(); + mGlobalPos.setValue(val["global_pos"]); + mDate = val["date"]; +} + +LLSD LLTeleportHistoryPersistentItem::toLLSD() const +{ + LLSD val; + + val["title"] = mTitle; + val["global_pos"] = mGlobalPos.getValue(); + val["date"] = mDate; + + return val; +} + +LLTeleportHistoryStorage::LLTeleportHistoryStorage() : + mFilename("teleport_history.txt") +{ +} + +LLTeleportHistoryStorage::~LLTeleportHistoryStorage() +{ +} + +void LLTeleportHistoryStorage::purgeItems() +{ + mItems.clear(); +} + +void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos) +{ + mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos)); +} + +void LLTeleportHistoryStorage::addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) +{ + mItems.push_back(LLTeleportHistoryPersistentItem(title, global_pos, date)); +} + +void LLTeleportHistoryStorage::removeItem(S32 idx) +{ + if (idx < 0 || idx >= (S32)mItems.size()) + return; + + mItems.erase (mItems.begin() + idx); +} + +void LLTeleportHistoryStorage::save() +{ + // build filename for each user + std::string resolvedFilename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, mFilename); + + // open the history file for writing + llofstream file (resolvedFilename); + if (!file.is_open()) + { + llwarns << "can't open teleport history file \"" << mFilename << "\" for writing" << llendl; + return; + } + + for (size_t i=0; i(s_item) << std::endl; + } + + file.close(); +} + +void LLTeleportHistoryStorage::load() +{ + // build filename for each user + std::string resolved_filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, mFilename); + + // open the history file for reading + llifstream file(resolved_filename); + if (!file.is_open()) + { + llwarns << "can't load teleport history from file \"" << mFilename << "\"" << llendl; + return; + } + + // remove current entries before we load over them + mItems.clear(); + + // the parser's destructor is protected so we cannot create in the stack. + LLPointer parser = new LLSDNotationParser(); + std::string line; + while (std::getline(file, line)) + { + LLSD s_item; + std::istringstream iss(line); + if (parser->parse(iss, s_item, line.length()) == LLSDParser::PARSE_FAILURE) + { + llinfos << "Parsing saved teleport history failed" << llendl; + break; + } + + mItems.push_back(s_item); + } + + file.close(); +} + +void LLTeleportHistoryStorage::dump() const +{ + llinfos << "Teleport history storage dump (" << mItems.size() << " items):" << llendl; + + for (size_t i=0; i + +#include "llsingleton.h" +#include "lldate.h" +#include "v3dmath.h" + +class LLSD; + +/** + * An item of the teleport history, stored in file + * + * Contains the location's global coordinates, title and date. + */ +class LLTeleportHistoryPersistentItem +{ +public: + LLTeleportHistoryPersistentItem() + {} + + LLTeleportHistoryPersistentItem(const std::string title, const LLVector3d& global_pos) + : mTitle(title), mGlobalPos(global_pos), mDate(LLDate::now()) + {} + + LLTeleportHistoryPersistentItem(const std::string title, const LLVector3d& global_pos, const LLDate& date) + : mTitle(title), mGlobalPos(global_pos), mDate(date) + {} + + LLTeleportHistoryPersistentItem(const LLSD& val); + LLSD toLLSD() const; + + std::string mTitle; + LLVector3d mGlobalPos; + LLDate mDate; +}; + +/** + * Persistent teleport history. + * + */ +class LLTeleportHistoryStorage: public LLSingleton +{ + LOG_CLASS(LLTeleportHistoryStorage); + +public: + + typedef std::vector item_list_list_t; + + LLTeleportHistoryStorage(); + ~LLTeleportHistoryStorage(); + + /** + * @return history items. + */ + const item_list_list_t& getItems() const { return mItems; } + void purgeItems(); + + void addItem(const std::string title, const LLVector3d& global_pos); + void addItem(const std::string title, const LLVector3d& global_pos, const LLDate& date); + + void removeItem(S32 idx); + + void save(); + void load(); + + void dump() const; + +private: + + item_list_list_t mItems; + std::string mFilename; +}; + +#endif //LL_LLTELEPORTHISTORYSTORAGE_H diff --git a/indra/newview/lltexglobalcolor.cpp b/indra/newview/lltexglobalcolor.cpp new file mode 100644 index 0000000000..e81c3731f7 --- /dev/null +++ b/indra/newview/lltexglobalcolor.cpp @@ -0,0 +1,150 @@ +/** + * @file lltexlayerglobalcolor.cpp + * @brief SERAPH - ADD IN + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "lltexlayer.h" +#include "llvoavatar.h" +#include "lltexglobalcolor.h" + +//----------------------------------------------------------------------------- +// LLTexGlobalColor +//----------------------------------------------------------------------------- + +LLTexGlobalColor::LLTexGlobalColor(LLVOAvatar* avatar) + : + mAvatar(avatar), + mInfo(NULL) +{ +} + +LLTexGlobalColor::~LLTexGlobalColor() +{ + // mParamColorList are LLViewerVisualParam's and get deleted with ~LLCharacter() + //std::for_each(mParamColorList.begin(), mParamColorList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) +{ + llassert(mInfo == NULL); + mInfo = info; + //mID = info->mID; // No ID + + mParamGlobalColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) + { + LLTexParamGlobalColor* param_color = new LLTexParamGlobalColor(this); + if (!param_color->setInfo(*iter)) + { + mInfo = NULL; + return FALSE; + } + mParamGlobalColorList.push_back(param_color); + } + + return TRUE; +} + +LLColor4 LLTexGlobalColor::getColor() const +{ + // Sum of color params + if (mParamGlobalColorList.empty()) + return LLColor4(1.f, 1.f, 1.f, 1.f); + + LLColor4 net_color(0.f, 0.f, 0.f, 0.f); + LLTexLayer::calculateTexLayerColor(mParamGlobalColorList, net_color); + return net_color; +} + +const std::string& LLTexGlobalColor::getName() const +{ + return mInfo->mName; +} + +//----------------------------------------------------------------------------- +// LLTexParamGlobalColor +//----------------------------------------------------------------------------- +LLTexParamGlobalColor::LLTexParamGlobalColor(LLTexGlobalColor* tex_global_color) : + LLTexLayerParamColor((LLTexLayer*)NULL), + mTexGlobalColor(tex_global_color) +{ + mAvatar = tex_global_color->getAvatar(); +} + +void LLTexParamGlobalColor::onGlobalColorChanged(bool set_by_user) +{ + mAvatar->onGlobalColorChanged(mTexGlobalColor, set_by_user); +} + +//----------------------------------------------------------------------------- +// LLTexGlobalColorInfo +//----------------------------------------------------------------------------- + +LLTexGlobalColorInfo::LLTexGlobalColorInfo() +{ +} + + +LLTexGlobalColorInfo::~LLTexGlobalColorInfo() +{ + for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); +} + +BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) +{ + // name attribute + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); + if (!node->getFastAttributeString(name_string, mName)) + { + llwarns << " element is missing name attribute." << llendl; + return FALSE; + } + // sub-element + for (LLXmlTreeNode* child = node->getChildByName("param"); + child; + child = node->getNextNamedChild()) + { + if (child->getChildByName("param_color")) + { + // + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); + if (!info->parseXml(child)) + { + delete info; + return FALSE; + } + mParamColorInfoList.push_back(info); + } + } + return TRUE; +} diff --git a/indra/newview/lltexglobalcolor.h b/indra/newview/lltexglobalcolor.h new file mode 100644 index 0000000000..154b814392 --- /dev/null +++ b/indra/newview/lltexglobalcolor.h @@ -0,0 +1,86 @@ +/** + * @file lltexglobalcolor.h + * @brief This is global texture color info used by llvoavatar. + * + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * + * Copyright (c) 2008-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXGLOBALCOLOR_H +#define LL_LLTEXGLOBALCOLOR_H + +#include "lltexlayer.h" +#include "lltexlayerparams.h" + +class LLVOAvatar; +class LLTexGlobalColorInfo; + +class LLTexGlobalColor +{ +public: + LLTexGlobalColor( LLVOAvatar* avatar ); + ~LLTexGlobalColor(); + + LLTexGlobalColorInfo* getInfo() const { return mInfo; } + // This sets mInfo and calls initialization functions + BOOL setInfo(LLTexGlobalColorInfo *info); + + LLVOAvatar* getAvatar() const { return mAvatar; } + LLColor4 getColor() const; + const std::string& getName() const; + +private: + param_color_list_t mParamGlobalColorList; + LLVOAvatar* mAvatar; // just backlink, don't LLPointer + LLTexGlobalColorInfo *mInfo; +}; + +// Used by llvoavatar to determine skin/eye/hair color. +class LLTexGlobalColorInfo +{ + friend class LLTexGlobalColor; +public: + LLTexGlobalColorInfo(); + ~LLTexGlobalColorInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + +private: + param_color_info_list_t mParamColorInfoList; + std::string mName; +}; + +class LLTexParamGlobalColor : public LLTexLayerParamColor +{ +public: + LLTexParamGlobalColor(LLTexGlobalColor *tex_color); +protected: + /*virtual*/ void onGlobalColorChanged(bool set_by_user); +private: + LLTexGlobalColor* mTexGlobalColor; +}; + +#endif diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp index 424c525870..5a5f187415 100644 --- a/indra/newview/lltexlayer.cpp +++ b/indra/newview/lltexlayer.cpp @@ -31,80 +31,56 @@ */ #include "llviewerprecompiledheaders.h" - -#include "imageids.h" #include "llagent.h" -#include "llcrc.h" -#include "lldir.h" -#include "llglheaders.h" -#include "llimagebmp.h" -#include "llimagej2c.h" -#include "llimagetga.h" -#include "llpolymorph.h" -#include "llquantize.h" #include "lltexlayer.h" -#include "llui.h" -#include "llvfile.h" -#include "llviewerimagelist.h" -#include "llviewerimagelist.h" -#include "llviewerregion.h" #include "llviewerstats.h" -#include "llviewerwindow.h" +#include "llviewerregion.h" #include "llvoavatar.h" -#include "llxmltree.h" +#include "llvoavatarself.h" #include "pipeline.h" -#include "v4coloru.h" -#include "llrender.h" #include "llassetuploadresponders.h" +#include "lltexlayerparams.h" +#include "llui.h" //#include "../tools/imdebug/imdebug.h" using namespace LLVOAvatarDefines; -// static -S32 LLTexLayerSetBuffer::sGLByteCount = 0; -S32 LLTexLayerSetBuffer::sGLBumpByteCount = 0; - //----------------------------------------------------------------------------- // LLBakedUploadData() //----------------------------------------------------------------------------- -LLBakedUploadData::LLBakedUploadData( LLVOAvatar* avatar, - LLTexLayerSet* layerset, - LLTexLayerSetBuffer* layerset_buffer, - const LLUUID & id ) : - mAvatar( avatar ), - mLayerSet( layerset ), - mLayerSetBuffer( layerset_buffer ), - mID(id) +LLBakedUploadData::LLBakedUploadData(const LLVOAvatarSelf* avatar, + LLTexLayerSet* layerset, + const LLUUID& id) : + mAvatar(avatar), + mTexLayerSet(layerset), + mID(id), + mStartTime(LLFrameTimer::getTotalTime()) // Record starting time { - mStartTime = LLFrameTimer::getTotalTime(); // Record starting time - for( S32 i = 0; i < WT_COUNT; i++ ) - { - LLWearable* wearable = gAgent.getWearable( (EWearableType)i); - if( wearable ) - { - mWearableAssets[i] = wearable->getID(); - } - } } //----------------------------------------------------------------------------- // LLTexLayerSetBuffer // The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one. //----------------------------------------------------------------------------- -LLTexLayerSetBuffer::LLTexLayerSetBuffer( LLTexLayerSet* owner, S32 width, S32 height, BOOL has_bump ) - : + +// static +S32 LLTexLayerSetBuffer::sGLByteCount = 0; +S32 LLTexLayerSetBuffer::sGLBumpByteCount = 0; + +LLTexLayerSetBuffer::LLTexLayerSetBuffer(LLTexLayerSet* const owner, + S32 width, S32 height, + BOOL has_bump) : // ORDER_LAST => must render these after the hints are created. - LLDynamicTexture( width, height, 4, LLDynamicTexture::ORDER_LAST, TRUE ), + LLViewerDynamicTexture( width, height, 4, LLViewerDynamicTexture::ORDER_LAST, TRUE ), mNeedsUpdate( TRUE ), mNeedsUpload( FALSE ), mUploadPending( FALSE ), // Not used for any logic here, just to sync sending of updates - mTexLayerSet( owner ) + mTexLayerSet(owner), + mHasBump(has_bump), + mBumpTex(NULL) { LLTexLayerSetBuffer::sGLByteCount += getSize(); - mHasBump = has_bump ; - mBumpTex = NULL ; - createBumpTexture() ; } @@ -115,15 +91,16 @@ LLTexLayerSetBuffer::~LLTexLayerSetBuffer() if( mBumpTex.notNull()) { mBumpTex = NULL ; - LLImageGL::sGlobalTextureMemoryInBytes -= mWidth * mHeight * 4; - LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4; + LLImageGL::sGlobalTextureMemoryInBytes -= mFullWidth * mFullHeight * 4; + LLTexLayerSetBuffer::sGLBumpByteCount -= mFullWidth * mFullHeight * 4; } } + //virtual void LLTexLayerSetBuffer::restoreGLTexture() { createBumpTexture() ; - LLDynamicTexture::restoreGLTexture() ; + LLViewerDynamicTexture::restoreGLTexture() ; } //virtual @@ -132,11 +109,11 @@ void LLTexLayerSetBuffer::destroyGLTexture() if( mBumpTex.notNull() ) { mBumpTex = NULL ; - LLImageGL::sGlobalTextureMemoryInBytes -= mWidth * mHeight * 4; - LLTexLayerSetBuffer::sGLBumpByteCount -= mWidth * mHeight * 4; + LLImageGL::sGlobalTextureMemoryInBytes -= mFullWidth * mFullHeight * 4; + LLTexLayerSetBuffer::sGLBumpByteCount -= mFullWidth * mFullHeight * 4; } - LLDynamicTexture::destroyGLTexture() ; + LLViewerDynamicTexture::destroyGLTexture() ; } void LLTexLayerSetBuffer::createBumpTexture() @@ -144,7 +121,7 @@ void LLTexLayerSetBuffer::createBumpTexture() if( mHasBump ) { LLGLSUIDefault gls_ui; - mBumpTex = new LLImageGL(FALSE) ; + mBumpTex = LLViewerTextureManager::getLocalTexture(FALSE) ; if(!mBumpTex->createGLTexture()) { mBumpTex = NULL ; @@ -158,13 +135,13 @@ void LLTexLayerSetBuffer::createBumpTexture() gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_RGBA8, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, NULL); stop_glerror(); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - LLImageGL::sGlobalTextureMemoryInBytes += mWidth * mHeight * 4; - LLTexLayerSetBuffer::sGLBumpByteCount += mWidth * mHeight * 4; + LLImageGL::sGlobalTextureMemoryInBytes += mFullWidth * mFullHeight * 4; + LLTexLayerSetBuffer::sGLBumpByteCount += mFullWidth * mFullHeight * 4; } } @@ -202,19 +179,19 @@ void LLTexLayerSetBuffer::cancelUpload() mUploadPending = FALSE; } -void LLTexLayerSetBuffer::pushProjection() +void LLTexLayerSetBuffer::pushProjection() const { glMatrixMode(GL_PROJECTION); gGL.pushMatrix(); glLoadIdentity(); - glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f); + glOrtho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); gGL.pushMatrix(); glLoadIdentity(); } -void LLTexLayerSetBuffer::popProjection() +void LLTexLayerSetBuffer::popProjection() const { glMatrixMode(GL_PROJECTION); gGL.popMatrix(); @@ -225,12 +202,12 @@ void LLTexLayerSetBuffer::popProjection() BOOL LLTexLayerSetBuffer::needsRender() { - LLVOAvatar* avatar = mTexLayerSet->getAvatar(); + const LLVOAvatarSelf* avatar = mTexLayerSet->getAvatar(); BOOL upload_now = mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal(); - BOOL needs_update = gAgent.mNumPendingQueries == 0 && (mNeedsUpdate || upload_now) && !avatar->mAppearanceAnimating; + BOOL needs_update = gAgentQueryManager.hasNoPendingQueries() && (mNeedsUpdate || upload_now) && !avatar->mAppearanceAnimating; if (needs_update) { - BOOL invalid_skirt = avatar->getBakedTE(mTexLayerSet) == TEX_SKIRT_BAKED && !avatar->isWearingWearableType(WT_SKIRT); + BOOL invalid_skirt = avatar->getBakedTE(mTexLayerSet) == LLVOAvatarDefines::TEX_SKIRT_BAKED && !avatar->isWearingWearableType(WT_SKIRT); if (invalid_skirt) { // we were trying to create a skirt texture @@ -253,14 +230,14 @@ void LLTexLayerSetBuffer::preRender(BOOL clear_depth) pushProjection(); // keep depth buffer, we don't need to clear it - LLDynamicTexture::preRender(FALSE); + LLViewerDynamicTexture::preRender(FALSE); } void LLTexLayerSetBuffer::postRender(BOOL success) { popProjection(); - LLDynamicTexture::postRender(success); + LLViewerDynamicTexture::postRender(success); } BOOL LLTexLayerSetBuffer::render() @@ -272,14 +249,14 @@ BOOL LLTexLayerSetBuffer::render() // do we need to upload, and do we have sufficient data to create an uploadable composite? // When do we upload the texture if gAgent.mNumPendingQueries is non-zero? - BOOL upload_now = (gAgent.mNumPendingQueries == 0 && mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal()); + BOOL upload_now = (gAgentQueryManager.hasNoPendingQueries() && mNeedsUpload && mTexLayerSet->isLocalTextureDataFinal()); BOOL success = TRUE; // Composite bump if( mBumpTex.notNull() ) { // Composite the bump data - success &= mTexLayerSet->renderBump( mOrigin.mX, mOrigin.mY, mWidth, mHeight ); + success &= mTexLayerSet->renderBump( mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight ); stop_glerror(); if (success) @@ -290,14 +267,14 @@ BOOL LLTexLayerSetBuffer::render() gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mBumpTex->getTexName()); stop_glerror(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mOrigin.mX, mOrigin.mY, mWidth, mHeight); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight); stop_glerror(); // if we need to upload the data, read it back into a buffer if( upload_now ) { - baked_bump_data = new U8[ mWidth * mHeight * 4 ]; - glReadPixels(mOrigin.mX, mOrigin.mY, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_bump_data ); + baked_bump_data = new U8[ mFullWidth * mFullHeight * 4 ]; + glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_bump_data ); stop_glerror(); } } @@ -305,14 +282,13 @@ BOOL LLTexLayerSetBuffer::render() // Composite the color data LLGLSUIDefault gls_ui; - success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mWidth, mHeight ); + success &= mTexLayerSet->render( mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight ); gGL.flush(); if( upload_now ) { if (!success) { - delete [] baked_bump_data; llinfos << "Failed attempt to bake " << mTexLayerSet->getBodyRegion() << llendl; mUploadPending = FALSE; } @@ -327,15 +303,16 @@ BOOL LLTexLayerSetBuffer::render() gGL.setSceneBlendType(LLRender::BT_ALPHA); // we have valid texture data now - mTexture->setGLTextureCreated(true); + mGLTexturep->setGLTextureCreated(true); mNeedsUpdate = FALSE; + delete [] baked_bump_data; return success; } bool LLTexLayerSetBuffer::isInitialized(void) const { - return mTexture.notNull() && mTexture->isGLTextureCreated(); + return mGLTexturep.notNull() && mGLTexturep->isGLTextureCreated(); } BOOL LLTexLayerSetBuffer::updateImmediate() @@ -353,12 +330,12 @@ BOOL LLTexLayerSetBuffer::updateImmediate() return result; } -void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) +void LLTexLayerSetBuffer::readBackAndUpload(const U8* baked_bump_data) { // pointers for storing data to upload - U8* baked_color_data = new U8[ mWidth * mHeight * 4 ]; + U8* baked_color_data = new U8[ mFullWidth * mFullHeight * 4 ]; - glReadPixels(mOrigin.mX, mOrigin.mY, mWidth, mHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); + glReadPixels(mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, GL_RGBA, GL_UNSIGNED_BYTE, baked_color_data ); stop_glerror(); llinfos << "Baked " << mTexLayerSet->getBodyRegion() << llendl; @@ -373,31 +350,27 @@ void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) LLGLSUIDefault gls_ui; - LLPointer baked_mask_image = new LLImageRaw(mWidth, mHeight, 1 ); + LLPointer baked_mask_image = new LLImageRaw(mFullWidth, mFullHeight, 1 ); U8* baked_mask_data = baked_mask_image->getData(); - - mTexLayerSet->gatherAlphaMasks(baked_mask_data, mWidth, mHeight); -// imdebug("lum b=8 w=%d h=%d %p", mWidth, mHeight, baked_mask_data); - + + mTexLayerSet->gatherMorphMaskAlpha(baked_mask_data, mFullWidth, mFullHeight); // writes into baked_color_data const char* comment_text = NULL; S32 baked_image_components = mBumpTex.notNull() ? 5 : 4; // red green blue [bump] clothing - LLPointer baked_image = new LLImageRaw( mWidth, mHeight, baked_image_components ); + LLPointer baked_image = new LLImageRaw( mFullWidth, mFullHeight, baked_image_components ); U8* baked_image_data = baked_image->getData(); + if( mBumpTex.notNull() ) { comment_text = LINDEN_J2C_COMMENT_PREFIX "RGBHM"; // 5 channels: rgb, heightfield/alpha, mask - // Hide the alpha for the eyelashes in a corner of the bump map - if (mTexLayerSet->getBodyRegion() == "head") - { S32 i = 0; - for( S32 u = 0; u < mWidth; u++ ) + for( S32 u = 0; u < mFullWidth; u++ ) { - for( S32 v = 0; v < mHeight; v++ ) + for( S32 v = 0; v < mFullHeight; v++ ) { baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; @@ -411,28 +384,9 @@ void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) else { S32 i = 0; - for( S32 u = 0; u < mWidth; u++ ) + for( S32 u = 0; u < mFullWidth; u++ ) { - for( S32 v = 0; v < mHeight; v++ ) - { - baked_image_data[5*i + 0] = baked_color_data[4*i + 0]; - baked_image_data[5*i + 1] = baked_color_data[4*i + 1]; - baked_image_data[5*i + 2] = baked_color_data[4*i + 2]; - baked_image_data[5*i + 3] = 255; // reserve for alpha - baked_image_data[5*i + 4] = baked_mask_data[i]; - i++; - } - } - } - } - else - { - if (mTexLayerSet->getBodyRegion() == "skirt" || mTexLayerSet->getBodyRegion() == "hair") - { - S32 i = 0; - for( S32 u = 0; u < mWidth; u++ ) - { - for( S32 v = 0; v < mHeight; v++ ) + for( S32 v = 0; v < mFullHeight; v++ ) { baked_image_data[4*i + 0] = baked_color_data[4*i + 0]; baked_image_data[4*i + 1] = baked_color_data[4*i + 1]; @@ -442,22 +396,6 @@ void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) } } } - else - { - S32 i = 0; - for( S32 u = 0; u < mWidth; u++ ) - { - for( S32 v = 0; v < mHeight; v++ ) - { - baked_image_data[4*i + 0] = baked_color_data[4*i + 0]; - baked_image_data[4*i + 1] = baked_color_data[4*i + 1]; - baked_image_data[4*i + 2] = baked_color_data[4*i + 2]; - baked_image_data[4*i + 3] = 255; // eyes should have no mask - reserve for alpha - i++; - } - } - } - } LLPointer compressedImage = new LLImageJ2C; compressedImage->setRate(0.f); @@ -490,7 +428,7 @@ void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) { // baked_upload_data is owned by the responder and deleted after the request completes LLBakedUploadData* baked_upload_data = - new LLBakedUploadData( gAgent.getAvatarObject(), this->mTexLayerSet, this, asset_id ); + new LLBakedUploadData(gAgent.getAvatarObject(), this->mTexLayerSet, asset_id); mUploadID = asset_id; // upload the image @@ -536,73 +474,74 @@ void LLTexLayerSetBuffer::readBackAndUpload(U8* baked_bump_data) } delete [] baked_color_data; - delete [] baked_bump_data; } // static -void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, void* userdata, S32 result, LLExtStat ext_status) // StoreAssetData callback (not fixed) +void LLTexLayerSetBuffer::onTextureUploadComplete(const LLUUID& uuid, + void* userdata, + S32 result, + LLExtStat ext_status) // StoreAssetData callback (not fixed) { LLBakedUploadData* baked_upload_data = (LLBakedUploadData*)userdata; - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); - if (0 == result && avatar && !avatar->isDead()) + if (0 == result && + avatar && + !avatar->isDead() && + baked_upload_data->mAvatar == avatar && // Sanity check: only the user's avatar should be uploading textures. + baked_upload_data->mTexLayerSet->hasComposite() + ) { - // Sanity check: only the user's avatar should be uploading textures. - if( baked_upload_data->mAvatar == avatar ) + LLTexLayerSetBuffer* layerset_buffer = baked_upload_data->mTexLayerSet->getComposite(); + + if (layerset_buffer->mUploadID.isNull()) { - // Composite may have changed since the pointer was stored - need to do some checking. - LLTexLayerSetBuffer* prev_layerset_buffer = baked_upload_data->mLayerSetBuffer; - // Can't just call getComposite() because this will trigger creation if none exists. - LLTexLayerSetBuffer* curr_layerset_buffer = - baked_upload_data->mLayerSet->hasComposite()?baked_upload_data->mLayerSet->getComposite():NULL; + // The upload got canceled, we should be in the + // process of baking a new texture so request an + // upload with the new data - if (prev_layerset_buffer != curr_layerset_buffer) + // BAP: does this really belong in this callback, as + // opposed to where the cancellation takes place? + // suspect this does nothing. + layerset_buffer->requestUpload(); + } + else if (baked_upload_data->mID == layerset_buffer->mUploadID) + { + // This is the upload we're currently waiting for. + layerset_buffer->mUploadID.setNull(); + layerset_buffer->mUploadPending = FALSE; + + if (result >= 0) { - llinfos << "Baked texture out of date, composite no longer valid, ignored" << llendl; + LLVOAvatarDefines::ETextureIndex baked_te = avatar->getBakedTE(layerset_buffer->mTexLayerSet); + // Update baked texture info with the new UUID + U64 now = LLFrameTimer::getTotalTime(); // Record starting time + llinfos << "Baked texture upload took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl; + avatar->setNewBakedTexture(baked_te, uuid); } else - { - curr_layerset_buffer->mUploadPending = FALSE; - - if (curr_layerset_buffer->mUploadID.isNull()) - { - // The upload got canceled, we should be in the process of baking a new texture - // so request an upload with the new data - curr_layerset_buffer->requestUpload(); - } - else if( baked_upload_data->mID == curr_layerset_buffer->mUploadID ) - { - // This is the upload we're currently waiting for. - curr_layerset_buffer->mUploadID.setNull(); - - if( result >= 0 ) - { - ETextureIndex baked_te = avatar->getBakedTE( curr_layerset_buffer->mTexLayerSet ); - U64 now = LLFrameTimer::getTotalTime(); // Record starting time - llinfos << "Baked texture upload took " << (S32)((now - baked_upload_data->mStartTime) / 1000) << " ms" << llendl; - avatar->setNewBakedTexture( baked_te, uuid ); - } - else - { - llinfos << "Baked upload failed. Reason: " << result << llendl; - // *FIX: retry upload after n seconds, asset server could be busy - } - } - else - { - llinfos << "Received baked texture out of date, ignored." << llendl; - } - - avatar->dirtyMesh(); + { + // Avatar appearance is changing, ignore the upload results + llinfos << "Baked upload failed. Reason: " << result << llendl; + // *FIX: retry upload after n seconds, asset server could be busy } } + else + { + llinfos << "Received baked texture out of date, ignored." << llendl; + } + + avatar->dirtyMesh(); } else { - // Baked texture failed to upload, but since we didn't set the new baked texture, it means that they'll - // try and rebake it at some point in the future (after login?) + // Baked texture failed to upload (in which case since we + // didn't set the new baked texture, it means that they'll try + // and rebake it at some point in the future (after login?)), + // or this response to upload is out of date, in which case a + // current response should be on the way or already processed. llwarns << "Baked upload failed" << llendl; } @@ -616,11 +555,7 @@ void LLTexLayerSetBuffer::bindBumpTexture( U32 stage ) gGL.getTexUnit(stage)->bindManual(LLTexUnit::TT_TEXTURE, mBumpTex->getTexName()); gGL.getTexUnit(0)->activate(); - if( mLastBindTime != LLImageGL::sLastFrameTime ) - { - mLastBindTime = LLImageGL::sLastFrameTime; - LLImageGL::updateBoundTexMem(mWidth * mHeight * 4); - } + mGLTexturep->updateBindStats(mFullWidth * mFullHeight * 4); } else { @@ -635,8 +570,7 @@ void LLTexLayerSetBuffer::bindBumpTexture( U32 stage ) // An ordered set of texture layers that get composited into a single texture. //----------------------------------------------------------------------------- -LLTexLayerSetInfo::LLTexLayerSetInfo( ) - : +LLTexLayerSetInfo::LLTexLayerSetInfo() : mBodyRegion( "" ), mWidth( 512 ), mHeight( 512 ), @@ -701,6 +635,19 @@ BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) return TRUE; } +// creates visual params without generating layersets or layers +void LLTexLayerSetInfo::createVisualParams(LLVOAvatar *avatar) +{ + //layer_info_list_t mLayerInfoList; + for (layer_info_list_t::iterator layer_iter = mLayerInfoList.begin(); + layer_iter != mLayerInfoList.end(); + layer_iter++) + { + LLTexLayerInfo *layer_info = *layer_iter; + layer_info->createVisualParams(avatar); + } +} + //----------------------------------------------------------------------------- // LLTexLayerSet // An ordered set of texture layers that get composited into a single texture. @@ -708,8 +655,7 @@ BOOL LLTexLayerSetInfo::parseXml(LLXmlTreeNode* node) BOOL LLTexLayerSet::sHasCaches = FALSE; -LLTexLayerSet::LLTexLayerSet( LLVOAvatar* avatar ) - : +LLTexLayerSet::LLTexLayerSet(LLVOAvatarSelf* const avatar) : mComposite( NULL ), mAvatar( avatar ), mUpdatesEnabled( FALSE ), @@ -720,23 +666,25 @@ LLTexLayerSet::LLTexLayerSet( LLVOAvatar* avatar ) LLTexLayerSet::~LLTexLayerSet() { + deleteCaches(); std::for_each(mLayerList.begin(), mLayerList.end(), DeletePointer()); - delete mComposite; + std::for_each(mMaskLayerList.begin(), mMaskLayerList.end(), DeletePointer()); } //----------------------------------------------------------------------------- // setInfo //----------------------------------------------------------------------------- -BOOL LLTexLayerSet::setInfo(LLTexLayerSetInfo *info) +BOOL LLTexLayerSet::setInfo(const LLTexLayerSetInfo *info) { llassert(mInfo == NULL); mInfo = info; //mID = info->mID; // No ID - LLTexLayerSetInfo::layer_info_list_t::iterator iter; mLayerList.reserve(info->mLayerInfoList.size()); - for (iter = info->mLayerInfoList.begin(); iter != info->mLayerInfoList.end(); iter++) + for (LLTexLayerSetInfo::layer_info_list_t::const_iterator iter = info->mLayerInfoList.begin(); + iter != info->mLayerInfoList.end(); + iter++) { LLTexLayer* layer = new LLTexLayer( this ); if (!layer->setInfo(*iter)) @@ -744,8 +692,15 @@ BOOL LLTexLayerSet::setInfo(LLTexLayerSetInfo *info) mInfo = NULL; return FALSE; } + if (!layer->isVisibilityMask()) + { mLayerList.push_back( layer ); } + else + { + mMaskLayerList.push_back(layer); + } + } requestUpdate(); @@ -784,19 +739,26 @@ void LLTexLayerSet::deleteCaches() LLTexLayer* layer = *iter; layer->deleteCaches(); } + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayer* layer = *iter; + layer->deleteCaches(); + } } // Returns TRUE if at least one packet of data has been received for each of the textures that this layerset depends on. -BOOL LLTexLayerSet::isLocalTextureDataAvailable() +BOOL LLTexLayerSet::isLocalTextureDataAvailable() const { - return mAvatar->isLocalTextureDataAvailable( this ); + if (!mAvatar->isSelf()) return FALSE; + return ((LLVOAvatarSelf *)mAvatar)->isLocalTextureDataAvailable(this); } // Returns TRUE if all of the data for the textures that this layerset depends on have arrived. -BOOL LLTexLayerSet::isLocalTextureDataFinal() +BOOL LLTexLayerSet::isLocalTextureDataFinal() const { - return mAvatar->isLocalTextureDataFinal( this ); + if (!mAvatar->isSelf()) return FALSE; + return ((LLVOAvatarSelf *)mAvatar)->isLocalTextureDataFinal(this); } @@ -808,62 +770,26 @@ BOOL LLTexLayerSet::render( S32 x, S32 y, S32 width, S32 height ) LLGLDepthTest gls_depth(GL_FALSE, GL_FALSE); gGL.setColorMask(true, true); + BOOL render_morph = mAvatar->morphMaskNeedsUpdate(mBakedTexIndex); + // composite color layers for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayer* layer = *iter; - if( layer->getRenderPass() == RP_COLOR ) + if (layer->getRenderPass() == LLTexLayer::RP_COLOR) { gGL.flush(); - success &= layer->render( x, y, width, height ); + success &= layer->render(x, y, width, height, render_morph); gGL.flush(); - } - } - - // (Optionally) replace alpha with a single component image from a tga file. - if( !getInfo()->mStaticAlphaFileName.empty() ) - { - LLGLSNoAlphaTest gls_no_alpha_test; - gGL.flush(); - gGL.setColorMask(false, true); - gGL.setSceneBlendType(LLRender::BT_REPLACE); - - { - LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticAlphaFileName, TRUE ); - if( image_gl ) + if (layer->isMorphValid()) { - LLGLSUIDefault gls_ui; - gGL.getTexUnit(0)->bind(image_gl); - gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); - gl_rect_2d_simple_tex( width, height ); - } - else - { - success = FALSE; + mAvatar->setMorphMasksValid(TRUE, mBakedTexIndex); } } - gGL.flush(); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - - gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); - gGL.setColorMask(true, true); - gGL.setSceneBlendType(LLRender::BT_ALPHA); } - else - if( getInfo()->mClearAlpha ) - { - // Set the alpha channel to one (clean up after previous blending) - LLGLDisable no_alpha(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.f, 0.f, 0.f, 1.f ); - gGL.flush(); - gGL.setColorMask(false, true); + + renderAlphaMaskTextures(width, height, false); - gl_rect_2d_simple( width, height ); - - gGL.flush(); - gGL.setColorMask(true, true); - } stop_glerror(); return success; @@ -881,9 +807,9 @@ BOOL LLTexLayerSet::renderBump( S32 x, S32 y, S32 width, S32 height ) for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayer* layer = *iter; - if( layer->getRenderPass() == RP_BUMP ) + if (layer->getRenderPass() == LLTexLayer::RP_BUMP) { - success &= layer->render( x, y, width, height ); +// success &= layer->render(x, y, width, height); } } @@ -901,6 +827,16 @@ BOOL LLTexLayerSet::renderBump( S32 x, S32 y, S32 width, S32 height ) return success; } +BOOL LLTexLayerSet::isBodyRegion(const std::string& region) const +{ + return mInfo->mBodyRegion == region; +} + +const std::string LLTexLayerSet::getBodyRegion() const +{ + return mInfo->mBodyRegion; +} + void LLTexLayerSet::requestUpdate() { if( mUpdatesEnabled ) @@ -933,8 +869,9 @@ void LLTexLayerSet::createComposite() // Composite other avatars at reduced resolution if( !mAvatar->isSelf() ) { - width /= 2; - height /= 2; + // TODO: replace with sanity check to ensure not called for non-self avatars +// width /= 2; +// height /= 2; } mComposite = new LLTexLayerSetBuffer( this, width, height, mHasBump ); } @@ -944,7 +881,6 @@ void LLTexLayerSet::destroyComposite() { if( mComposite ) { - delete mComposite; mComposite = NULL; } } @@ -967,12 +903,14 @@ LLTexLayerSetBuffer* LLTexLayerSet::getComposite() return mComposite; } -void LLTexLayerSet::gatherAlphaMasks(U8 *data, S32 width, S32 height) +void LLTexLayerSet::gatherMorphMaskAlpha(U8 *data, S32 width, S32 height) { S32 size = width * height; memset(data, 255, width * height); + BOOL render_morph = mAvatar->morphMaskNeedsUpdate(mBakedTexIndex); + for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayer* layer = *iter; @@ -981,8 +919,10 @@ void LLTexLayerSet::gatherAlphaMasks(U8 *data, S32 width, S32 height) { LLColor4 net_color; layer->findNetColor( &net_color ); + // TODO: eliminate need for layer morph mask valid flag layer->invalidateMorphMasks(); - layer->renderAlphaMasks(mComposite->getOriginX(), mComposite->getOriginY(), width, height, &net_color); + mAvatar->invalidateMorphMasks(mBakedTexIndex); + layer->renderMorphMasks(mComposite->getOriginX(), mComposite->getOriginY(), width, height, net_color, render_morph); alphaData = layer->getAlphaData(); } if (alphaData) @@ -997,35 +937,111 @@ void LLTexLayerSet::gatherAlphaMasks(U8 *data, S32 width, S32 height) } } } + + // Set alpha back to that of our alpha masks. + renderAlphaMaskTextures(width, height, true); +} + +void LLTexLayerSet::renderAlphaMaskTextures(S32 width, S32 height, bool forceClear) +{ + const LLTexLayerSetInfo *info = getInfo(); + + gGL.setColorMask(false, true); + gGL.setSceneBlendType(LLRender::BT_REPLACE); + // (Optionally) replace alpha with a single component image from a tga file. + if (!info->mStaticAlphaFileName.empty() && mMaskLayerList.empty()) + { + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.flush(); + { + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(info->mStaticAlphaFileName, TRUE); + if( tex ) + { + LLGLSUIDefault gls_ui; + gGL.getTexUnit(0)->bind(tex); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); + gl_rect_2d_simple_tex( width, height ); + } + } + gGL.flush(); + } + else if (forceClear || info->mClearAlpha || (mMaskLayerList.size() > 0)) + { + // Set the alpha channel to one (clean up after previous blending) + gGL.flush(); + LLGLDisable no_alpha(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f( 0.f, 0.f, 0.f, 1.f ); + + gl_rect_2d_simple( width, height ); + + gGL.flush(); + } + + // (Optional) Mask out part of the baked texture with alpha masks + // will still have an effect even if mClearAlpha is set or the alpha component was replaced + if (mMaskLayerList.size() > 0) + { + gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); + gGL.getTexUnit(0)->setTextureBlendType( LLTexUnit::TB_REPLACE ); + for (layer_list_t::iterator iter = mMaskLayerList.begin(); iter != mMaskLayerList.end(); iter++) + { + LLTexLayer* layer = *iter; + gGL.flush(); + layer->blendAlphaTexture(width, height); + gGL.flush(); + } + + } + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + + gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT); + gGL.setColorMask(true, true); + gGL.setSceneBlendType(LLRender::BT_ALPHA); } void LLTexLayerSet::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) +{ + mAvatar->applyMorphMask(tex_data, width, height, num_components, mBakedTexIndex); +} + +//----------------------------------------------------------------------------- +// finds a specific layer based on a passed in name +//----------------------------------------------------------------------------- +LLTexLayer* LLTexLayerSet::findLayerByName(std::string name) { for( layer_list_t::iterator iter = mLayerList.begin(); iter != mLayerList.end(); iter++ ) { LLTexLayer* layer = *iter; - layer->applyMorphMask(tex_data, width, height, num_components); + + if (layer->getName().compare(name) == 0) + { + return layer; + } } + return NULL; } + //----------------------------------------------------------------------------- // LLTexLayerInfo //----------------------------------------------------------------------------- -LLTexLayerInfo::LLTexLayerInfo( ) - : +LLTexLayerInfo::LLTexLayerInfo() : mWriteAllChannels( FALSE ), - mRenderPass( RP_COLOR ), + mRenderPass(LLTexLayer::RP_COLOR), mFixedColor( 0.f, 0.f, 0.f, 0.f ), mLocalTexture( -1 ), mStaticImageIsMask( FALSE ), - mUseLocalTextureAlphaOnly( FALSE ) + mUseLocalTextureAlphaOnly(FALSE), + mIsVisibilityMask(FALSE) { } LLTexLayerInfo::~LLTexLayerInfo( ) { - std::for_each(mColorInfoList.begin(), mColorInfoList.end(), DeletePointer()); - std::for_each(mAlphaInfoList.begin(), mAlphaInfoList.end(), DeletePointer()); + std::for_each(mParamColorInfoList.begin(), mParamColorInfoList.end(), DeletePointer()); + std::for_each(mParamAlphaInfoList.begin(), mParamAlphaInfoList.end(), DeletePointer()); } BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) @@ -1048,7 +1064,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) { if( render_pass_name == "bump" ) { - mRenderPass = RP_BUMP; + mRenderPass = LLTexLayer::RP_BUMP; } } @@ -1057,6 +1073,14 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) static LLStdStringHandle global_color_string = LLXmlTree::addAttributeString("global_color"); node->getFastAttributeString( global_color_string, mGlobalColor ); + // Visibility mask (optional) + BOOL is_visibility; + static LLStdStringHandle visibility_mask_string = LLXmlTree::addAttributeString("visibility_mask"); + if (node->getFastAttributeBOOL(visibility_mask_string, is_visibility)) + { + mIsVisibilityMask = is_visibility; + } + // color attribute (optional) LLColor4U color4u; static LLStdStringHandle fixed_color_string = LLXmlTree::addAttributeString("fixed_color"); @@ -1070,7 +1094,7 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) texture_node; texture_node = node->getNextNamedChild()) { - std::string local_texture; + std::string local_texture_name; static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); static LLStdStringHandle local_texture_string = LLXmlTree::addAttributeString("local_texture"); static LLStdStringHandle file_is_mask_string = LLXmlTree::addAttributeString("file_is_mask"); @@ -1079,73 +1103,27 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) { texture_node->getFastAttributeBOOL( file_is_mask_string, mStaticImageIsMask ); } - else if( texture_node->getFastAttributeString( local_texture_string, local_texture ) ) + else if (texture_node->getFastAttributeString(local_texture_string, local_texture_name)) { texture_node->getFastAttributeBOOL( local_texture_alpha_only_string, mUseLocalTextureAlphaOnly ); - if( "upper_shirt" == local_texture ) + /* if ("upper_shirt" == local_texture_name) + mLocalTexture = TEX_UPPER_SHIRT; */ + mLocalTexture = TEX_NUM_INDICES; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + iter++) { - mLocalTexture = TEX_UPPER_SHIRT; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (local_texture_name == texture_dict->mName) + { + mLocalTexture = iter->first; + break; } - else if( "upper_bodypaint" == local_texture ) - { - mLocalTexture = TEX_UPPER_BODYPAINT; } - else if( "lower_pants" == local_texture ) + if (mLocalTexture == TEX_NUM_INDICES) { - mLocalTexture = TEX_LOWER_PANTS; - } - else if( "lower_bodypaint" == local_texture ) - { - mLocalTexture = TEX_LOWER_BODYPAINT; - } - else if( "lower_shoes" == local_texture ) - { - mLocalTexture = TEX_LOWER_SHOES; - } - else if( "head_bodypaint" == local_texture ) - { - mLocalTexture = TEX_HEAD_BODYPAINT; - } - else if( "lower_socks" == local_texture ) - { - mLocalTexture = TEX_LOWER_SOCKS; - } - else if( "upper_jacket" == local_texture ) - { - mLocalTexture = TEX_UPPER_JACKET; - } - else if( "lower_jacket" == local_texture ) - { - mLocalTexture = TEX_LOWER_JACKET; - } - else if( "upper_gloves" == local_texture ) - { - mLocalTexture = TEX_UPPER_GLOVES; - } - else if( "upper_undershirt" == local_texture ) - { - mLocalTexture = TEX_UPPER_UNDERSHIRT; - } - else if( "lower_underpants" == local_texture ) - { - mLocalTexture = TEX_LOWER_UNDERPANTS; - } - else if( "eyes_iris" == local_texture ) - { - mLocalTexture = TEX_EYES_IRIS; - } - else if( "skirt" == local_texture ) - { - mLocalTexture = TEX_SKIRT; - } - else if( "hair_grain" == local_texture ) - { - mLocalTexture = TEX_HAIR; - } - else - { - llwarns << " element has invalid local_texure attribute: " << mName << " " << local_texture << llendl; + llwarns << " element has invalid local_texure attribute: " << mName << " " << local_texture_name << llendl; return FALSE; } } @@ -1179,13 +1157,13 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) if( child->getChildByName( "param_color" ) ) { // - LLTexParamColorInfo* info = new LLTexParamColorInfo( ); + LLTexLayerParamColorInfo* info = new LLTexLayerParamColorInfo(); if (!info->parseXml(child)) { delete info; return FALSE; } - mColorInfoList.push_back( info ); + mParamColorInfoList.push_back(info); } else if( child->getChildByName( "param_alpha" ) ) { @@ -1196,13 +1174,47 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) delete info; return FALSE; } - mAlphaInfoList.push_back( info ); + mParamAlphaInfoList.push_back(info); } } return TRUE; } +BOOL LLTexLayerInfo::createVisualParams(LLVOAvatar *avatar) +{ + BOOL success = TRUE; + for (param_color_info_list_t::iterator color_info_iter = mParamColorInfoList.begin(); + color_info_iter != mParamColorInfoList.end(); + color_info_iter++) + { + LLTexLayerParamColorInfo * color_info = *color_info_iter; + LLTexLayerParamColor* param_color = new LLTexLayerParamColor(avatar); + if (!param_color->setInfo(color_info)) + { + llwarns << "NULL TexLayer Color Param could not be added to visual param list. Deleting." << llendl; + delete param_color; + success = FALSE; + } + } + + for (param_alpha_info_list_t::iterator alpha_info_iter = mParamAlphaInfoList.begin(); + alpha_info_iter != mParamAlphaInfoList.end(); + alpha_info_iter++) + { + LLTexLayerParamAlphaInfo * alpha_info = *alpha_info_iter; + LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha(avatar); + if (!param_alpha->setInfo(alpha_info)) + { + llwarns << "NULL TexLayer Alpha Param could not be added to visual param list. Deleting." << llendl; + delete param_alpha; + success = FALSE; + } + } + + return success; +} + //----------------------------------------------------------------------------- // LLTexLayer // A single texture layer, consisting of: @@ -1216,15 +1228,25 @@ BOOL LLTexLayerInfo::parseXml(LLXmlTreeNode* node) // * a texture entry index (TE) // * (optional) one or more alpha parameters (weighted alpha textures) //----------------------------------------------------------------------------- -LLTexLayer::LLTexLayer( LLTexLayerSet* layer_set ) - : +LLTexLayer::LLTexLayer(LLTexLayerSet* layer_set) : mTexLayerSet( layer_set ), mMorphMasksValid( FALSE ), mStaticImageInvalid( FALSE ), - mInfo( NULL ) + mInfo(NULL), + mHasMorph(FALSE) { } +LLTexLayer::LLTexLayer(const LLTexLayer &layer) : + mTexLayerSet( layer.mTexLayerSet ) +{ + setInfo(layer.getInfo()); + + + mHasMorph = layer.mHasMorph; + +} + LLTexLayer::~LLTexLayer() { // mParamAlphaList and mParamColorList are LLViewerVisualParam's and get @@ -1238,45 +1260,28 @@ LLTexLayer::~LLTexLayer() U8* alpha_data = iter->second; delete [] alpha_data; } + } //----------------------------------------------------------------------------- // setInfo //----------------------------------------------------------------------------- -BOOL LLTexLayer::setInfo(LLTexLayerInfo* info) +BOOL LLTexLayer::setInfo(const LLTexLayerInfo* info) { llassert(mInfo == NULL); mInfo = info; //mID = info->mID; // No ID - if (info->mRenderPass == RP_BUMP) + if (info->mRenderPass == LLTexLayer::RP_BUMP) mTexLayerSet->setBump(TRUE); + mParamColorList.reserve(mInfo->mParamColorInfoList.size()); + for (param_color_info_list_t::const_iterator iter = mInfo->mParamColorInfoList.begin(); + iter != mInfo->mParamColorInfoList.end(); + iter++) { - LLTexLayerInfo::morph_name_list_t::iterator iter; - for (iter = mInfo->mMorphNameList.begin(); iter != mInfo->mMorphNameList.end(); iter++) - { - // *FIX: we assume that the referenced visual param is a - // morph target, need a better way of actually looking - // this up. - LLPolyMorphTarget *morph_param; - std::string *name = &(iter->first); - morph_param = (LLPolyMorphTarget *)(getTexLayerSet()->getAvatar()->getVisualParam(name->c_str())); - if (morph_param) - { - BOOL invert = iter->second; - addMaskedMorph(morph_param, invert); - } - } - } - - { - LLTexLayerInfo::color_info_list_t::iterator iter; - mParamColorList.reserve(mInfo->mColorInfoList.size()); - for (iter = mInfo->mColorInfoList.begin(); iter != mInfo->mColorInfoList.end(); iter++) - { - LLTexParamColor* param_color = new LLTexParamColor( this ); + LLTexLayerParamColor* param_color = new LLTexLayerParamColor(this); if (!param_color->setInfo(*iter)) { mInfo = NULL; @@ -1284,11 +1289,11 @@ BOOL LLTexLayer::setInfo(LLTexLayerInfo* info) } mParamColorList.push_back( param_color ); } - } - { - LLTexLayerInfo::alpha_info_list_t::iterator iter; - mParamAlphaList.reserve(mInfo->mAlphaInfoList.size()); - for (iter = mInfo->mAlphaInfoList.begin(); iter != mInfo->mAlphaInfoList.end(); iter++) + + mParamAlphaList.reserve(mInfo->mParamAlphaInfoList.size()); + for (param_alpha_info_list_t::const_iterator iter = mInfo->mParamAlphaInfoList.begin(); + iter != mInfo->mParamAlphaInfoList.end(); + iter++) { LLTexLayerParamAlpha* param_alpha = new LLTexLayerParamAlpha( this ); if (!param_alpha->setInfo(*iter)) @@ -1298,84 +1303,83 @@ BOOL LLTexLayer::setInfo(LLTexLayerInfo* info) } mParamAlphaList.push_back( param_alpha ); } - } return TRUE; } -#if 0 // obsolete -//----------------------------------------------------------------------------- -// parseData -//----------------------------------------------------------------------------- -BOOL LLTexLayer::parseData( LLXmlTreeNode* node ) +//static +void LLTexLayer::calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color) { - LLTexLayerInfo *info = new LLTexLayerInfo; - - if (!info->parseXml(node)) + for (param_color_list_t::const_iterator iter = param_list.begin(); + iter != param_list.end(); iter++) +{ + const LLTexLayerParamColor* param = *iter; + LLColor4 param_net = param->getNetColor(); + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)param->getInfo(); + switch(info->getOperation()) { - delete info; - return FALSE; + case LLTexLayerParamColor::OP_ADD: + net_color += param_net; + break; + case LLTexLayerParamColor::OP_MULTIPLY: + net_color = net_color * param_net; + break; + case LLTexLayerParamColor::OP_BLEND: + net_color = lerp(net_color, param_net, param->getWeight()); + break; + default: + llassert(0); + break; } - if (!setInfo(info)) - { - delete info; - return FALSE; } - return TRUE; + net_color.clamp(); } -#endif - -//----------------------------------------------------------------------------- - void LLTexLayer::deleteCaches() { - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) { LLTexLayerParamAlpha* param = *iter; param->deleteCaches(); } - mStaticImageRaw = NULL; } -BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) +BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph) { LLGLEnable color_mat(GL_COLOR_MATERIAL); gPipeline.disableLights(); - BOOL success = TRUE; - - BOOL color_specified = FALSE; - BOOL alpha_mask_specified = FALSE; - LLColor4 net_color; - color_specified = findNetColor( &net_color ); - + BOOL color_specified = findNetColor(&net_color); + if (mTexLayerSet->getAvatar()->mIsDummy) { color_specified = true; net_color = LLVOAvatar::getDummyColor(); } + BOOL success = TRUE; + // If you can't see the layer, don't render it. if( is_approx_zero( net_color.mV[VW] ) ) { return success; } - alpha_list_t::iterator iter = mParamAlphaList.begin(); + BOOL alpha_mask_specified = FALSE; + param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); if( iter != mParamAlphaList.end() ) { // If we have alpha masks, but we're skipping all of them, skip the whole layer. // However, we can't do this optimization if we have morph masks that need updating. - if( mMaskedMorphs.empty() ) + if (!mHasMorph) { BOOL skip_layer = TRUE; while( iter != mParamAlphaList.end() ) { - LLTexLayerParamAlpha* param = *iter; + const LLTexLayerParamAlpha* param = *iter; if( !param->getSkip() ) { @@ -1392,7 +1396,7 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) } } - renderAlphaMasks( x, y, width, height, &net_color ); + renderMorphMasks(x, y, width, height, net_color, render_morph); alpha_mask_specified = TRUE; gGL.flush(); gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ONE_MINUS_DEST_ALPHA); @@ -1409,16 +1413,16 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) if( (getInfo()->mLocalTexture != -1) && !getInfo()->mUseLocalTextureAlphaOnly ) { { - LLImageGL* image_gl = NULL; - if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) ) + LLViewerTexture* tex = NULL; + if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex ) ) { - if( image_gl ) + if( tex ) { LLGLDisable alpha_test(getInfo()->mWriteAllChannels ? GL_ALPHA_TEST : 0); - LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode(); + LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); - gGL.getTexUnit(0)->bind(image_gl); + gGL.getTexUnit(0)->bind(tex); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); gl_rect_2d_simple_tex( width, height ); @@ -1437,10 +1441,10 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) if( !getInfo()->mStaticImageFileName.empty() ) { { - LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); - if( image_gl ) + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) { - gGL.getTexUnit(0)->bind(image_gl); + gGL.getTexUnit(0)->bind(tex); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } @@ -1451,14 +1455,14 @@ BOOL LLTexLayer::render( S32 x, S32 y, S32 width, S32 height ) } } - if( ((-1 == getInfo()->mLocalTexture) || + if(((-1 == getInfo()->mLocalTexture) || getInfo()->mUseLocalTextureAlphaOnly) && getInfo()->mStaticImageFileName.empty() && color_specified ) { LLGLDisable no_alpha(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( net_color.mV); + gGL.color4fv( net_color.mV ); gl_rect_2d_simple( width, height ); } @@ -1483,9 +1487,9 @@ U8* LLTexLayer::getAlphaData() const LLUUID& uuid = mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)getInfo()->mLocalTexture); alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) { - LLTexLayerParamAlpha* param = *iter; + const LLTexLayerParamAlpha* param = *iter; F32 param_weight = param->getWeight(); alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); } @@ -1496,7 +1500,7 @@ U8* LLTexLayer::getAlphaData() return (iter2 == mAlphaCache.end()) ? 0 : iter2->second; } -BOOL LLTexLayer::findNetColor( LLColor4* net_color ) +BOOL LLTexLayer::findNetColor(LLColor4* net_color) const { // Color is either: // * one or more color parameters (weighted colors) (which may make use of a global color or fixed color) @@ -1510,8 +1514,7 @@ BOOL LLTexLayer::findNetColor( LLColor4* net_color ) { net_color->setVec( mTexLayerSet->getAvatar()->getGlobalColor( getInfo()->mGlobalColor ) ); } - else - if( getInfo()->mFixedColor.mV[VW] ) + else if (getInfo()->mFixedColor.mV[VW]) { net_color->setVec( getInfo()->mFixedColor ); } @@ -1520,30 +1523,7 @@ BOOL LLTexLayer::findNetColor( LLColor4* net_color ) net_color->setVec( 0.f, 0.f, 0.f, 0.f ); } - for( color_list_t::iterator iter = mParamColorList.begin(); - iter != mParamColorList.end(); iter++ ) - { - LLTexParamColor* param = *iter; - LLColor4 param_net = param->getNetColor(); - switch( param->getOperation() ) - { - case OP_ADD: - *net_color += param_net; - break; - case OP_MULTIPLY: - net_color->mV[VX] *= param_net.mV[VX]; - net_color->mV[VY] *= param_net.mV[VY]; - net_color->mV[VZ] *= param_net.mV[VZ]; - net_color->mV[VW] *= param_net.mV[VW]; - break; - case OP_BLEND: - net_color->setVec( lerp(*net_color, param_net, param->getWeight()) ); - break; - default: - llassert(0); - break; - } - } + calculateTexLayerColor(mParamColorList, *net_color); return TRUE; } @@ -1564,8 +1544,51 @@ BOOL LLTexLayer::findNetColor( LLColor4* net_color ) return FALSE; // No need to draw a separate colored polygon } +BOOL LLTexLayer::blendAlphaTexture(S32 width, S32 height) +{ + BOOL success = TRUE; -BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4* colorp ) + gGL.flush(); + + if( !getInfo()->mStaticImageFileName.empty() ) + { + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); + if( tex ) + { + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.getTexUnit(0)->bind(tex); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else + { + success = FALSE; + } + } + else + { + if (getInfo()->mLocalTexture >=0 && getInfo()->mLocalTexture < TEX_NUM_INDICES) + { + LLViewerTexture* tex = NULL; + if (mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex)) + { + if (tex) + { + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.getTexUnit(0)->bind(tex); + gl_rect_2d_simple_tex( width, height ); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + success = TRUE; + } + } + } + } + + return success; +} + + +BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, BOOL render_morph) { BOOL success = TRUE; @@ -1573,9 +1596,7 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 gGL.setColorMask(false, true); - alpha_list_t::iterator iter = mParamAlphaList.begin(); - LLTexLayerParamAlpha* first_param = *iter; - + LLTexLayerParamAlpha* first_param = *mParamAlphaList.begin(); // Note: if the first param is a mulitply, multiply against the current buffer's alpha if( !first_param || !first_param->getMultiplyBlend() ) { @@ -1593,8 +1614,7 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 // Accumulate alphas LLGLSNoAlphaTest gls_no_alpha_test; gGL.color4f( 1.f, 1.f, 1.f, 1.f ); - - for( iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) + for (param_alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) { LLTexLayerParamAlpha* param = *iter; success &= param->render( x, y, width, height ); @@ -1602,22 +1622,21 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 // Approximates a min() function gGL.flush(); - gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); + gGL.setSceneBlendType(LLRender::BT_MULT_ALPHA); // Accumulate the alpha component of the texture if( getInfo()->mLocalTexture != -1 ) { - { - LLImageGL* image_gl = NULL; - if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &image_gl ) ) + LLViewerTexture* tex = NULL; + if( mTexLayerSet->getAvatar()->getLocalTextureGL((ETextureIndex)getInfo()->mLocalTexture, &tex ) ) { - if( image_gl && (image_gl->getComponents() == 4) ) + if( tex && (tex->getComponents() == 4) ) { LLGLSNoAlphaTest gls_no_alpha_test; - LLTexUnit::eTextureAddressMode old_mode = image_gl->getAddressMode(); + LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode(); - gGL.getTexUnit(0)->bind(image_gl); + gGL.getTexUnit(0)->bind(tex); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); gl_rect_2d_simple_tex( width, height ); @@ -1631,19 +1650,17 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 success = FALSE; } } - } if( !getInfo()->mStaticImageFileName.empty() ) { - { - LLImageGL* image_gl = gTexStaticImageList.getImageGL( getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask ); - if( image_gl ) + LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask); + if( tex ) { - if( (image_gl->getComponents() == 4) || - ( (image_gl->getComponents() == 1) && getInfo()->mStaticImageIsMask ) ) + if( (tex->getComponents() == 4) || + ( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) ) { LLGLSNoAlphaTest gls_no_alpha_test; - gGL.getTexUnit(0)->bind(image_gl); + gGL.getTexUnit(0)->bind(tex); gl_rect_2d_simple_tex( width, height ); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } @@ -1653,15 +1670,14 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 success = FALSE; } } - } // Draw a rectangle with the layer color to multiply the alpha by that color's alpha. // Note: we're still using gGL.blendFunc( GL_DST_ALPHA, GL_ZERO ); - if( colorp->mV[VW] != 1.f ) + if (layer_color.mV[VW] != 1.f) { LLGLDisable no_alpha(GL_ALPHA_TEST); gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4fv( colorp->mV ); + gGL.color4fv(layer_color.mV); gl_rect_2d_simple( width, height ); } @@ -1670,34 +1686,28 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 gGL.setColorMask(true, true); - if (!mMorphMasksValid && !mMaskedMorphs.empty()) + if (render_morph && mHasMorph) { LLCRC alpha_mask_crc; const LLUUID& uuid = mTexLayerSet->getAvatar()->getLocalTextureID((ETextureIndex)getInfo()->mLocalTexture); alpha_mask_crc.update((U8*)(&uuid.mData), UUID_BYTES); - for( alpha_list_t::iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++ ) + for (param_alpha_list_t::const_iterator iter = mParamAlphaList.begin(); iter != mParamAlphaList.end(); iter++) { - LLTexLayerParamAlpha* param = *iter; + const LLTexLayerParamAlpha* param = *iter; F32 param_weight = param->getWeight(); alpha_mask_crc.update((U8*)¶m_weight, sizeof(F32)); } U32 cache_index = alpha_mask_crc.getCRC(); - - alpha_cache_t::iterator iter2 = mAlphaCache.find(cache_index); - U8* alpha_data; - if (iter2 != mAlphaCache.end()) - { - alpha_data = iter2->second; - } - else + U8* alpha_data = get_if_there(mAlphaCache,cache_index,(U8*)NULL); + if (!alpha_data) { // clear out a slot if we have filled our cache S32 max_cache_entries = getTexLayerSet()->getAvatar()->isSelf() ? 4 : 1; while ((S32)mAlphaCache.size() >= max_cache_entries) { - iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry + alpha_cache_t::iterator iter2 = mAlphaCache.begin(); // arbitrarily grab the first entry alpha_data = iter2->second; delete [] alpha_data; mAlphaCache.erase(iter2); @@ -1710,28 +1720,12 @@ BOOL LLTexLayer::renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4 getTexLayerSet()->getAvatar()->dirtyMesh(); mMorphMasksValid = TRUE; - - for( morph_list_t::iterator iter3 = mMaskedMorphs.begin(); - iter3 != mMaskedMorphs.end(); iter3++ ) - { - LLMaskedMorph* maskedMorph = &(*iter3); - maskedMorph->mMorphTarget->applyMask(alpha_data, width, height, 1, maskedMorph->mInvert); - } + getTexLayerSet()->applyMorphMask(alpha_data, width, height, 1); } return success; } -void LLTexLayer::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components) -{ - for( morph_list_t::iterator iter = mMaskedMorphs.begin(); - iter != mMaskedMorphs.end(); iter++ ) - { - LLMaskedMorph* maskedMorph = &(*iter); - maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); - } -} - // Returns TRUE on success. BOOL LLTexLayer::renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 in_components, S32 width, S32 height, BOOL is_mask ) { @@ -1808,666 +1802,54 @@ void LLTexLayer::requestUpdate() mTexLayerSet->requestUpdate(); } -void LLTexLayer::addMaskedMorph(LLPolyMorphTarget* morph_target, BOOL invert) +const std::string& LLTexLayer::getName() const { - mMaskedMorphs.push_front(LLMaskedMorph(morph_target, invert)); + return mInfo->mName; +} + +LLTexLayer::ERenderPass LLTexLayer::getRenderPass() const +{ + return mInfo->mRenderPass; +} +const std::string& LLTexLayer::getGlobalColor() const +{ + return mInfo->mGlobalColor; } void LLTexLayer::invalidateMorphMasks() { mMorphMasksValid = FALSE; + } + +BOOL LLTexLayer::isVisibilityMask() const + { + return mInfo->mIsVisibilityMask; } //----------------------------------------------------------------------------- -// LLTexLayerParamAlphaInfo -//----------------------------------------------------------------------------- -LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo( ) - : - mMultiplyBlend( FALSE ), - mSkipIfZeroWeight( FALSE ), - mDomain( 0.f ) -{ -} - -BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) -{ - llassert( node->hasName( "param" ) && node->getChildByName( "param_alpha" ) ); - - if( !LLViewerVisualParamInfo::parseXml(node) ) - return FALSE; - - LLXmlTreeNode* param_alpha_node = node->getChildByName( "param_alpha" ); - if( !param_alpha_node ) - { - return FALSE; - } - - static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); - if( param_alpha_node->getFastAttributeString( tga_file_string, mStaticImageFileName ) ) - { - // Don't load the image file until it's actually needed. - } -// else -// { -// llwarns << " element is missing tga_file attribute." << llendl; -// } - - static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend"); - param_alpha_node->getFastAttributeBOOL( multiply_blend_string, mMultiplyBlend ); - - static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero"); - param_alpha_node->getFastAttributeBOOL( skip_if_zero_string, mSkipIfZeroWeight ); - - static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain"); - param_alpha_node->getFastAttributeF32( domain_string, mDomain ); - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlpha +// LLTexLayerStaticImageList //----------------------------------------------------------------------------- -// static -LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances; - -// static -void LLTexLayerParamAlpha::dumpCacheByteCount() -{ - S32 gl_bytes = 0; - getCacheByteCount( &gl_bytes ); - llinfos << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << llendl; -} - -// static -void LLTexLayerParamAlpha::getCacheByteCount( S32* gl_bytes ) -{ - *gl_bytes = 0; - - for( param_alpha_ptr_list_t::iterator iter = sInstances.begin(); - iter != sInstances.end(); iter++ ) - { - LLTexLayerParamAlpha* instance = *iter; - LLImageGL* image_gl = instance->mCachedProcessedImageGL; - if( image_gl ) - { - S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); - - if( image_gl->getHasGLTexture() ) - { - *gl_bytes += bytes; - } - } - } -} - -LLTexLayerParamAlpha::LLTexLayerParamAlpha( LLTexLayer* layer ) - : - mCachedProcessedImageGL( NULL ), - mTexLayer( layer ), - mNeedsCreateTexture( FALSE ), - mStaticImageInvalid( FALSE ), - mAvgDistortionVec(1.f, 1.f, 1.f), - mCachedEffectiveWeight(0.f) -{ - sInstances.push_front( this ); -} - -LLTexLayerParamAlpha::~LLTexLayerParamAlpha() -{ - deleteCaches(); - sInstances.remove( this ); -} - -//----------------------------------------------------------------------------- -// setInfo() -//----------------------------------------------------------------------------- -BOOL LLTexLayerParamAlpha::setInfo(LLTexLayerParamAlphaInfo *info) -{ - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mInfo = info; - mID = info->mID; - - mTexLayer->getTexLayerSet()->getAvatar()->addVisualParam( this ); - setWeight(getDefaultWeight(), FALSE ); - - return TRUE; -} - -//----------------------------------------------------------------------------- - -void LLTexLayerParamAlpha::deleteCaches() -{ - mStaticImageTGA = NULL; // deletes image - mCachedProcessedImageGL = NULL; - mStaticImageRaw = NULL; - mNeedsCreateTexture = FALSE; -} - -void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL set_by_user) -{ - if (mIsAnimating) - { - return; - } - F32 min_weight = getMinWeight(); - F32 max_weight = getMaxWeight(); - F32 new_weight = llclamp(weight, min_weight, max_weight); - U8 cur_u8 = F32_to_U8( mCurWeight, min_weight, max_weight ); - U8 new_u8 = F32_to_U8( new_weight, min_weight, max_weight ); - if( cur_u8 != new_u8) - { - mCurWeight = new_weight; - - LLVOAvatar* avatar = mTexLayer->getTexLayerSet()->getAvatar(); - if( avatar->getSex() & getSex() ) - { - if ( gAgent.cameraCustomizeAvatar() ) - { - set_by_user = FALSE; - } - avatar->invalidateComposite( mTexLayer->getTexLayerSet(), set_by_user ); - mTexLayer->invalidateMorphMasks(); - avatar->updateMeshTextures(); - } - } -} - -void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL set_by_user) -{ - mTargetWeight = target_value; - setWeight(target_value, set_by_user); - mIsAnimating = TRUE; - if (mNext) - { - mNext->setAnimationTarget(target_value, set_by_user); - } -} - -void LLTexLayerParamAlpha::animate(F32 delta, BOOL set_by_user) -{ - if (mNext) - { - mNext->animate(delta, set_by_user); - } -} - -BOOL LLTexLayerParamAlpha::getSkip() -{ - LLVOAvatar *avatar = mTexLayer->getTexLayerSet()->getAvatar(); - - if( getInfo()->mSkipIfZeroWeight ) - { - F32 effective_weight = ( avatar->getSex() & getSex() ) ? mCurWeight : getDefaultWeight(); - if (is_approx_zero( effective_weight )) - { - return TRUE; - } - } - - EWearableType type = (EWearableType)getWearableType(); - if( (type != WT_INVALID) && !avatar->isWearingWearableType( type ) ) - { - return TRUE; - } - - return FALSE; -} - - -BOOL LLTexLayerParamAlpha::render( S32 x, S32 y, S32 width, S32 height ) -{ - BOOL success = TRUE; - - F32 effective_weight = ( mTexLayer->getTexLayerSet()->getAvatar()->getSex() & getSex() ) ? mCurWeight : getDefaultWeight(); - BOOL weight_changed = effective_weight != mCachedEffectiveWeight; - if( getSkip() ) - { - return success; - } - - gGL.flush(); - if( getInfo()->mMultiplyBlend ) - { - gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function - } - else - { - gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function - } - - if( !getInfo()->mStaticImageFileName.empty() && !mStaticImageInvalid) - { - if( mStaticImageTGA.isNull() ) - { - // Don't load the image file until we actually need it the first time. Like now. - mStaticImageTGA = gTexStaticImageList.getImageTGA( getInfo()->mStaticImageFileName ); - // We now have something in one of our caches - LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull() ? TRUE : FALSE; - - if( mStaticImageTGA.isNull() ) - { - llwarns << "Unable to load static file: " << getInfo()->mStaticImageFileName << llendl; - mStaticImageInvalid = TRUE; // don't try again. - return FALSE; - } - } - - const S32 image_tga_width = mStaticImageTGA->getWidth(); - const S32 image_tga_height = mStaticImageTGA->getHeight(); - if( !mCachedProcessedImageGL || - (mCachedProcessedImageGL->getWidth() != image_tga_width) || - (mCachedProcessedImageGL->getHeight() != image_tga_height) || - (weight_changed) ) - { -// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; - mCachedEffectiveWeight = effective_weight; - - if( !mCachedProcessedImageGL ) - { - mCachedProcessedImageGL = new LLImageGL( image_tga_width, image_tga_height, 1, FALSE); - - // We now have something in one of our caches - LLTexLayerSet::sHasCaches |= mCachedProcessedImageGL ? TRUE : FALSE; - - mCachedProcessedImageGL->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); - } - - // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed. - mStaticImageRaw = NULL; - mStaticImageRaw = new LLImageRaw; - mStaticImageTGA->decodeAndProcess( mStaticImageRaw, getInfo()->mDomain, effective_weight ); - mNeedsCreateTexture = TRUE; - } - - if( mCachedProcessedImageGL ) - { - { - // Create the GL texture, and then hang onto it for future use. - if( mNeedsCreateTexture ) - { - mCachedProcessedImageGL->createGLTexture(0, mStaticImageRaw); - mNeedsCreateTexture = FALSE; - gGL.getTexUnit(0)->bind(mCachedProcessedImageGL); - mCachedProcessedImageGL->setAddressMode(LLTexUnit::TAM_CLAMP); - } - - LLGLSNoAlphaTest gls_no_alpha_test; - gGL.getTexUnit(0)->bind(mCachedProcessedImageGL); - gl_rect_2d_simple_tex( width, height ); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - stop_glerror(); - } - } - - // Don't keep the cache for other people's avatars - // (It's not really a "cache" in that case, but the logic is the same) - if( !mTexLayer->getTexLayerSet()->getAvatar()->isSelf() ) - { - mCachedProcessedImageGL = NULL; - } - } - else - { - LLGLDisable no_alpha(GL_ALPHA_TEST); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.f, 0.f, 0.f, effective_weight ); - gl_rect_2d_simple( width, height ); - } - - return success; -} - -//----------------------------------------------------------------------------- -// LLTexGlobalColorInfo -//----------------------------------------------------------------------------- - -LLTexGlobalColorInfo::LLTexGlobalColorInfo() +LLTexLayerStaticImageList::LLTexLayerStaticImageList() : + mGLBytes(0), + mTGABytes(0), + mImageNames(16384) { } - -LLTexGlobalColorInfo::~LLTexGlobalColorInfo() -{ - for_each(mColorInfoList.begin(), mColorInfoList.end(), DeletePointer()); -} - -BOOL LLTexGlobalColorInfo::parseXml(LLXmlTreeNode* node) -{ - // name attribute - static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name"); - if( !node->getFastAttributeString( name_string, mName ) ) - { - llwarns << " element is missing name attribute." << llendl; - return FALSE; - } - // sub-element - for (LLXmlTreeNode* child = node->getChildByName( "param" ); - child; - child = node->getNextNamedChild()) - { - if( child->getChildByName( "param_color" ) ) - { - // - LLTexParamColorInfo* info = new LLTexParamColorInfo(); - if (!info->parseXml(child)) - { - delete info; - return FALSE; - } - mColorInfoList.push_back( info ); - } - } - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLTexGlobalColor -//----------------------------------------------------------------------------- - -LLTexGlobalColor::LLTexGlobalColor( LLVOAvatar* avatar ) - : - mAvatar( avatar ), - mInfo( NULL ) -{ -} - - -LLTexGlobalColor::~LLTexGlobalColor() -{ - // mParamList are LLViewerVisualParam's and get deleted with ~LLCharacter() - //std::for_each(mParamList.begin(), mParamList.end(), DeletePointer()); -} - -BOOL LLTexGlobalColor::setInfo(LLTexGlobalColorInfo *info) -{ - llassert(mInfo == NULL); - mInfo = info; - //mID = info->mID; // No ID - - LLTexGlobalColorInfo::color_info_list_t::iterator iter; - mParamList.reserve(mInfo->mColorInfoList.size()); - for (iter = mInfo->mColorInfoList.begin(); iter != mInfo->mColorInfoList.end(); iter++) - { - LLTexParamColor* param_color = new LLTexParamColor( this ); - if (!param_color->setInfo(*iter)) - { - mInfo = NULL; - return FALSE; - } - mParamList.push_back( param_color ); - } - - return TRUE; -} - -//----------------------------------------------------------------------------- - -LLColor4 LLTexGlobalColor::getColor() -{ - // Sum of color params - if( !mParamList.empty() ) - { - LLColor4 net_color( 0.f, 0.f, 0.f, 0.f ); - - for( param_list_t::iterator iter = mParamList.begin(); - iter != mParamList.end(); iter++ ) - { - LLTexParamColor* param = *iter; - LLColor4 param_net = param->getNetColor(); - switch( param->getOperation() ) - { - case OP_ADD: - net_color += param_net; - break; - case OP_MULTIPLY: - net_color.mV[VX] *= param_net.mV[VX]; - net_color.mV[VY] *= param_net.mV[VY]; - net_color.mV[VZ] *= param_net.mV[VZ]; - net_color.mV[VW] *= param_net.mV[VW]; - break; - case OP_BLEND: - net_color = lerp(net_color, param_net, param->getWeight()); - break; - default: - llassert(0); - break; - } - } - - net_color.mV[VX] = llclampf( net_color.mV[VX] ); - net_color.mV[VY] = llclampf( net_color.mV[VY] ); - net_color.mV[VZ] = llclampf( net_color.mV[VZ] ); - net_color.mV[VW] = llclampf( net_color.mV[VW] ); - - return net_color; - } - return LLColor4( 1.f, 1.f, 1.f, 1.f ); -} - -//----------------------------------------------------------------------------- -// LLTexParamColorInfo -//----------------------------------------------------------------------------- -LLTexParamColorInfo::LLTexParamColorInfo() - : - mOperation( OP_ADD ), - mNumColors( 0 ) -{ -} - -BOOL LLTexParamColorInfo::parseXml(LLXmlTreeNode *node) -{ - llassert( node->hasName( "param" ) && node->getChildByName( "param_color" ) ); - - if (!LLViewerVisualParamInfo::parseXml(node)) - return FALSE; - - LLXmlTreeNode* param_color_node = node->getChildByName( "param_color" ); - if( !param_color_node ) - { - return FALSE; - } - - std::string op_string; - static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation"); - if( param_color_node->getFastAttributeString( operation_string, op_string ) ) - { - LLStringUtil::toLower(op_string); - if ( op_string == "add" ) mOperation = OP_ADD; - else if ( op_string == "multiply" ) mOperation = OP_MULTIPLY; - else if ( op_string == "blend" ) mOperation = OP_BLEND; - } - - mNumColors = 0; - - LLColor4U color4u; - for (LLXmlTreeNode* child = param_color_node->getChildByName( "value" ); - child; - child = param_color_node->getNextNamedChild()) - { - if( (mNumColors < MAX_COLOR_VALUES) ) - { - static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color"); - if( child->getFastAttributeColor4U( color_string, color4u ) ) - { - mColors[ mNumColors ].setVec(color4u); - mNumColors++; - } - } - } - if( !mNumColors ) - { - llwarns << " is missing sub-elements" << llendl; - return FALSE; - } - - if( (mOperation == OP_BLEND) && (mNumColors != 1) ) - { - llwarns << " with operation\"blend\" must have exactly one " << llendl; - return FALSE; - } - - return TRUE; -} - -//----------------------------------------------------------------------------- -// LLTexParamColor -//----------------------------------------------------------------------------- -LLTexParamColor::LLTexParamColor( LLTexGlobalColor* tex_global_color ) - : - mAvgDistortionVec(1.f, 1.f, 1.f), - mTexGlobalColor( tex_global_color ), - mTexLayer( NULL ), - mAvatar( tex_global_color->getAvatar() ) -{ -} - -LLTexParamColor::LLTexParamColor( LLTexLayer* layer ) - : - mAvgDistortionVec(1.f, 1.f, 1.f), - mTexGlobalColor( NULL ), - mTexLayer( layer ), - mAvatar( layer->getTexLayerSet()->getAvatar() ) -{ -} - - -LLTexParamColor::~LLTexParamColor() -{ -} - -//----------------------------------------------------------------------------- -// setInfo() -//----------------------------------------------------------------------------- - -BOOL LLTexParamColor::setInfo(LLTexParamColorInfo *info) -{ - llassert(mInfo == NULL); - if (info->mID < 0) - return FALSE; - mID = info->mID; - mInfo = info; - - mAvatar->addVisualParam( this ); - setWeight( getDefaultWeight(), FALSE ); - - return TRUE; -} - -LLColor4 LLTexParamColor::getNetColor() -{ - llassert( getInfo()->mNumColors >= 1 ); - - F32 effective_weight = ( mAvatar && (mAvatar->getSex() & getSex()) ) ? mCurWeight : getDefaultWeight(); - - S32 index_last = getInfo()->mNumColors - 1; - F32 scaled_weight = effective_weight * index_last; - S32 index_start = (S32) scaled_weight; - S32 index_end = index_start + 1; - if( index_start == index_last ) - { - return getInfo()->mColors[index_last]; - } - else - { - F32 weight = scaled_weight - index_start; - const LLColor4 *start = &getInfo()->mColors[ index_start ]; - const LLColor4 *end = &getInfo()->mColors[ index_end ]; - return LLColor4( - (1.f - weight) * start->mV[VX] + weight * end->mV[VX], - (1.f - weight) * start->mV[VY] + weight * end->mV[VY], - (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ], - (1.f - weight) * start->mV[VW] + weight * end->mV[VW] ); - } -} - -void LLTexParamColor::setWeight(F32 weight, BOOL set_by_user) -{ - if (mIsAnimating) - { - return; - } - F32 min_weight = getMinWeight(); - F32 max_weight = getMaxWeight(); - F32 new_weight = llclamp(weight, min_weight, max_weight); - U8 cur_u8 = F32_to_U8( mCurWeight, min_weight, max_weight ); - U8 new_u8 = F32_to_U8( new_weight, min_weight, max_weight ); - if( cur_u8 != new_u8) - { - mCurWeight = new_weight; - - if( getInfo()->mNumColors <= 0 ) - { - // This will happen when we set the default weight the first time. - return; - } - - if( mAvatar->getSex() & getSex() ) - { - if( mTexGlobalColor ) - { - mAvatar->onGlobalColorChanged( mTexGlobalColor, set_by_user ); - } - else - if( mTexLayer ) - { - mAvatar->invalidateComposite( mTexLayer->getTexLayerSet(), set_by_user ); - } - } -// llinfos << "param " << mName << " = " << new_weight << llendl; - } -} - -void LLTexParamColor::setAnimationTarget(F32 target_value, BOOL set_by_user) -{ - // set value first then set interpolating flag to ignore further updates - mTargetWeight = target_value; - setWeight(target_value, set_by_user); - mIsAnimating = TRUE; - if (mNext) - { - mNext->setAnimationTarget(target_value, set_by_user); - } -} - -void LLTexParamColor::animate(F32 delta, BOOL set_by_user) -{ - if (mNext) - { - mNext->animate(delta, set_by_user); - } -} - - -//----------------------------------------------------------------------------- -// LLTexStaticImageList -//----------------------------------------------------------------------------- - -// static -LLTexStaticImageList gTexStaticImageList; -LLStringTable LLTexStaticImageList::sImageNames(16384); - -LLTexStaticImageList::LLTexStaticImageList() - : - mGLBytes( 0 ), - mTGABytes( 0 ) -{} - -LLTexStaticImageList::~LLTexStaticImageList() +LLTexLayerStaticImageList::~LLTexLayerStaticImageList() { deleteCachedImages(); } -void LLTexStaticImageList::dumpByteCount() +void LLTexLayerStaticImageList::dumpByteCount() { llinfos << "Avatar Static Textures " << "KB GL:" << (mGLBytes / 1024) << "KB TGA:" << (mTGABytes / 1024) << "KB" << llendl; } -void LLTexStaticImageList::deleteCachedImages() +void LLTexLayerStaticImageList::deleteCachedImages() { if( mGLBytes || mTGABytes ) { @@ -2478,23 +1860,23 @@ void LLTexStaticImageList::deleteCachedImages() //mStaticImageLists uses LLPointers, clear() will cause deletion mStaticImageListTGA.clear(); - mStaticImageListGL.clear(); + mStaticImageList.clear(); mGLBytes = 0; mTGABytes = 0; } } -// Note: in general, for a given image image we'll call either getImageTga() or getImageGL(). +// Note: in general, for a given image image we'll call either getImageTga() or getTexture(). // We call getImageTga() if the image is used as an alpha gradient. -// Otherwise, we call getImageGL() +// Otherwise, we call getTexture() // Returns an LLImageTGA that contains the encoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -LLImageTGA* LLTexStaticImageList::getImageTGA(const std::string& file_name) +LLImageTGA* LLTexLayerStaticImageList::getImageTGA(const std::string& file_name) { - const char *namekey = sImageNames.addString(file_name); - image_tga_map_t::iterator iter = mStaticImageListTGA.find(namekey); + const char *namekey = mImageNames.addString(file_name); + image_tga_map_t::const_iterator iter = mStaticImageListTGA.find(namekey); if( iter != mStaticImageListTGA.end() ) { return iter->second; @@ -2517,23 +1899,21 @@ LLImageTGA* LLTexStaticImageList::getImageTGA(const std::string& file_name) } } - - // Returns a GL Image (without a backing ImageRaw) that contains the decoded data from a tga file named file_name. // Caches the result to speed identical subsequent requests. -LLImageGL* LLTexStaticImageList::getImageGL(const std::string& file_name, BOOL is_mask ) +LLViewerTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_name, BOOL is_mask) { - LLPointer image_gl; - const char *namekey = sImageNames.addString(file_name); + LLPointer tex; + const char *namekey = mImageNames.addString(file_name); - image_gl_map_t::iterator iter = mStaticImageListGL.find(namekey); - if( iter != mStaticImageListGL.end() ) + texture_map_t::const_iterator iter = mStaticImageList.find(namekey); + if( iter != mStaticImageList.end() ) { - image_gl = iter->second; + tex = iter->second; } else { - image_gl = new LLImageGL( FALSE ); + tex = LLViewerTextureManager::getLocalTexture( FALSE ); LLPointer image_raw = new LLImageRaw; if( loadImageRaw( file_name, image_raw ) ) { @@ -2541,28 +1921,28 @@ LLImageGL* LLTexStaticImageList::getImageGL(const std::string& file_name, BOOL i { // Note: these are static, unchanging images so it's ok to assume // that once an image is a mask it's always a mask. - image_gl->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); + tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA ); } - image_gl->createGLTexture(0, image_raw); + tex->createGLTexture(0, image_raw); - gGL.getTexUnit(0)->bind(image_gl); - image_gl->setAddressMode(LLTexUnit::TAM_CLAMP); + gGL.getTexUnit(0)->bind(tex); + tex->setAddressMode(LLTexUnit::TAM_CLAMP); - mStaticImageListGL [ namekey ] = image_gl; - mGLBytes += (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); + mStaticImageList [ namekey ] = tex; + mGLBytes += (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); } else { - image_gl = NULL; + tex = NULL; } } - return image_gl; + return tex; } // Reads a .tga file, decodes it, and puts the decoded data in image_raw. // Returns TRUE if successful. -BOOL LLTexStaticImageList::loadImageRaw( const std::string& file_name, LLImageRaw* image_raw ) +BOOL LLTexLayerStaticImageList::loadImageRaw(const std::string& file_name, LLImageRaw* image_raw) { BOOL success = FALSE; std::string path; @@ -2577,11 +1957,4 @@ BOOL LLTexStaticImageList::loadImageRaw( const std::string& file_name, LLImageRa return success; } -//----------------------------------------------------------------------------- -// LLMaskedMorph() -//----------------------------------------------------------------------------- -LLMaskedMorph::LLMaskedMorph( LLPolyMorphTarget *morph_target, BOOL invert ) : mMorphTarget(morph_target), mInvert(invert) -{ - morph_target->addPendingMorphMask(); -} diff --git a/indra/newview/lltexlayer.h b/indra/newview/lltexlayer.h index 1924d0bee3..b0ac13913e 100644 --- a/indra/newview/lltexlayer.h +++ b/indra/newview/lltexlayer.h @@ -34,136 +34,95 @@ #define LL_LLTEXLAYER_H #include -#include "llassetstorage.h" #include "lldynamictexture.h" -#include "llrect.h" -#include "llstring.h" -#include "lluuid.h" -#include "llviewerimage.h" -#include "llviewervisualparam.h" #include "llwearable.h" -#include "v4color.h" -#include "llfloater.h" +#include "llvoavatardefines.h" -class LLTexLayerSetInfo; -class LLTexLayerSet; -class LLTexLayerInfo; -class LLTexLayer; -class LLImageGL; -class LLImageTGA; -class LLTexGlobalColorInfo; -class LLTexLayerParamAlphaInfo; -class LLTexLayerParamAlpha; -class LLTexParamColorInfo; -class LLTexParamColor; -class LLPolyMesh; -class LLXmlTreeNode; -class LLImageRaw; -class LLPolyMorphTarget; - -class LLTextureCtrl; class LLVOAvatar; +class LLVOAvatarSelf; +class LLImageTGA; +class LLImageRaw; +class LLXmlTreeNode; +class LLPolyMorphTarget; +class LLTexLayerSet; +class LLTexLayerSetInfo; +class LLTexLayerInfo; +class LLTexLayerSetBuffer; +class LLTexLayerParamColor; +class LLTexLayerParamColorInfo; +class LLTexLayerParamAlpha; +class LLTexLayerParamAlphaInfo; -enum EColorOperation -{ - OP_ADD = 0, - OP_MULTIPLY = 1, - OP_BLEND = 2, - OP_COUNT = 3 // Number of operations -}; - +typedef std::vector param_color_list_t; +typedef std::vector param_alpha_list_t; +typedef std::vector param_color_info_list_t; +typedef std::vector param_alpha_info_list_t; //----------------------------------------------------------------------------- -// LLTexLayerParamAlphaInfo -//----------------------------------------------------------------------------- -class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo +// LLTexLayer +// A single texture layer +// Only exists for llvoavatarself + +class LLTexLayer { - friend class LLTexLayerParamAlpha; public: - LLTexLayerParamAlphaInfo(); - /*virtual*/ ~LLTexLayerParamAlphaInfo() {}; + enum ERenderPass + { + RP_COLOR, + RP_BUMP, + RP_SHINE + }; - /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + LLTexLayer(LLTexLayerSet* const layer_set); + LLTexLayer(const LLTexLayer &layer); + ~LLTexLayer(); -protected: - std::string mStaticImageFileName; - BOOL mMultiplyBlend; - BOOL mSkipIfZeroWeight; - F32 mDomain; -}; + const LLTexLayerInfo* getInfo() const { return mInfo; } + BOOL setInfo(const LLTexLayerInfo *info); // This sets mInfo and calls initialization functions + BOOL render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph); + void requestUpdate(); + LLTexLayerSet* const getTexLayerSet() const { return mTexLayerSet; } -//----------------------------------------------------------------------------- -// LLTexParamColorInfo -//----------------------------------------------------------------------------- -class LLTexParamColorInfo : public LLViewerVisualParamInfo -{ - friend class LLTexParamColor; + void deleteCaches(); + U8* getAlphaData(); + void invalidateMorphMasks(); + void setHasMorph(BOOL newval) { mHasMorph = newval; } + BOOL isMorphValid() { return mMorphMasksValid; } -public: - LLTexParamColorInfo(); - virtual ~LLTexParamColorInfo() {}; - BOOL parseXml( LLXmlTreeNode* node ); - -protected: - enum { MAX_COLOR_VALUES = 20 }; - EColorOperation mOperation; - LLColor4 mColors[MAX_COLOR_VALUES]; - S32 mNumColors; -}; + const std::string& getName() const; + ERenderPass getRenderPass() const; + const std::string& getGlobalColor() const; -//----------------------------------------------------------------------------- -// LLTexGlobalColorInfo -//----------------------------------------------------------------------------- -class LLTexGlobalColorInfo -{ - friend class LLTexGlobalColor; -public: - LLTexGlobalColorInfo(); - ~LLTexGlobalColorInfo(); + BOOL findNetColor(LLColor4* color) const; + BOOL renderImageRaw(U8* in_data, S32 in_width, S32 in_height, S32 in_components, S32 width, S32 height, BOOL is_mask); + BOOL blendAlphaTexture(S32 width, S32 height); // Multiplies a single alpha texture against the frame buffer + BOOL renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLColor4 &layer_color, BOOL render_morph); + BOOL hasAlphaParams() const { return !mParamAlphaList.empty(); } + BOOL isVisibilityMask() const; - BOOL parseXml(LLXmlTreeNode* node); + static void calculateTexLayerColor(const param_color_list_t ¶m_list, LLColor4 &net_color); + +private: + LLTexLayerSet* const mTexLayerSet; + + // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order. + param_color_list_t mParamColorList; + // mGlobalColor name stored in mInfo + // mFixedColor value stored in mInfo + param_alpha_list_t mParamAlphaList; -protected: - typedef std::vector color_info_list_t; - color_info_list_t mColorInfoList; - std::string mName; -}; - -//----------------------------------------------------------------------------- -// LLTexLayerSetInfo -// Containes shared layer set data -//----------------------------------------------------------------------------- -class LLTexLayerSetInfo -{ - friend class LLTexLayerSet; -public: - LLTexLayerSetInfo(); - ~LLTexLayerSetInfo(); - - BOOL parseXml(LLXmlTreeNode* node); - -protected: - std::string mBodyRegion; - S32 mWidth; - S32 mHeight; - std::string mStaticAlphaFileName; - BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName) - - typedef std::vector layer_info_list_t; - layer_info_list_t mLayerInfoList; -}; - -//----------------------------------------------------------------------------- -// LLTexLayerInfo -//----------------------------------------------------------------------------- -enum ERenderPass -{ - RP_COLOR, - RP_BUMP, - RP_SHINE + BOOL mMorphMasksValid; + typedef std::map alpha_cache_t; + alpha_cache_t mAlphaCache; + BOOL mStaticImageInvalid; + + BOOL mHasMorph; + + const LLTexLayerInfo *mInfo; }; +// Make private class LLTexLayerInfo { friend class LLTexLayer; @@ -172,12 +131,13 @@ public: ~LLTexLayerInfo(); BOOL parseXml(LLXmlTreeNode* node); + BOOL createVisualParams(LLVOAvatar *avatar); -protected: +private: std::string mName; - BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, - ERenderPass mRenderPass; + BOOL mWriteAllChannels; // Don't use masking. Just write RGBA into buffer, + LLTexLayer::ERenderPass mRenderPass; std::string mGlobalColor; LLColor4 mFixedColor; @@ -185,34 +145,114 @@ protected: S32 mLocalTexture; std::string mStaticImageFileName; BOOL mStaticImageIsMask; - BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask + BOOL mUseLocalTextureAlphaOnly; // Ignore RGB channels from the input texture. Use alpha as a mask + BOOL mIsVisibilityMask; - typedef std::vector > morph_name_list_t; - morph_name_list_t mMorphNameList; - - typedef std::vector color_info_list_t; - color_info_list_t mColorInfoList; - - typedef std::vector alpha_info_list_t; - alpha_info_list_t mAlphaInfoList; - + typedef std::vector< std::pair< std::string,BOOL > > morph_name_list_t; + morph_name_list_t mMorphNameList; + param_color_info_list_t mParamColorInfoList; + param_alpha_info_list_t mParamAlphaInfoList; }; +// +// LLTexLayer //----------------------------------------------------------------------------- -// LLTexLayerSetBuffer + +//----------------------------------------------------------------------------- +// LLTexLayerSet +// An ordered set of texture layers that get composited into a single texture. +// Only exists for llvoavatarself + +class LLTexLayerSet +{ + friend class LLTexLayerSetBuffer; +public: + LLTexLayerSet(LLVOAvatarSelf* const avatar); + ~LLTexLayerSet(); + + const LLTexLayerSetInfo* getInfo() const { return mInfo; } + BOOL setInfo(const LLTexLayerSetInfo *info); // This sets mInfo and calls initialization functions + + BOOL render(S32 x, S32 y, S32 width, S32 height); + BOOL renderBump(S32 x, S32 y, S32 width,S32 height); + + BOOL isBodyRegion(const std::string& region) const; + LLTexLayerSetBuffer* getComposite(); + void requestUpdate(); + void requestUpload(); + void cancelUpload(); + void updateComposite(); + BOOL isLocalTextureDataAvailable() const; + BOOL isLocalTextureDataFinal() const; + void createComposite(); + void destroyComposite(); + void setUpdatesEnabled(BOOL b); + BOOL getUpdatesEnabled() const { return mUpdatesEnabled; } + void deleteCaches(); + void gatherMorphMaskAlpha(U8 *data, S32 width, S32 height); + void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); + void renderAlphaMaskTextures(S32 width, S32 height, bool forceClear = false); + LLTexLayer* findLayerByName(std::string name); + + LLVOAvatarSelf* getAvatar() const { return mAvatar; } + const std::string getBodyRegion() const; + BOOL hasComposite() const { return (mComposite.notNull()); } + void setBump(BOOL b) { mHasBump = b; } + BOOL hasBump() const { return mHasBump; } + LLVOAvatarDefines::EBakedTextureIndex getBakedTexIndex() { return mBakedTexIndex; } + void setBakedTexIndex( LLVOAvatarDefines::EBakedTextureIndex index) { mBakedTexIndex = index; } + +public: + static BOOL sHasCaches; + +private: + typedef std::vector layer_list_t; + layer_list_t mLayerList; + layer_list_t mMaskLayerList; + LLPointer mComposite; + LLVOAvatarSelf* const mAvatar; // Backlink only; don't make this an LLPointer. + BOOL mUpdatesEnabled; + BOOL mHasBump; + + LLVOAvatarDefines::EBakedTextureIndex mBakedTexIndex; + + const LLTexLayerSetInfo *mInfo; +}; + +// Contains shared layer set data +class LLTexLayerSetInfo +{ + friend class LLTexLayerSet; +public: + LLTexLayerSetInfo(); + ~LLTexLayerSetInfo(); + + BOOL parseXml(LLXmlTreeNode* node); + void createVisualParams(LLVOAvatar *avatar); + +private: + std::string mBodyRegion; + S32 mWidth; + S32 mHeight; + std::string mStaticAlphaFileName; + BOOL mClearAlpha; // Set alpha to 1 for this layerset (if there is no mStaticAlphaFileName) + + typedef std::vector layer_info_list_t; + layer_info_list_t mLayerInfoList; +}; + // The composite image that a LLTexLayerSet writes to. Each LLTexLayerSet has one. -//----------------------------------------------------------------------------- -class LLTexLayerSetBuffer : public LLDynamicTexture +class LLTexLayerSetBuffer : public LLViewerDynamicTexture { public: - LLTexLayerSetBuffer( LLTexLayerSet* owner, S32 width, S32 height, BOOL has_bump ); + LLTexLayerSetBuffer(LLTexLayerSet* const owner, S32 width, S32 height, BOOL has_bump); virtual ~LLTexLayerSetBuffer(); virtual void preRender(BOOL clear_depth); virtual void postRender(BOOL success); virtual BOOL render(); BOOL updateImmediate(); - void bindBumpTexture( U32 stage ); + void bindBumpTexture(U32 stage); bool isInitialized(void) const; BOOL needsRender(); void requestUpdate(); @@ -220,342 +260,85 @@ public: void cancelUpload(); BOOL uploadPending() { return mUploadPending; } BOOL render( S32 x, S32 y, S32 width, S32 height ); - void readBackAndUpload(U8* baked_bump_data); - void createBumpTexture() ; + void readBackAndUpload(const U8* baked_bump_data); + void createBumpTexture(); - static void onTextureUploadComplete( const LLUUID& uuid, - void* userdata, - S32 result, LLExtStat ext_status); + static void onTextureUploadComplete(const LLUUID& uuid, + void* userdata, + S32 result, LLExtStat ext_status); static void dumpTotalByteCount(); - virtual void restoreGLTexture() ; - virtual void destroyGLTexture() ; + virtual void restoreGLTexture(); + virtual void destroyGLTexture(); private: - void pushProjection(); - void popProjection(); + void pushProjection() const; + void popProjection() const; private: - BOOL mHasBump ; + const BOOL mHasBump; + LLTexLayerSet* const mTexLayerSet; + BOOL mNeedsUpdate; BOOL mNeedsUpload; BOOL mUploadPending; - LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit) - LLTexLayerSet* mTexLayerSet; - LLPointer mBumpTex; // zero if none + LLUUID mUploadID; // Identifys the current upload process (null if none). Used to avoid overlaps (eg, when the user rapidly makes two changes outside of Face Edit) + LLPointer mBumpTex; // zero if none static S32 sGLByteCount; static S32 sGLBumpByteCount; }; -//----------------------------------------------------------------------------- +// // LLTexLayerSet -// An ordered set of texture layers that get composited into a single texture. //----------------------------------------------------------------------------- -class LLTexLayerSet + +//----------------------------------------------------------------------------- +// LLTexLayerStaticImageList +// + +class LLTexLayerStaticImageList : public LLSingleton { public: - LLTexLayerSet( LLVOAvatar* avatar ); - ~LLTexLayerSet(); + LLTexLayerStaticImageList(); + ~LLTexLayerStaticImageList(); - //BOOL parseData(LLXmlTreeNode* node); - LLTexLayerSetInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerSetInfo *info); - - BOOL render( S32 x, S32 y, S32 width, S32 height ); - BOOL renderBump( S32 x, S32 y, S32 width,S32 height ); - BOOL isBodyRegion( const std::string& region ) { return mInfo->mBodyRegion == region; } - LLTexLayerSetBuffer* getComposite(); - void requestUpdate(); - void requestUpload(); - void cancelUpload(); - LLVOAvatar* getAvatar() { return mAvatar; } - void updateComposite(); - BOOL isLocalTextureDataAvailable(); - BOOL isLocalTextureDataFinal(); - void createComposite(); - void destroyComposite(); - void setUpdatesEnabled( BOOL b ); - BOOL getUpdatesEnabled() { return mUpdatesEnabled; } - void deleteCaches(); - void gatherAlphaMasks(U8 *data, S32 width, S32 height); - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); - const std::string getBodyRegion() { return mInfo->mBodyRegion; } - BOOL hasComposite() { return (mComposite != NULL); } - void setBump( BOOL b ) { mHasBump = b; } - BOOL hasBump() { return mHasBump; } - -public: - static BOOL sHasCaches; - -protected: - typedef std::vector layer_list_t; - layer_list_t mLayerList; - LLTexLayerSetBuffer* mComposite; - // Backlink only; don't make this an LLPointer. - LLVOAvatar* mAvatar; - BOOL mUpdatesEnabled; - BOOL mHasBump; - - LLTexLayerSetInfo *mInfo; -}; - -//----------------------------------------------------------------------------- -// LLMaskedMorph -//----------------------------------------------------------------------------- - -class LLMaskedMorph -{ -public: - LLMaskedMorph( LLPolyMorphTarget *morph_target, BOOL invert ); - -public: - LLPolyMorphTarget *mMorphTarget; - BOOL mInvert; -}; - -//----------------------------------------------------------------------------- -// LLTexLayer -// A single texture layer -//----------------------------------------------------------------------------- -class LLTexLayer -{ -public: - LLTexLayer( LLTexLayerSet* layer_set ); - ~LLTexLayer(); - - //BOOL parseData(LLXmlTreeNode* node); - LLTexLayerInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerInfo *info); - - BOOL render( S32 x, S32 y, S32 width, S32 height ); - void requestUpdate(); - LLTexLayerSet* getTexLayerSet() { return mTexLayerSet; } - - const std::string& getName() { return mInfo->mName; } - - void addMaskedMorph(LLPolyMorphTarget* morph_target, BOOL invert); - void deleteCaches(); - U8* getAlphaData(); - void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components); - - void invalidateMorphMasks(); - ERenderPass getRenderPass() { return mInfo->mRenderPass; } - const std::string& getGlobalColor() { return mInfo->mGlobalColor; } - BOOL findNetColor( LLColor4* color ); - BOOL renderImageRaw( U8* in_data, S32 in_width, S32 in_height, S32 in_components, S32 width, S32 height, BOOL is_mask ); - BOOL renderAlphaMasks( S32 x, S32 y, S32 width, S32 height, LLColor4* colorp ); - BOOL hasAlphaParams() { return (!mParamAlphaList.empty());} - -protected: - LLTexLayerSet* mTexLayerSet; - LLPointer mStaticImageRaw; - - // Layers can have either mParamColorList, mGlobalColor, or mFixedColor. They are looked for in that order. - typedef std::vector color_list_t; - color_list_t mParamColorList; - // mGlobalColor name stored in mInfo - // mFixedColor value stored in mInfo - - typedef std::vector alpha_list_t; - alpha_list_t mParamAlphaList; - - - typedef std::deque morph_list_t; - morph_list_t mMaskedMorphs; - typedef std::map alpha_cache_t; - alpha_cache_t mAlphaCache; - BOOL mMorphMasksValid; - BOOL mStaticImageInvalid; - - LLTexLayerInfo *mInfo; -}; - -//----------------------------------------------------------------------------- -// LLTexLayerParamAlpha -//----------------------------------------------------------------------------- -class LLTexLayerParamAlpha : public LLViewerVisualParam -{ -public: - LLTexLayerParamAlpha( LLTexLayer* layer ); - /*virtual*/ ~LLTexLayerParamAlpha(); - - // Special: These functions are overridden by child classes - LLTexLayerParamAlphaInfo* getInfo() const { return (LLTexLayerParamAlphaInfo*)mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexLayerParamAlphaInfo *info); - - // LLVisualParam Virtual functions - ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); - /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); - /*virtual*/ void animate(F32 delta, BOOL set_by_user); - - // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f);} - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; - - // New functions - BOOL render( S32 x, S32 y, S32 width, S32 height ); - BOOL getSkip(); - void deleteCaches(); - LLTexLayer* getTexLayer() { return mTexLayer; } - BOOL getMultiplyBlend() { return getInfo()->mMultiplyBlend; } - -protected: - LLPointer mCachedProcessedImageGL; - LLTexLayer* mTexLayer; - LLPointer mStaticImageTGA; - LLPointer mStaticImageRaw; - BOOL mNeedsCreateTexture; - BOOL mStaticImageInvalid; - LLVector3 mAvgDistortionVec; - F32 mCachedEffectiveWeight; - -public: - // Global list of instances for gathering statistics - static void dumpCacheByteCount(); - static void getCacheByteCount( S32* gl_bytes ); - - typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; - static param_alpha_ptr_list_t sInstances; -}; - - -//----------------------------------------------------------------------------- -// LLTexGlobalColor -//----------------------------------------------------------------------------- -class LLTexGlobalColor -{ -public: - LLTexGlobalColor( LLVOAvatar* avatar ); - ~LLTexGlobalColor(); - - //BOOL parseData(LLXmlTreeNode* node); - LLTexGlobalColorInfo* getInfo() const { return mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexGlobalColorInfo *info); - - void requstUpdate(); - LLVOAvatar* getAvatar() { return mAvatar; } - LLColor4 getColor(); - const std::string& getName() { return mInfo->mName; } - -protected: - typedef std::vector param_list_t; - param_list_t mParamList; - LLVOAvatar* mAvatar; // just backlink, don't LLPointer - - LLTexGlobalColorInfo *mInfo; -}; - - -//----------------------------------------------------------------------------- -// LLTexParamColor -//----------------------------------------------------------------------------- -class LLTexParamColor : public LLViewerVisualParam -{ -public: - LLTexParamColor( LLTexGlobalColor* tex_color ); - LLTexParamColor( LLTexLayer* layer ); - /* virtual */ ~LLTexParamColor(); - - // Special: These functions are overridden by child classes - LLTexParamColorInfo* getInfo() const { return (LLTexParamColorInfo*)mInfo; } - // This sets mInfo and calls initialization functions - BOOL setInfo(LLTexParamColorInfo *info); - - // LLVisualParam Virtual functions - ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); - /*virtual*/ void apply( ESex avatar_sex ) {} - /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); - /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); - /*virtual*/ void animate(F32 delta, BOOL set_by_user); - - - // LLViewerVisualParam Virtual functions - /*virtual*/ F32 getTotalDistortion() { return 1.f; } - /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } - /*virtual*/ F32 getMaxDistortion() { return 3.f; } - /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f); } - /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; - /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; - - // New functions - LLColor4 getNetColor(); - EColorOperation getOperation() const { return getInfo()->mOperation; } - - -protected: - LLVector3 mAvgDistortionVec; - LLTexGlobalColor* mTexGlobalColor; // either has mTexGlobalColor or mTexLayer as its parent - LLTexLayer* mTexLayer; - LLVOAvatar* mAvatar; // redundant, but simplifies the code (don't LLPointer) -}; - -//----------------------------------------------------------------------------- -// LLTexStaticImageList -//----------------------------------------------------------------------------- - -class LLTexStaticImageList -{ -public: - LLTexStaticImageList(); - ~LLTexStaticImageList(); - - LLImageRaw* getImageRaw( const std::string& file_name ); - LLImageGL* getImageGL( const std::string& file_name, BOOL is_mask ); - LLImageTGA* getImageTGA( const std::string& file_name ); + LLViewerTexture* getTexture(const std::string& file_name, BOOL is_mask); + LLImageTGA* getImageTGA(const std::string& file_name); void deleteCachedImages(); void dumpByteCount(); private: - BOOL loadImageRaw( const std::string& file_name, LLImageRaw* image_raw ); + BOOL loadImageRaw(const std::string& file_name, LLImageRaw* image_raw); private: - static LLStringTable sImageNames; + LLStringTable mImageNames; - typedef std::map< const char *, LLPointer > image_gl_map_t; - typedef std::map< const char *, LLPointer > image_tga_map_t; - image_gl_map_t mStaticImageListGL; + typedef std::map< const char*, LLPointer > texture_map_t; + texture_map_t mStaticImageList; + typedef std::map< const char*, LLPointer > image_tga_map_t; image_tga_map_t mStaticImageListTGA; -public: S32 mGLBytes; S32 mTGABytes; }; // Used by LLTexLayerSetBuffer for a callback. - -// For DEV-DEV-31590, "Heap corruption and crash after outfit -// changes", added the mLayerSet member. The current -// LLTexLayerSetBuffer can be found by querying mLayerSet->mComposite, -// but we still store the original mLayerSetBuffer here so we can -// detect when an upload is out of date. This prevents a memory -// stomp. See LLTexLayerSetBuffer::onTextureUploadComplete() for usage. +// Note to anyone merging branches - this supercedes the previous fix +// for DEV-31590 "Heap corruption and crash after outfit changes", +// here and in lltexlayer.cpp. Equally correct and a bit simpler. class LLBakedUploadData { public: - LLBakedUploadData( LLVOAvatar* avatar, LLTexLayerSet* layerset, LLTexLayerSetBuffer* layerset_buffer, const LLUUID & id); + LLBakedUploadData(const LLVOAvatarSelf* avatar, LLTexLayerSet* layerset, const LLUUID& id); ~LLBakedUploadData() {} - LLUUID mID; - LLVOAvatar* mAvatar; // just backlink, don't LLPointer - LLTexLayerSet* mLayerSet; - LLTexLayerSetBuffer* mLayerSetBuffer; - LLUUID mWearableAssets[WT_COUNT]; - U64 mStartTime; // Used to measure time baked texture upload requires + const LLUUID mID; + const LLVOAvatarSelf* mAvatar; // just backlink, don't LLPointer + LLTexLayerSet* mTexLayerSet; + const U64 mStartTime; // Used to measure time baked texture upload requires }; -extern LLTexStaticImageList gTexStaticImageList; - #endif // LL_LLTEXLAYER_H diff --git a/indra/newview/lltexlayerparams.cpp b/indra/newview/lltexlayerparams.cpp new file mode 100644 index 0000000000..c9117a84a5 --- /dev/null +++ b/indra/newview/lltexlayerparams.cpp @@ -0,0 +1,541 @@ +/** + * @file lltexlayerparams.cpp + * @brief SERAPH - ADD IN + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "llagent.h" +#include "lltexlayer.h" +#include "llvoavatarself.h" +#include "lltexlayerparams.h" +#include "llui.h" + +//----------------------------------------------------------------------------- +// LLTexLayerParam +//----------------------------------------------------------------------------- +LLTexLayerParam::LLTexLayerParam(LLTexLayer *layer) : + mTexLayer(layer), + mAvatar(NULL) +{ + if (mTexLayer != NULL) + { + mAvatar = mTexLayer->getTexLayerSet()->getAvatar(); + } +} + +LLTexLayerParam::LLTexLayerParam(LLVOAvatar *avatar) : + mTexLayer(NULL) +{ + mAvatar = avatar; +} + + +BOOL LLTexLayerParam::setInfo(LLViewerVisualParamInfo *info) +{ + LLViewerVisualParam::setInfo(info); + mAvatar->addVisualParam( this); + return TRUE; +} + + + +//----------------------------------------------------------------------------- +// LLTexLayerParamAlpha +//----------------------------------------------------------------------------- + +// static +LLTexLayerParamAlpha::param_alpha_ptr_list_t LLTexLayerParamAlpha::sInstances; + +// static +void LLTexLayerParamAlpha::dumpCacheByteCount() +{ + S32 gl_bytes = 0; + getCacheByteCount( &gl_bytes); + llinfos << "Processed Alpha Texture Cache GL:" << (gl_bytes/1024) << "KB" << llendl; +} + +// static +void LLTexLayerParamAlpha::getCacheByteCount(S32* gl_bytes) +{ + *gl_bytes = 0; + + for (param_alpha_ptr_list_t::iterator iter = sInstances.begin(); + iter != sInstances.end(); iter++) + { + LLTexLayerParamAlpha* instance = *iter; + LLViewerTexture* tex = instance->mCachedProcessedTexture; + if (tex) + { + S32 bytes = (S32)tex->getWidth() * tex->getHeight() * tex->getComponents(); + + if (tex->hasValidGLTexture()) + { + *gl_bytes += bytes; + } + } + } +} + +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLTexLayer* layer) : + LLTexLayerParam(layer), + mCachedProcessedTexture(NULL), + mNeedsCreateTexture(FALSE), + mStaticImageInvalid(FALSE), + mAvgDistortionVec(1.f, 1.f, 1.f), + mCachedEffectiveWeight(0.f) +{ + sInstances.push_front(this); +} + +LLTexLayerParamAlpha::LLTexLayerParamAlpha(LLVOAvatar* avatar) : + LLTexLayerParam(avatar), + mCachedProcessedTexture(NULL), + mNeedsCreateTexture(FALSE), + mStaticImageInvalid(FALSE), + mAvgDistortionVec(1.f, 1.f, 1.f), + mCachedEffectiveWeight(0.f) +{ + sInstances.push_front(this); +} + + +LLTexLayerParamAlpha::~LLTexLayerParamAlpha() +{ + deleteCaches(); + sInstances.remove(this); +} + +void LLTexLayerParamAlpha::deleteCaches() +{ + mStaticImageTGA = NULL; // deletes image + mCachedProcessedTexture = NULL; + mStaticImageRaw = NULL; + mNeedsCreateTexture = FALSE; +} + +BOOL LLTexLayerParamAlpha::getMultiplyBlend() const +{ + return ((LLTexLayerParamAlphaInfo *)getInfo())->mMultiplyBlend; +} + +void LLTexLayerParamAlpha::setWeight(F32 weight, BOOL set_by_user) +{ + if (mIsAnimating || mTexLayer == NULL) + { + return; + } + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + F32 new_weight = llclamp(weight, min_weight, max_weight); + U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight); + U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight); + if (cur_u8 != new_u8) + { + mCurWeight = new_weight; + + LLVOAvatar* avatar = mTexLayer->getTexLayerSet()->getAvatar(); + if (avatar->getSex() & getSex()) + { + if (gAgent.cameraCustomizeAvatar()) + { + set_by_user = FALSE; + } + avatar->invalidateComposite(mTexLayer->getTexLayerSet(), set_by_user); + mTexLayer->invalidateMorphMasks(); + avatar->updateMeshTextures(); + } + } +} + +void LLTexLayerParamAlpha::setAnimationTarget(F32 target_value, BOOL set_by_user) +{ + mTargetWeight = target_value; + setWeight(target_value, set_by_user); + mIsAnimating = TRUE; + if (mNext) + { + mNext->setAnimationTarget(target_value, set_by_user); + } +} + +void LLTexLayerParamAlpha::animate(F32 delta, BOOL set_by_user) +{ + if (mNext) + { + mNext->animate(delta, set_by_user); + } +} + +BOOL LLTexLayerParamAlpha::getSkip() const +{ + if (!mTexLayer) + { + return TRUE; + } + + const LLVOAvatar *avatar = mTexLayer->getTexLayerSet()->getAvatar(); + + if (((LLTexLayerParamAlphaInfo *)getInfo())->mSkipIfZeroWeight) + { + F32 effective_weight = (avatar->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); + if (is_approx_zero(effective_weight)) + { + return TRUE; + } + } + + EWearableType type = (EWearableType)getWearableType(); + if ((type != WT_INVALID) && !avatar->isWearingWearableType(type)) + { + return TRUE; + } + + return FALSE; +} + + +BOOL LLTexLayerParamAlpha::render(S32 x, S32 y, S32 width, S32 height) +{ + BOOL success = TRUE; + + if (!mTexLayer) + { + return success; + } + + F32 effective_weight = (mTexLayer->getTexLayerSet()->getAvatar()->getSex() & getSex()) ? mCurWeight : getDefaultWeight(); + BOOL weight_changed = effective_weight != mCachedEffectiveWeight; + if (getSkip()) + { + return success; + } + + LLTexLayerParamAlphaInfo *info = (LLTexLayerParamAlphaInfo *)getInfo(); + gGL.flush(); + if (info->mMultiplyBlend) + { + gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); // Multiplication: approximates a min() function + } + else + { + gGL.setSceneBlendType(LLRender::BT_ADD); // Addition: approximates a max() function + } + + if (!info->mStaticImageFileName.empty() && !mStaticImageInvalid) + { + if (mStaticImageTGA.isNull()) + { + // Don't load the image file until we actually need it the first time. Like now. + mStaticImageTGA = LLTexLayerStaticImageList::getInstance()->getImageTGA(info->mStaticImageFileName); + // We now have something in one of our caches + LLTexLayerSet::sHasCaches |= mStaticImageTGA.notNull() ? TRUE : FALSE; + + if (mStaticImageTGA.isNull()) + { + llwarns << "Unable to load static file: " << info->mStaticImageFileName << llendl; + mStaticImageInvalid = TRUE; // don't try again. + return FALSE; + } + } + + const S32 image_tga_width = mStaticImageTGA->getWidth(); + const S32 image_tga_height = mStaticImageTGA->getHeight(); + if (!mCachedProcessedTexture || + (mCachedProcessedTexture->getWidth() != image_tga_width) || + (mCachedProcessedTexture->getHeight() != image_tga_height) || + (weight_changed)) + { +// llinfos << "Building Cached Alpha: " << mName << ": (" << mStaticImageRaw->getWidth() << ", " << mStaticImageRaw->getHeight() << ") " << effective_weight << llendl; + mCachedEffectiveWeight = effective_weight; + + if (!mCachedProcessedTexture) + { + mCachedProcessedTexture = LLViewerTextureManager::getLocalTexture(image_tga_width, image_tga_height, 1, FALSE); + + // We now have something in one of our caches + LLTexLayerSet::sHasCaches |= mCachedProcessedTexture ? TRUE : FALSE; + + mCachedProcessedTexture->setExplicitFormat(GL_ALPHA8, GL_ALPHA); + } + + // Applies domain and effective weight to data as it is decoded. Also resizes the raw image if needed. + mStaticImageRaw = NULL; + mStaticImageRaw = new LLImageRaw; + mStaticImageTGA->decodeAndProcess(mStaticImageRaw, info->mDomain, effective_weight); + mNeedsCreateTexture = TRUE; + } + + if (mCachedProcessedTexture) + { + { + // Create the GL texture, and then hang onto it for future use. + if (mNeedsCreateTexture) + { + mCachedProcessedTexture->createGLTexture(0, mStaticImageRaw); + mNeedsCreateTexture = FALSE; + gGL.getTexUnit(0)->bind(mCachedProcessedTexture); + mCachedProcessedTexture->setAddressMode(LLTexUnit::TAM_CLAMP); + } + + LLGLSNoAlphaTest gls_no_alpha_test; + gGL.getTexUnit(0)->bind(mCachedProcessedTexture); + gl_rect_2d_simple_tex(width, height); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + stop_glerror(); + } + } + + // Don't keep the cache for other people's avatars + // (It's not really a "cache" in that case, but the logic is the same) + if (mAvatar->isSelf()) + { + mCachedProcessedTexture = NULL; + } + } + else + { + LLGLDisable no_alpha(GL_ALPHA_TEST); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + gGL.color4f(0.f, 0.f, 0.f, effective_weight); + gl_rect_2d_simple(width, height); + } + + return success; +} + +//----------------------------------------------------------------------------- +// LLTexLayerParamAlphaInfo +//----------------------------------------------------------------------------- +LLTexLayerParamAlphaInfo::LLTexLayerParamAlphaInfo() : + mMultiplyBlend(FALSE), + mSkipIfZeroWeight(FALSE), + mDomain(0.f) +{ +} + +BOOL LLTexLayerParamAlphaInfo::parseXml(LLXmlTreeNode* node) +{ + llassert(node->hasName("param") && node->getChildByName("param_alpha")); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + LLXmlTreeNode* param_alpha_node = node->getChildByName("param_alpha"); + if (!param_alpha_node) + { + return FALSE; + } + + static LLStdStringHandle tga_file_string = LLXmlTree::addAttributeString("tga_file"); + if (param_alpha_node->getFastAttributeString(tga_file_string, mStaticImageFileName)) + { + // Don't load the image file until it's actually needed. + } +// else +// { +// llwarns << " element is missing tga_file attribute." << llendl; +// } + + static LLStdStringHandle multiply_blend_string = LLXmlTree::addAttributeString("multiply_blend"); + param_alpha_node->getFastAttributeBOOL(multiply_blend_string, mMultiplyBlend); + + static LLStdStringHandle skip_if_zero_string = LLXmlTree::addAttributeString("skip_if_zero"); + param_alpha_node->getFastAttributeBOOL(skip_if_zero_string, mSkipIfZeroWeight); + + static LLStdStringHandle domain_string = LLXmlTree::addAttributeString("domain"); + param_alpha_node->getFastAttributeF32(domain_string, mDomain); + + return TRUE; +} + + + + +LLTexLayerParamColor::LLTexLayerParamColor(LLTexLayer* layer) : + LLTexLayerParam(layer), + mAvgDistortionVec(1.f, 1.f, 1.f) +{ +} + +LLTexLayerParamColor::LLTexLayerParamColor(LLVOAvatar *avatar) : + LLTexLayerParam(avatar), + mAvgDistortionVec(1.f, 1.f, 1.f) +{ +} + +LLTexLayerParamColor::~LLTexLayerParamColor() +{ +} + +LLColor4 LLTexLayerParamColor::getNetColor() const +{ + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + + llassert(info->mNumColors >= 1); + + F32 effective_weight = (mAvatar && (mAvatar->getSex() & getSex())) ? mCurWeight : getDefaultWeight(); + + S32 index_last = info->mNumColors - 1; + F32 scaled_weight = effective_weight * index_last; + S32 index_start = (S32) scaled_weight; + S32 index_end = index_start + 1; + if (index_start == index_last) + { + return info->mColors[index_last]; + } + else + { + F32 weight = scaled_weight - index_start; + const LLColor4 *start = &info->mColors[ index_start ]; + const LLColor4 *end = &info->mColors[ index_end ]; + return LLColor4((1.f - weight) * start->mV[VX] + weight * end->mV[VX], + (1.f - weight) * start->mV[VY] + weight * end->mV[VY], + (1.f - weight) * start->mV[VZ] + weight * end->mV[VZ], + (1.f - weight) * start->mV[VW] + weight * end->mV[VW]); + } +} + +void LLTexLayerParamColor::setWeight(F32 weight, BOOL set_by_user) +{ + if (mIsAnimating) + { + return; + } + + const LLTexLayerParamColorInfo *info = (LLTexLayerParamColorInfo *)getInfo(); + F32 min_weight = getMinWeight(); + F32 max_weight = getMaxWeight(); + F32 new_weight = llclamp(weight, min_weight, max_weight); + U8 cur_u8 = F32_to_U8(mCurWeight, min_weight, max_weight); + U8 new_u8 = F32_to_U8(new_weight, min_weight, max_weight); + if (cur_u8 != new_u8) + { + mCurWeight = new_weight; + + if (info->mNumColors <= 0) + { + // This will happen when we set the default weight the first time. + return; + } + + if (mAvatar->getSex() & getSex()) + { + onGlobalColorChanged(set_by_user); + if (mTexLayer) + { + mAvatar->invalidateComposite(mTexLayer->getTexLayerSet(), set_by_user); + } + } +// llinfos << "param " << mName << " = " << new_weight << llendl; + } +} + +void LLTexLayerParamColor::setAnimationTarget(F32 target_value, BOOL set_by_user) +{ + // set value first then set interpolating flag to ignore further updates + mTargetWeight = target_value; + setWeight(target_value, set_by_user); + mIsAnimating = TRUE; + if (mNext) + { + mNext->setAnimationTarget(target_value, set_by_user); + } +} + +void LLTexLayerParamColor::animate(F32 delta, BOOL set_by_user) +{ + if (mNext) + { + mNext->animate(delta, set_by_user); + } +} + +//----------------------------------------------------------------------------- +// LLTexLayerParamColorInfo +//----------------------------------------------------------------------------- +LLTexLayerParamColorInfo::LLTexLayerParamColorInfo() : + mOperation(LLTexLayerParamColor::OP_ADD), + mNumColors(0) +{ +} + +BOOL LLTexLayerParamColorInfo::parseXml(LLXmlTreeNode *node) +{ + llassert(node->hasName("param") && node->getChildByName("param_color")); + + if (!LLViewerVisualParamInfo::parseXml(node)) + return FALSE; + + LLXmlTreeNode* param_color_node = node->getChildByName("param_color"); + if (!param_color_node) + { + return FALSE; + } + + std::string op_string; + static LLStdStringHandle operation_string = LLXmlTree::addAttributeString("operation"); + if (param_color_node->getFastAttributeString(operation_string, op_string)) + { + LLStringUtil::toLower(op_string); + if (op_string == "add") mOperation = LLTexLayerParamColor::OP_ADD; + else if (op_string == "multiply") mOperation = LLTexLayerParamColor::OP_MULTIPLY; + else if (op_string == "blend") mOperation = LLTexLayerParamColor::OP_BLEND; + } + + mNumColors = 0; + + LLColor4U color4u; + for (LLXmlTreeNode* child = param_color_node->getChildByName("value"); + child; + child = param_color_node->getNextNamedChild()) + { + if ((mNumColors < MAX_COLOR_VALUES)) + { + static LLStdStringHandle color_string = LLXmlTree::addAttributeString("color"); + if (child->getFastAttributeColor4U(color_string, color4u)) + { + mColors[ mNumColors ].setVec(color4u); + mNumColors++; + } + } + } + if (!mNumColors) + { + llwarns << " is missing sub-elements" << llendl; + return FALSE; + } + + if ((mOperation == LLTexLayerParamColor::OP_BLEND) && (mNumColors != 1)) + { + llwarns << " with operation\"blend\" must have exactly one " << llendl; + return FALSE; + } + + return TRUE; +} diff --git a/indra/newview/lltexlayerparams.h b/indra/newview/lltexlayerparams.h new file mode 100644 index 0000000000..49feb01b5e --- /dev/null +++ b/indra/newview/lltexlayerparams.h @@ -0,0 +1,180 @@ +/** + * @file lltexlayerparams.h + * @brief Texture layer parameters, used by lltexlayer. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + * + * Copyright (c) 2002-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTEXLAYERPARAMS_H +#define LL_LLTEXLAYERPARAMS_H + +#include "llviewervisualparam.h" + +class LLTexLayer; +class LLVOAvatar; + +class LLTexLayerParam : public LLViewerVisualParam +{ +public: + LLTexLayerParam(LLTexLayer *layer); + LLTexLayerParam(LLVOAvatar *avatar); + /* Virtual */ BOOL setInfo(LLViewerVisualParamInfo *info); +protected: + LLTexLayer* mTexLayer; + LLVOAvatar* mAvatar; +}; + +//----------------------------------------------------------------------------- +// LLTexLayerParamAlpha +// +class LLTexLayerParamAlpha : public LLTexLayerParam +{ +public: + LLTexLayerParamAlpha( LLTexLayer* layer ); + LLTexLayerParamAlpha( LLVOAvatar* avatar ); + /*virtual*/ ~LLTexLayerParamAlpha(); + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); + /*virtual*/ void animate(F32 delta, BOOL set_by_user); + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f);} + /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + BOOL render( S32 x, S32 y, S32 width, S32 height ); + BOOL getSkip() const; + void deleteCaches(); + BOOL getMultiplyBlend() const; + +private: + LLPointer mCachedProcessedTexture; + LLPointer mStaticImageTGA; + LLPointer mStaticImageRaw; + BOOL mNeedsCreateTexture; + BOOL mStaticImageInvalid; + LLVector3 mAvgDistortionVec; + F32 mCachedEffectiveWeight; + +public: + // Global list of instances for gathering statistics + static void dumpCacheByteCount(); + static void getCacheByteCount( S32* gl_bytes ); + + typedef std::list< LLTexLayerParamAlpha* > param_alpha_ptr_list_t; + static param_alpha_ptr_list_t sInstances; +}; +class LLTexLayerParamAlphaInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamAlpha; +public: + LLTexLayerParamAlphaInfo(); + /*virtual*/ ~LLTexLayerParamAlphaInfo() {}; + + /*virtual*/ BOOL parseXml(LLXmlTreeNode* node); + +private: + std::string mStaticImageFileName; + BOOL mMultiplyBlend; + BOOL mSkipIfZeroWeight; + F32 mDomain; +}; +// +// LLTexLayerParamAlpha +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// LLTexLayerParamColor +// +class LLTexLayerParamColor : public LLTexLayerParam +{ +public: + enum EColorOperation + { + OP_ADD = 0, + OP_MULTIPLY = 1, + OP_BLEND = 2, + OP_COUNT = 3 // Number of operations + }; + + LLTexLayerParamColor( LLTexLayer* layer ); + LLTexLayerParamColor( LLVOAvatar* avatar ); + /* virtual */ ~LLTexLayerParamColor(); + + // LLVisualParam Virtual functions + ///*virtual*/ BOOL parseData(LLXmlTreeNode* node); + /*virtual*/ void apply( ESex avatar_sex ) {} + /*virtual*/ void setWeight(F32 weight, BOOL set_by_user); + /*virtual*/ void setAnimationTarget(F32 target_value, BOOL set_by_user); + /*virtual*/ void animate(F32 delta, BOOL set_by_user); + + + // LLViewerVisualParam Virtual functions + /*virtual*/ F32 getTotalDistortion() { return 1.f; } + /*virtual*/ const LLVector3& getAvgDistortion() { return mAvgDistortionVec; } + /*virtual*/ F32 getMaxDistortion() { return 3.f; } + /*virtual*/ LLVector3 getVertexDistortion(S32 index, LLPolyMesh *poly_mesh) { return LLVector3(1.f, 1.f, 1.f); } + /*virtual*/ const LLVector3* getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return &mAvgDistortionVec;}; + /*virtual*/ const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **poly_mesh) { index = 0; poly_mesh = NULL; return NULL;}; + + // New functions + LLColor4 getNetColor() const; +protected: + virtual void onGlobalColorChanged(bool set_by_user) {} +private: + LLVector3 mAvgDistortionVec; +}; + +class LLTexLayerParamColorInfo : public LLViewerVisualParamInfo +{ + friend class LLTexLayerParamColor; + +public: + LLTexLayerParamColorInfo(); + virtual ~LLTexLayerParamColorInfo() {}; + BOOL parseXml( LLXmlTreeNode* node ); + LLTexLayerParamColor::EColorOperation getOperation() const { return mOperation; } +private: + enum { MAX_COLOR_VALUES = 20 }; + LLTexLayerParamColor::EColorOperation mOperation; + LLColor4 mColors[MAX_COLOR_VALUES]; + S32 mNumColors; +}; + +// +// LLTexLayerParamColor +//----------------------------------------------------------------------------- + +#endif diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index a3966ed666..1b249d75d1 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -946,7 +946,7 @@ std::string LLTextureCache::getLocalFileName(const LLUUID& id) // Does not include extension std::string idstr = id.asString(); // TODO: should we be storing cached textures in skin directory? - std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "default", "textures", idstr); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_LOCAL_ASSETS, idstr); return filename; } diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index dc34c5ad37..1b47fa43c7 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -37,17 +37,18 @@ #include "llrender.h" #include "llagent.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llcheckboxctrl.h" #include "llcombobox.h" #include "llbutton.h" #include "lldraghandle.h" #include "llfocusmgr.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llfolderview.h" +#include "llfoldervieweventlistener.h" #include "llinventory.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "lllineeditor.h" #include "llui.h" #include "llviewerinventory.h" @@ -59,6 +60,7 @@ #include "llscrollcontainer.h" #include "lltoolmgr.h" #include "lltoolpipette.h" +#include "llfiltereditor.h" #include "lltool.h" #include "llviewerwindow.h" @@ -69,26 +71,9 @@ #include "lltrans.h" -static const S32 CLOSE_BTN_WIDTH = 100; -const S32 PIPETTE_BTN_WIDTH = 32; static const S32 HPAD = 4; static const S32 VPAD = 4; static const S32 LINE = 16; -static const S32 SMALL_BTN_WIDTH = 64; -static const S32 TEX_PICKER_MIN_WIDTH = - (HPAD + - CLOSE_BTN_WIDTH + - HPAD + - CLOSE_BTN_WIDTH + - HPAD + - SMALL_BTN_WIDTH + - HPAD + - SMALL_BTN_WIDTH + - HPAD + - 30 + - RESIZE_HANDLE_WIDTH * 2); -static const S32 CLEAR_BTN_WIDTH = 50; -static const S32 TEX_PICKER_MIN_HEIGHT = 290; static const S32 FOOTER_HEIGHT = 100; static const S32 BORDER_PAD = HPAD; static const S32 TEXTURE_INVENTORY_PADDING = 30; @@ -108,7 +93,6 @@ class LLFloaterTexturePicker : public LLFloater public: LLFloaterTexturePicker( LLTextureCtrl* owner, - const LLRect& rect, const std::string& label, PermissionMask immediate_filter_perm_mask, PermissionMask non_immediate_filter_perm_mask, @@ -126,7 +110,6 @@ public: virtual BOOL handleKeyHere(KEY key, MASK mask); // LLFloater overrides - virtual void onClose(bool app_quitting); virtual BOOL postBuild(); // New functions @@ -136,8 +119,6 @@ public: const LLUUID& findItemID(const LLUUID& asset_id, BOOL copyable_only); void setCanApplyImmediately(BOOL b); - void setDirty( BOOL b ) { mIsDirty = b; } - BOOL isDirty() const { return mIsDirty; } void setActive( BOOL active ); LLTextureCtrl* getOwner() const { return mOwner; } @@ -147,23 +128,25 @@ public: PermissionMask getFilterPermMask(); void updateFilterPermMask(); void commitIfImmediateSet(); - + + void onFilterEdit(const std::string& search_string ); + void onClose(); + static void onBtnSetToDefault( void* userdata ); static void onBtnSelect( void* userdata ); static void onBtnCancel( void* userdata ); - static void onBtnPipette( void* userdata ); + void onBtnPipette( ); //static void onBtnRevert( void* userdata ); static void onBtnWhite( void* userdata ); static void onBtnNone( void* userdata ); static void onBtnClear( void* userdata ); - static void onSelectionChange(const std::deque &items, BOOL user_action, void* data); + void onSelectionChange(const std::deque &items, BOOL user_action); static void onShowFolders(LLUICtrl* ctrl, void* userdata); static void onApplyImmediateCheck(LLUICtrl* ctrl, void* userdata); - static void onSearchEdit(const std::string& search_string, void* user_data ); - static void onTextureSelect( const LLTextureEntry& te, void *data ); + void onTextureSelect( const LLTextureEntry& te ); protected: - LLPointer mTexturep; + LLPointer mTexturep; LLTextureCtrl* mOwner; LLUUID mImageAssetID; // Currently selected texture @@ -179,10 +162,9 @@ protected: LLTextBox* mResolutionLabel; std::string mPendingName; - BOOL mIsDirty; BOOL mActive; - LLSearchEditor* mSearchEdit; + LLFilterEditor* mFilterEdit; LLInventoryPanel* mInventoryPanel; PermissionMask mImmediateFilterPermMask; PermissionMask mNonImmediateFilterPermMask; @@ -194,18 +176,12 @@ protected: LLFloaterTexturePicker::LLFloaterTexturePicker( LLTextureCtrl* owner, - const LLRect& rect, const std::string& label, PermissionMask immediate_filter_perm_mask, PermissionMask non_immediate_filter_perm_mask, BOOL can_apply_immediately, const std::string& fallback_image_name) - : - LLFloater( std::string("texture picker"), - rect, - std::string( "Pick: " ) + label, - TRUE, - TEX_PICKER_MIN_WIDTH, TEX_PICKER_MIN_HEIGHT ), +: LLFloater(LLSD()), mOwner( owner ), mImageAssetID( owner->getImageAssetID() ), mFallbackImageName( fallback_image_name ), @@ -214,78 +190,15 @@ LLFloaterTexturePicker::LLFloaterTexturePicker( mLabel(label), mTentativeLabel(NULL), mResolutionLabel(NULL), - mIsDirty( FALSE ), mActive( TRUE ), - mSearchEdit(NULL), + mFilterEdit(NULL), mImmediateFilterPermMask(immediate_filter_perm_mask), mNonImmediateFilterPermMask(non_immediate_filter_perm_mask), mContextConeOpacity(0.f) { - LLUICtrlFactory::getInstance()->buildFloater(this,"floater_texture_ctrl.xml"); - - mTentativeLabel = getChild("Multiple"); - - mResolutionLabel = getChild("unknown"); - - - childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this); - childSetAction("None", LLFloaterTexturePicker::onBtnNone,this); - childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this); - - - childSetCommitCallback("show_folders_check", onShowFolders, this); - childSetVisible("show_folders_check", FALSE); - - mSearchEdit = getChild("inventory search editor"); - mSearchEdit->setSearchCallback(onSearchEdit, this); - - mInventoryPanel = getChild("inventory panel"); - - if(mInventoryPanel) - { - U32 filter_types = 0x0; - filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; - filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; - - mInventoryPanel->setFilterTypes(filter_types); - //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. - mInventoryPanel->setFilterPermMask(immediate_filter_perm_mask); - mInventoryPanel->setSelectCallback(onSelectionChange, this); - mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); - mInventoryPanel->setAllowMultiSelect(FALSE); - - // store this filter as the default one - mInventoryPanel->getRootFolder()->getFilter()->markDefault(); - - // Commented out to stop opening all folders with textures - // mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_TEXTURE); - - // don't put keyboard focus on selected item, because the selection callback - // will assume that this was user input - mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); - } - mCanApplyImmediately = can_apply_immediately; - mNoCopyTextureSelected = FALSE; - - childSetValue("apply_immediate_check", gSavedSettings.getBOOL("ApplyTextureImmediately")); - childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this); - - if (!can_apply_immediately) - { - childSetEnabled("show_folders_check", FALSE); - } - - childSetAction("Pipette", LLFloaterTexturePicker::onBtnPipette,this); - childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this); - childSetAction("Select", LLFloaterTexturePicker::onBtnSelect,this); - - // update permission filter once UI is fully initialized - updateFilterPermMask(); - + LLUICtrlFactory::getInstance()->buildFloater(this,"floater_texture_ctrl.xml",NULL); setCanMinimize(FALSE); - - mSavedFolderState.setApply(FALSE); } LLFloaterTexturePicker::~LLFloaterTexturePicker() @@ -297,7 +210,7 @@ void LLFloaterTexturePicker::setImageID(const LLUUID& image_id) if( mImageAssetID != image_id && mActive) { mNoCopyTextureSelected = FALSE; - mIsDirty = TRUE; + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? mImageAssetID = image_id; LLUUID item_id = findItemID(mImageAssetID, FALSE); if (item_id.isNull()) @@ -350,9 +263,9 @@ void LLFloaterTexturePicker::updateImageStats() if (mTexturep.notNull()) { //RN: have we received header data for this image? - if (mTexturep->getWidth(0) > 0 && mTexturep->getHeight(0) > 0) + if (mTexturep->getFullWidth() > 0 && mTexturep->getFullHeight() > 0) { - std::string formatted_dims = llformat("%d x %d", mTexturep->getWidth(0),mTexturep->getHeight(0)); + std::string formatted_dims = llformat("%d x %d", mTexturep->getFullWidth(),mTexturep->getFullHeight()); mResolutionLabel->setTextArg("[DIMENSIONS]", formatted_dims); } else @@ -360,6 +273,10 @@ void LLFloaterTexturePicker::updateImageStats() mResolutionLabel->setTextArg("[DIMENSIONS]", std::string("[? x ?]")); } } + else + { + mResolutionLabel->setTextArg("[DIMENSIONS]", std::string("")); + } } // virtual @@ -418,15 +335,15 @@ BOOL LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask) { LLFolderView* root_folder = mInventoryPanel->getRootFolder(); - if (root_folder && mSearchEdit) + if (root_folder && mFilterEdit) { - if (mSearchEdit->hasFocus() + if (mFilterEdit->hasFocus() && (key == KEY_RETURN || key == KEY_DOWN) && mask == MASK_NONE) { if (!root_folder->getCurSelectedItem()) { - LLFolderViewItem* itemp = root_folder->getItemByID(gAgent.getInventoryRootID()); + LLFolderViewItem* itemp = root_folder->getItemByID(gInventory.getRootFolderID()); if (itemp) { root_folder->setSelection(itemp, FALSE, FALSE); @@ -435,7 +352,7 @@ BOOL LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask) root_folder->scrollToShowSelection(); // move focus to inventory proper - root_folder->setFocus(TRUE); + mInventoryPanel->setFocus(TRUE); // treat this as a user selection of the first filtered result commitIfImmediateSet(); @@ -443,29 +360,29 @@ BOOL LLFloaterTexturePicker::handleKeyHere(KEY key, MASK mask) return TRUE; } - if (root_folder->hasFocus() && key == KEY_UP) + if (mInventoryPanel->hasFocus() && key == KEY_UP) { - mSearchEdit->focusFirstItem(TRUE); + mFilterEdit->focusFirstItem(TRUE); } } return LLFloater::handleKeyHere(key, mask); } -// virtual -void LLFloaterTexturePicker::onClose(bool app_quitting) +void LLFloaterTexturePicker::onClose() { if (mOwner) { mOwner->onFloaterClose(); } stopUsingPipette(); - destroy(); } // virtual BOOL LLFloaterTexturePicker::postBuild() { + mCloseSignal.connect(boost::bind(&LLFloaterTexturePicker::onClose, this)); + LLFloater::postBuild(); if (!mLabel.empty()) @@ -474,13 +391,76 @@ BOOL LLFloaterTexturePicker::postBuild() setTitle(pick + mLabel); } + mTentativeLabel = getChild("Multiple"); + mResolutionLabel = getChild("unknown"); + + + childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this); + childSetAction("None", LLFloaterTexturePicker::onBtnNone,this); + childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this); + + + childSetCommitCallback("show_folders_check", onShowFolders, this); + childSetVisible("show_folders_check", FALSE); + + mFilterEdit = getChild("inventory search editor"); + mFilterEdit->setCommitCallback(boost::bind(&LLFloaterTexturePicker::onFilterEdit, this, _2)); + + mInventoryPanel = getChild("inventory panel"); + + if(mInventoryPanel) + { + U32 filter_types = 0x0; + filter_types |= 0x1 << LLInventoryType::IT_TEXTURE; + filter_types |= 0x1 << LLInventoryType::IT_SNAPSHOT; + + mInventoryPanel->setFilterTypes(filter_types); + //mInventoryPanel->setFilterPermMask(getFilterPermMask()); //Commented out due to no-copy texture loss. + mInventoryPanel->setFilterPermMask(mImmediateFilterPermMask); + mInventoryPanel->setSelectCallback(boost::bind(&LLFloaterTexturePicker::onSelectionChange, this, _1, _2)); + mInventoryPanel->setShowFolderState(LLInventoryFilter::SHOW_NON_EMPTY_FOLDERS); + mInventoryPanel->setAllowMultiSelect(FALSE); + + // store this filter as the default one + mInventoryPanel->getRootFolder()->getFilter()->markDefault(); + + // Commented out to stop opening all folders with textures + // mInventoryPanel->openDefaultFolderForType(LLAssetType::AT_TEXTURE); + + // don't put keyboard focus on selected item, because the selection callback + // will assume that this was user input + mInventoryPanel->setSelection(findItemID(mImageAssetID, FALSE), TAKE_FOCUS_NO); + } + + + mNoCopyTextureSelected = FALSE; + + childSetValue("apply_immediate_check", gSavedSettings.getBOOL("ApplyTextureImmediately")); + childSetCommitCallback("apply_immediate_check", onApplyImmediateCheck, this); + + if (!mCanApplyImmediately) + { + childSetEnabled("show_folders_check", FALSE); + } + + getChild("Pipette")->setCommitCallback( boost::bind(&LLFloaterTexturePicker::onBtnPipette, this)); + childSetAction("Cancel", LLFloaterTexturePicker::onBtnCancel,this); + childSetAction("Select", LLFloaterTexturePicker::onBtnSelect,this); + + // update permission filter once UI is fully initialized + updateFilterPermMask(); + mSavedFolderState.setApply(FALSE); + + LLToolPipette::getInstance()->setToolSelectCallback(boost::bind(&LLFloaterTexturePicker::onTextureSelect, this, _1)); + return TRUE; } // virtual void LLFloaterTexturePicker::draw() { + static LLUICachedControl floater_header_size ("UIFloaterHeaderSize", 0); if (mOwner) { // draw cone of context pointing back to texture swatch @@ -543,22 +523,19 @@ void LLFloaterTexturePicker::draw() childSetEnabled("Pipette", mActive); childSetValue("Pipette", LLToolMgr::getInstance()->getCurrentTool() == LLToolPipette::getInstance()); - //RN: reset search bar to reflect actual search query (all caps, for example) - mSearchEdit->setText(mInventoryPanel->getFilterSubString()); - //BOOL allow_copy = FALSE; if( mOwner ) { mTexturep = NULL; if(mImageAssetID.notNull()) { - mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); - mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); + mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); + mTexturep->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); } else if (!mFallbackImageName.empty()) { - mTexturep = gImageList.getImageFromFile(mFallbackImageName); - mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); + mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName); + mTexturep->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); } if (mTentativeLabel) @@ -579,9 +556,9 @@ void LLFloaterTexturePicker::draw() // Border LLRect border( BORDER_PAD, - getRect().getHeight() - LLFLOATER_HEADER_SIZE - BORDER_PAD, - ((TEX_PICKER_MIN_WIDTH / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD, - BORDER_PAD + FOOTER_HEIGHT + (getRect().getHeight() - TEX_PICKER_MIN_HEIGHT)); + getRect().getHeight() - floater_header_size - BORDER_PAD, + ((getMinWidth() / 2) - TEXTURE_INVENTORY_PADDING - HPAD) - BORDER_PAD, + BORDER_PAD + FOOTER_HEIGHT + (getRect().getHeight() - getMinHeight())); gl_rect_2d( border, LLColor4::black, FALSE ); @@ -602,7 +579,7 @@ void LLFloaterTexturePicker::draw() mTexturep->addTextureStats( (F32)(interior.getWidth() * interior.getHeight()) ); // Draw Tentative Label over the image - if( mOwner->getTentative() && !mIsDirty ) + if( mOwner->getTentative() && !mViewModel->isDirty() ) { mTentativeLabel->setVisible( TRUE ); drawChild(mTentativeLabel); @@ -719,7 +696,7 @@ void LLFloaterTexturePicker::onBtnRevert(void* userdata) // TODO: Change this to tell the owner to cancel. It needs to be // smart enough to restore multi-texture selections. self->mOwner->onFloaterCommit(); - self->mIsDirty = FALSE; + self->mViewModel->resetDirty(); }*/ // static @@ -731,8 +708,8 @@ void LLFloaterTexturePicker::onBtnCancel(void* userdata) { self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL); } - self->mIsDirty = FALSE; - self->close(); + self->mViewModel->resetDirty(); + self->closeFloater(); } // static @@ -743,52 +720,42 @@ void LLFloaterTexturePicker::onBtnSelect(void* userdata) { self->mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_SELECT); } - self->close(); + self->closeFloater(); } -// static -void LLFloaterTexturePicker::onBtnPipette( void* userdata ) +void LLFloaterTexturePicker::onBtnPipette() { - LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata; - - if ( self) + BOOL pipette_active = childGetValue("Pipette").asBoolean(); + pipette_active = !pipette_active; + if (pipette_active) { - BOOL pipette_active = self->childGetValue("Pipette").asBoolean(); - pipette_active = !pipette_active; - if (pipette_active) - { - LLToolPipette::getInstance()->setSelectCallback(onTextureSelect, self); - LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance()); - } - else - { - LLToolMgr::getInstance()->clearTransientTool(); - } + LLToolMgr::getInstance()->setTransientTool(LLToolPipette::getInstance()); + } + else + { + LLToolMgr::getInstance()->clearTransientTool(); } - } -// static -void LLFloaterTexturePicker::onSelectionChange(const std::deque &items, BOOL user_action, void* data) +void LLFloaterTexturePicker::onSelectionChange(const std::deque &items, BOOL user_action) { - LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data; if (items.size()) { LLFolderViewItem* first_item = items.front(); LLInventoryItem* itemp = gInventory.getItem(first_item->getListener()->getUUID()); - self->mNoCopyTextureSelected = FALSE; + mNoCopyTextureSelected = FALSE; if (itemp) { if (!itemp->getPermissions().allowCopyBy(gAgent.getID())) { - self->mNoCopyTextureSelected = TRUE; + mNoCopyTextureSelected = TRUE; } - self->mImageAssetID = itemp->getAssetUUID(); - self->mIsDirty = TRUE; + mImageAssetID = itemp->getAssetUUID(); + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? if (user_action) { // only commit intentional selections, not implicit ones - self->commitIfImmediateSet(); + commitIfImmediateSet(); } } } @@ -827,107 +794,97 @@ void LLFloaterTexturePicker::updateFilterPermMask() //mInventoryPanel->setFilterPermMask( getFilterPermMask() ); Commented out due to no-copy texture loss. } -void LLFloaterTexturePicker::onSearchEdit(const std::string& search_string, void* user_data ) +void LLFloaterTexturePicker::onFilterEdit(const std::string& search_string ) { - LLFloaterTexturePicker* picker = (LLFloaterTexturePicker*)user_data; - std::string upper_case_search_string = search_string; LLStringUtil::toUpper(upper_case_search_string); if (upper_case_search_string.empty()) { - if (picker->mInventoryPanel->getFilterSubString().empty()) + if (mInventoryPanel->getFilterSubString().empty()) { // current filter and new filter empty, do nothing return; } - picker->mSavedFolderState.setApply(TRUE); - picker->mInventoryPanel->getRootFolder()->applyFunctorRecursively(picker->mSavedFolderState); + mSavedFolderState.setApply(TRUE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); // add folder with current item to list of previously opened folders LLOpenFoldersWithSelection opener; - picker->mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); - picker->mInventoryPanel->getRootFolder()->scrollToShowSelection(); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(opener); + mInventoryPanel->getRootFolder()->scrollToShowSelection(); } - else if (picker->mInventoryPanel->getFilterSubString().empty()) + else if (mInventoryPanel->getFilterSubString().empty()) { // first letter in search term, save existing folder open state - if (!picker->mInventoryPanel->getRootFolder()->isFilterModified()) + if (!mInventoryPanel->getRootFolder()->isFilterModified()) { - picker->mSavedFolderState.setApply(FALSE); - picker->mInventoryPanel->getRootFolder()->applyFunctorRecursively(picker->mSavedFolderState); + mSavedFolderState.setApply(FALSE); + mInventoryPanel->getRootFolder()->applyFunctorRecursively(mSavedFolderState); } } - picker->mInventoryPanel->setFilterSubString(upper_case_search_string); + mInventoryPanel->setFilterSubString(upper_case_search_string); } -//static -void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te, void *data ) +void LLFloaterTexturePicker::onTextureSelect( const LLTextureEntry& te ) { - LLFloaterTexturePicker* self = (LLFloaterTexturePicker*)data; - - LLUUID inventory_item_id = self->findItemID(te.getID(), TRUE); - if (self && inventory_item_id.notNull()) + LLUUID inventory_item_id = findItemID(te.getID(), TRUE); + if (inventory_item_id.notNull()) { LLToolPipette::getInstance()->setResult(TRUE, ""); - self->setImageID(te.getID()); + setImageID(te.getID()); - self->mNoCopyTextureSelected = FALSE; + mNoCopyTextureSelected = FALSE; LLInventoryItem* itemp = gInventory.getItem(inventory_item_id); if (itemp && !itemp->getPermissions().allowCopyBy(gAgent.getID())) { // no copy texture - self->mNoCopyTextureSelected = TRUE; + mNoCopyTextureSelected = TRUE; } - self->commitIfImmediateSet(); + commitIfImmediateSet(); } else { - LLToolPipette::getInstance()->setResult(FALSE, "You do not have a copy this \nof texture in your inventory"); + LLToolPipette::getInstance()->setResult(FALSE, LLTrans::getString("InventoryNoTexture")); } } /////////////////////////////////////////////////////////////////////// // LLTextureCtrl -static LLRegisterWidget r("texture_picker"); +static LLDefaultChildRegistry::Register r("texture_picker"); -LLTextureCtrl::LLTextureCtrl( - const std::string& name, - const LLRect &rect, - const std::string& label, - const LLUUID &image_id, - const LLUUID &default_image_id, - const std::string& default_image_name ) - : - LLUICtrl(name, rect, TRUE, NULL, NULL, FOLLOWS_LEFT | FOLLOWS_TOP), +LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p) +: LLUICtrl(p), mDragCallback(NULL), mDropCallback(NULL), mOnCancelCallback(NULL), mOnSelectCallback(NULL), - mBorderColor( gColors.getColor("DefaultHighlightLight") ), - mImageAssetID( image_id ), - mDefaultImageAssetID( default_image_id ), - mDefaultImageName( default_image_name ), - mLabel( label ), + mBorderColor( p.border_color() ), mAllowNoTexture( FALSE ), mImmediateFilterPermMask( PERM_NONE ), mNonImmediateFilterPermMask( PERM_NONE ), mCanApplyImmediately( FALSE ), mNeedsRawImageData( FALSE ), mValid( TRUE ), - mDirty( FALSE ), - mShowLoadingPlaceholder( TRUE ) + mShowLoadingPlaceholder( TRUE ), + mImageAssetID(p.image_id), + mDefaultImageAssetID(p.default_image_id), + mDefaultImageName(p.default_image_name) { - mCaption = new LLTextBox( label, - LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 ), - label, - LLFontGL::getFontSansSerifSmall() ); - mCaption->setFollows( FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM ); + setAllowNoTexture(p.allow_no_texture); + setCanApplyImmediately(p.can_apply_immediately); + + LLTextBox::Params params(p.caption_text); + params.name(p.label); + params.rect(LLRect( 0, BTN_HEIGHT_SMALL, getRect().getWidth(), 0 )); + params.text(p.label); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + mCaption = LLUICtrlFactory::create (params); addChild( mCaption ); S32 image_top = getRect().getHeight(); @@ -935,92 +892,27 @@ LLTextureCtrl::LLTextureCtrl( S32 image_middle = (image_top + image_bottom) / 2; S32 line_height = llround(LLFontGL::getFontSansSerifSmall()->getLineHeight()); - mTentativeLabel = new LLTextBox( std::string("Multiple"), - LLRect( - 0, image_middle + line_height / 2, - getRect().getWidth(), image_middle - line_height / 2 ), - std::string("Multiple"), - LLFontGL::getFontSansSerifSmall() ); - mTentativeLabel->setHAlign( LLFontGL::HCENTER ); - mTentativeLabel->setFollowsAll(); + LLTextBox::Params tentative_label_p(p.multiselect_text); + tentative_label_p.name("Multiple"); + tentative_label_p.rect(LLRect (0, image_middle + line_height / 2, getRect().getWidth(), image_middle - line_height / 2 )); + tentative_label_p.follows.flags(FOLLOWS_ALL); + mTentativeLabel = LLUICtrlFactory::create (tentative_label_p); addChild( mTentativeLabel ); - LLRect border_rect(0, getRect().getHeight(), getRect().getWidth(), 0); + LLRect border_rect = getLocalRect(); border_rect.mBottom += BTN_HEIGHT_SMALL; - mBorder = new LLViewBorder(std::string("border"), border_rect, LLViewBorder::BEVEL_IN); - mBorder->setFollowsAll(); + LLViewBorder::Params vbparams(p.border); + vbparams.name("border"); + vbparams.rect(border_rect); + mBorder = LLUICtrlFactory::create (vbparams); addChild(mBorder); - setEnabled(TRUE); // for the tooltip mLoadingPlaceholderString = LLTrans::getString("texture_loading"); } - LLTextureCtrl::~LLTextureCtrl() { - closeFloater(); -} - -// virtual -LLXMLNodePtr LLTextureCtrl::getXML(bool save_children) const -{ - LLXMLNodePtr node = LLUICtrl::getXML(); - - node->createChild("label", TRUE)->setStringValue(getLabel()); - - node->createChild("default_image_name", TRUE)->setStringValue(getDefaultImageName()); - - node->createChild("allow_no_texture", TRUE)->setBoolValue(mAllowNoTexture); - - node->createChild("can_apply_immediately", TRUE)->setBoolValue(mCanApplyImmediately ); - - return node; -} - -LLView* LLTextureCtrl::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("texture_picker"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent); - - std::string label; - node->getAttributeString("label", label); - - std::string image_id(""); - node->getAttributeString("image", image_id); - - std::string default_image_id(""); - node->getAttributeString("default_image", default_image_id); - - std::string default_image_name("Default"); - node->getAttributeString("default_image_name", default_image_name); - - BOOL allow_no_texture = FALSE; - node->getAttributeBOOL("allow_no_texture", allow_no_texture); - - BOOL can_apply_immediately = FALSE; - node->getAttributeBOOL("can_apply_immediately", can_apply_immediately); - - if (label.empty()) - { - label.assign(node->getValue()); - } - - LLTextureCtrl* texture_picker = new LLTextureCtrl( - name, - rect, - label, - LLUUID(image_id), - LLUUID(default_image_id), - default_image_name ); - texture_picker->setAllowNoTexture(allow_no_texture); - texture_picker->setCanApplyImmediately(can_apply_immediately); - - texture_picker->initFromXML(node, parent); - - return texture_picker; + closeDependentFloater(); } void LLTextureCtrl::setShowLoadingPlaceholder(BOOL showLoadingPlaceholder) @@ -1047,7 +939,7 @@ void LLTextureCtrl::setVisible( BOOL visible ) { if( !visible ) { - closeFloater(); + closeDependentFloater(); } LLUICtrl::setVisible( visible ); } @@ -1066,7 +958,7 @@ void LLTextureCtrl::setEnabled( BOOL enabled ) setToolTip( std::string() ); // *TODO: would be better to keep floater open and show // disabled state. - closeFloater(); + closeDependentFloater(); } if( floaterp ) @@ -1092,18 +984,6 @@ void LLTextureCtrl::setValid(BOOL valid ) } } -// virtual -BOOL LLTextureCtrl::isDirty() const -{ - return mDirty; -} - -// virtual -void LLTextureCtrl::resetDirty() -{ - mDirty = FALSE; -} - // virtual void LLTextureCtrl::clear() @@ -1119,25 +999,20 @@ void LLTextureCtrl::setLabel(const std::string& label) void LLTextureCtrl::showPicker(BOOL take_focus) { + // show hourglass cursor when loading inventory window + // because inventory construction is slooow + getWindow()->setCursor(UI_CURSOR_WAIT); LLFloater* floaterp = mFloaterHandle.get(); // Show the dialog if( floaterp ) { - floaterp->open( ); /* Flawfinder: ignore */ + floaterp->openFloater(); } else { - if( !mLastFloaterLeftTop.mX && !mLastFloaterLeftTop.mY ) - { - gFloaterView->getNewFloaterPosition(&mLastFloaterLeftTop.mX, &mLastFloaterLeftTop.mY); - } - LLRect rect = gSavedSettings.getRect("TexturePickerRect"); - rect.translate( mLastFloaterLeftTop.mX - rect.mLeft, mLastFloaterLeftTop.mY - rect.mTop ); - floaterp = new LLFloaterTexturePicker( this, - rect, mLabel, mImmediateFilterPermMask, mNonImmediateFilterPermMask, @@ -1146,8 +1021,10 @@ void LLTextureCtrl::showPicker(BOOL take_focus) mFloaterHandle = floaterp->getHandle(); - gFloaterView->getParentFloater(this)->addDependentFloater(floaterp); - floaterp->open(); /* Flawfinder: ignore */ + LLFloater* root_floater = gFloaterView->getParentFloater(this); + if (root_floater) + root_floater->addDependentFloater(floaterp); + floaterp->openFloater(); } if (take_focus) @@ -1157,13 +1034,13 @@ void LLTextureCtrl::showPicker(BOOL take_focus) } -void LLTextureCtrl::closeFloater() +void LLTextureCtrl::closeDependentFloater() { LLFloaterTexturePicker* floaterp = (LLFloaterTexturePicker*)mFloaterHandle.get(); if( floaterp ) { floaterp->setOwner(NULL); - floaterp->close(); + floaterp->closeFloater(); } } @@ -1210,7 +1087,6 @@ void LLTextureCtrl::onFloaterClose() if (floaterp) { floaterp->setOwner(NULL); - mLastFloaterLeftTop.set( floaterp->getRect().mLeft, floaterp->getRect().mTop ); } mFloaterHandle.markDead(); @@ -1222,7 +1098,11 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) if( floaterp && getEnabled()) { - mDirty = (op != TEXTURE_CANCEL); + if (op == TEXTURE_CANCEL) + mViewModel->resetDirty(); + else + mViewModel->setDirty(); // *TODO: shouldn't we be using setValue() here? + if( floaterp->isDirty() ) { setTentative( FALSE ); @@ -1232,11 +1112,11 @@ void LLTextureCtrl::onFloaterCommit(ETexturePickOp op) lldebugs << "mImageAssetID: " << mImageAssetID << llendl; if (op == TEXTURE_SELECT && mOnSelectCallback) { - mOnSelectCallback(this, mCallbackUserData); + mOnSelectCallback( this, LLSD() ); } else if (op == TEXTURE_CANCEL && mOnCancelCallback) { - mOnCancelCallback(this, mCallbackUserData); + mOnCancelCallback( this, LLSD() ); } else { @@ -1256,7 +1136,7 @@ void LLTextureCtrl::setImageAssetID( const LLUUID& asset_id ) if( floaterp && getEnabled() ) { floaterp->setImageID( asset_id ); - floaterp->setDirty( FALSE ); + floaterp->resetDirty(); } } } @@ -1308,19 +1188,23 @@ void LLTextureCtrl::draw() } else if (!mImageAssetID.isNull()) { - mTexturep = gImageList.getImage(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); - mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); + mTexturep = LLViewerTextureManager::getFetchedTexture(mImageAssetID, MIPMAP_YES, IMMEDIATE_NO); + mTexturep->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); } else if (!mFallbackImageName.empty()) { // Show fallback image. - mTexturep = gImageList.getImageFromFile(mFallbackImageName); - mTexturep->setBoostLevel(LLViewerImage::BOOST_PREVIEW); + mTexturep = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName); + mTexturep->setBoostLevel(LLViewerTexture::BOOST_PREVIEW); + } + else//mImageAssetID == LLUUID::null + { + mTexturep = NULL; } // Border LLRect border( 0, getRect().getHeight(), getRect().getWidth(), BTN_HEIGHT_SMALL ); - gl_rect_2d( border, mBorderColor, FALSE ); + gl_rect_2d( border, mBorderColor.get(), FALSE ); // Interior LLRect interior = border; @@ -1388,7 +1272,7 @@ BOOL LLTextureCtrl::allowDrop(LLInventoryItem* item) { if(mDragCallback) { - return mDragCallback(this, item, mCallbackUserData); + return mDragCallback(this, item); } else { @@ -1408,7 +1292,7 @@ BOOL LLTextureCtrl::doDrop(LLInventoryItem* item) { // if it returns TRUE, we return TRUE, and therefore the // commit is called above. - return mDropCallback(this, item, mCallbackUserData); + return mDropCallback(this, item); } // no callback installed, so just set the image ids and carry on. @@ -1438,66 +1322,6 @@ LLSD LLTextureCtrl::getValue() const } -///////////////////////////////////////////////////////////////////////////////// -// LLToolTexEyedropper - -class LLToolTexEyedropper : public LLTool -{ -public: - LLToolTexEyedropper( void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ), void* userdata ); - virtual ~LLToolTexEyedropper(); - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - -protected: - void (*mCallback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ); - void* mCallbackUserData; -}; - - -LLToolTexEyedropper::LLToolTexEyedropper( - void (*callback)(const LLUUID& obj_id, const LLUUID& image_id, void* userdata ), - void* userdata ) - : LLTool(std::string("texeyedropper")), - mCallback( callback ), - mCallbackUserData( userdata ) -{ -} - -LLToolTexEyedropper::~LLToolTexEyedropper() -{ -} - - -BOOL LLToolTexEyedropper::handleMouseDown(S32 x, S32 y, MASK mask) -{ - // this will affect framerate on mouse down - const LLPickInfo& pick = gViewerWindow->pickImmediate(x, y, FALSE); - LLViewerObject* hit_obj = pick.getObject(); - if (hit_obj && - !hit_obj->isAvatar()) - { - if( (0 <= pick.mObjectFace) && (pick.mObjectFace < hit_obj->getNumTEs()) ) - { - LLViewerImage* image = hit_obj->getTEImage( pick.mObjectFace ); - if( image ) - { - if( mCallback ) - { - mCallback( hit_obj->getID(), image->getID(), mCallbackUserData ); - } - } - } - } - return TRUE; -} - -BOOL LLToolTexEyedropper::handleHover(S32 x, S32 y, MASK mask) -{ - lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolTexEyedropper" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_CROSS); // TODO: better cursor - return TRUE; -} diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 623f15eef5..0b232da62b 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -39,16 +39,17 @@ #include "llstring.h" #include "lluictrl.h" #include "llpermissionsflags.h" +#include "lltextbox.h" // for params +#include "llviewborder.h" // for params class LLButton; class LLFloaterTexturePicker; class LLInventoryItem; -class LLTextBox; -class LLViewBorder; -class LLViewerImage; +class LLViewerTexture; // used for setting drag & drop callbacks. -typedef BOOL (*drag_n_drop_callback)(LLUICtrl*, LLInventoryItem*, void*); +typedef boost::function drag_n_drop_callback; + ////////////////////////////////////////////////////////////////////////////////////////// // LLTextureCtrl @@ -66,17 +67,45 @@ public: } ETexturePickOp; public: - LLTextureCtrl( - const std::string& name, const LLRect& rect, - const std::string& label, - const LLUUID& image_id, - const LLUUID& default_image_id, - const std::string& default_image_name ); + struct Params : public LLInitParam::Block + { + Optional image_id; + Optional default_image_id; + Optional default_image_name; + Optional allow_no_texture; + Optional can_apply_immediately; + Optional label_width; + Optional border_color; + + Optional multiselect_text, + caption_text; + + Optional border; + + Params() + : image_id("image"), + default_image_id("default_image_id"), + default_image_name("default_image_name"), + allow_no_texture("allow_no_texture"), + can_apply_immediately("can_apply_immediately"), + label_width("label_width", -1), + border_color("border_color"), + multiselect_text("multiselect_text"), + caption_text("caption_text"), + border("border") + { + name = "texture picker"; + mouse_opaque(true); + follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + } + }; +protected: + LLTextureCtrl(const Params&); + friend class LLUICtrlFactory; +public: virtual ~LLTextureCtrl(); // LLView interface - virtual LLXMLNodePtr getXML(bool save_children = true) const; - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, @@ -90,9 +119,6 @@ public: virtual void setVisible( BOOL visible ); virtual void setEnabled( BOOL enabled ); - virtual BOOL isDirty() const; - virtual void resetDirty(); - void setValid(BOOL valid); // LLUICtrl interface @@ -105,6 +131,7 @@ public: // LLTextureCtrl interface void showPicker(BOOL take_focus); void setLabel(const std::string& label); + void setLabelWidth(S32 label_width) {mLabelWidth =label_width;} const std::string& getLabel() const { return mLabel; } void setAllowNoTexture( BOOL b ) { mAllowNoTexture = b; } @@ -133,7 +160,7 @@ public: PermissionMask getImmediateFilterPermMask() { return mImmediateFilterPermMask; } PermissionMask getNonImmediateFilterPermMask() { return mNonImmediateFilterPermMask; } - void closeFloater(); + void closeDependentFloater(); void onFloaterClose(); void onFloaterCommit(ETexturePickOp op); @@ -146,10 +173,10 @@ public: // the drop happened - resulting in an on commit callback, but not // necessariliy any other change. void setDropCallback(drag_n_drop_callback cb) { mDropCallback = cb; } - - void setOnCancelCallback(LLUICtrlCallback cb) { mOnCancelCallback = cb; } - void setOnSelectCallback(LLUICtrlCallback cb) { mOnSelectCallback = cb; } + void setOnCancelCallback(commit_callback_t cb) { mOnCancelCallback = cb; } + + void setOnSelectCallback(commit_callback_t cb) { mOnSelectCallback = cb; } void setShowLoadingPlaceholder(BOOL showLoadingPlaceholder); @@ -160,10 +187,10 @@ private: private: drag_n_drop_callback mDragCallback; drag_n_drop_callback mDropCallback; - LLUICtrlCallback mOnCancelCallback; - LLUICtrlCallback mOnSelectCallback; - LLPointer mTexturep; - LLColor4 mBorderColor; + commit_callback_t mOnCancelCallback; + commit_callback_t mOnSelectCallback; + LLPointer mTexturep; + LLUIColor mBorderColor; LLUUID mImageItemID; LLUUID mImageAssetID; LLUUID mDefaultImageAssetID; @@ -174,16 +201,15 @@ private: LLTextBox* mCaption; std::string mLabel; BOOL mAllowNoTexture; // If true, the user can select "none" as an option - LLCoordGL mLastFloaterLeftTop; PermissionMask mImmediateFilterPermMask; PermissionMask mNonImmediateFilterPermMask; BOOL mCanApplyImmediately; BOOL mNeedsRawImageData; LLViewBorder* mBorder; BOOL mValid; - BOOL mDirty; BOOL mShowLoadingPlaceholder; std::string mLoadingPlaceholderString; + S32 mLabelWidth; }; // XUI HACK: When floaters converted, switch this file to lltexturepicker.h/cpp diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp index e9dd7921cd..63af170fa9 100644 --- a/indra/newview/lltexturefetch.cpp +++ b/indra/newview/lltexturefetch.cpp @@ -44,8 +44,8 @@ #include "llagent.h" #include "lltexturecache.h" -#include "llviewerimagelist.h" -#include "llviewerimage.h" +#include "llviewertexturelist.h" +#include "llviewertexture.h" #include "llviewerregion.h" ////////////////////////////////////////////////////////////////////////////// @@ -469,8 +469,8 @@ void LLTextureFetchWorker::clearPackets() U32 LLTextureFetchWorker::calcWorkPriority() { -// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerImage::maxDecodePriority()); - F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerImage::maxDecodePriority(); +// llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerTexture::maxDecodePriority()); + F32 priority_scale = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority(); mWorkPriority = (U32)(mImagePriority * priority_scale); return mWorkPriority; } @@ -512,7 +512,7 @@ void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size) void LLTextureFetchWorker::setImagePriority(F32 priority) { -// llassert_always(priority >= 0 && priority <= LLViewerImage::maxDecodePriority()); +// llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority()); F32 delta = fabs(priority - mImagePriority); if (delta > (mImagePriority * .05f) || mState == DONE) { @@ -542,7 +542,7 @@ void LLTextureFetchWorker::startWork(S32 param) llassert(mFormattedImage.isNull()); } -#include "llviewerimagelist.h" // debug +#include "llviewertexturelist.h" // debug // Called from LLWorkerThread::processRequest() bool LLTextureFetchWorker::doWork(S32 param) @@ -796,7 +796,7 @@ bool LLTextureFetchWorker::doWork(S32 param) mFormattedImage->deleteData(); #endif mRequestedSize -= cur_size; - // F32 priority = mImagePriority / (F32)LLViewerImage::maxDecodePriority(); // 0-1 + // F32 priority = mImagePriority / (F32)LLViewerTexture::maxDecodePriority(); // 0-1 S32 offset = cur_size; mBufferSize = cur_size; // This will get modified by callbackHttpGet() std::string url; @@ -1877,6 +1877,21 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1 } ////////////////////////////////////////////////////////////////////////////// +BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id) +{ + BOOL from_cache = FALSE ; + + LLMutexLock lock(&mQueueMutex); + LLTextureFetchWorker* worker = getWorker(id); + if (worker) + { + worker->lockWorkData(); + from_cache = worker->mInLocalCache ; + worker->unlockWorkData(); + } + + return from_cache ; +} S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p, U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p) diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h index 56650e721c..97719a9468 100644 --- a/indra/newview/lltexturefetch.h +++ b/indra/newview/lltexturefetch.h @@ -38,7 +38,7 @@ #include "lluuid.h" #include "llworkerthread.h" -class LLViewerImage; +class LLViewerTexture; class LLTextureFetchWorker; class LLTextureCache; class LLHost; @@ -67,6 +67,7 @@ public: bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data); // Debug + BOOL isFromLocalCache(const LLUUID& id); S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p, U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p); void dump(); diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp index d356bf99ae..70a8ab9f61 100644 --- a/indra/newview/lltextureview.cpp +++ b/indra/newview/lltextureview.cpp @@ -49,8 +49,8 @@ #include "lltexturecache.h" #include "lltexturefetch.h" #include "llviewerobject.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llappviewer.h" extern F32 texmem_lower_bound_scale; @@ -58,18 +58,18 @@ extern F32 texmem_lower_bound_scale; LLTextureView *gTextureView = NULL; //static -std::set LLTextureView::sDebugImages; +std::set LLTextureView::sDebugImages; //////////////////////////////////////////////////////////////////////////// -static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max"); -static std::string title_string1b("Tex UUID Area DDis(Req) Fetch(DecodePri) [download] pk/max"); +static std::string title_string1a("Tex UUID Area DDis(Req) DecodePri(Fetch) [download] pk/max"); +static std::string title_string1b("Tex UUID Area DDis(Req) Fetch(DecodePri) [download] pk/max"); static std::string title_string2("State"); static std::string title_string3("Pkt Bnd"); static std::string title_string4(" W x H (Dis) Mem"); static S32 title_x1 = 0; -static S32 title_x2 = 440; +static S32 title_x2 = 460; static S32 title_x3 = title_x2 + 40; static S32 title_x4 = title_x3 + 50; static S32 texture_bar_height = 8; @@ -79,16 +79,24 @@ static S32 texture_bar_height = 8; class LLTextureBar : public LLView { public: - LLPointer mImagep; + LLPointer mImagep; S32 mHilite; public: - LLTextureBar(const std::string& name, const LLRect& r, LLTextureView* texview) - : LLView(name, r, FALSE), - mHilite(0), - mTextureView(texview) + struct Params : public LLInitParam::Block { - } + Mandatory texture_view; + Params() + : texture_view("texture_view") + { + mouse_opaque(false); + } + }; + LLTextureBar(const Params& p) + : LLView(p), + mHilite(0), + mTextureView(p.texture_view) + {} virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); @@ -101,8 +109,8 @@ public: { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; - LLViewerImage *i1p = bar1p->mImagep; - LLViewerImage *i2p = bar2p->mImagep; + LLViewerFetchedTexture *i1p = bar1p->mImagep; + LLViewerFetchedTexture *i2p = bar2p->mImagep; F32 pri1 = i1p->getDecodePriority(); // i1p->mRequestedDownloadPriority F32 pri2 = i2p->getDecodePriority(); // i2p->mRequestedDownloadPriority if (pri1 > pri2) @@ -120,10 +128,10 @@ public: { LLTextureBar* bar1p = (LLTextureBar*)i1; LLTextureBar* bar2p = (LLTextureBar*)i2; - LLViewerImage *i1p = bar1p->mImagep; - LLViewerImage *i2p = bar2p->mImagep; - U32 pri1 = i1p->mFetchPriority; - U32 pri2 = i2p->mFetchPriority; + LLViewerFetchedTexture *i1p = bar1p->mImagep; + LLViewerFetchedTexture *i2p = bar2p->mImagep; + U32 pri1 = i1p->getFetchPriority() ; + U32 pri2 = i2p->getFetchPriority() ; if (pri1 > pri2) return true; else if (pri2 > pri1) @@ -307,10 +315,10 @@ void LLTextureBar::draw() pip_x += pip_width + pip_space; // we don't want to show bind/resident pips for textures using the default texture - if (mImagep->getHasGLTexture()) + if (mImagep->hasValidGLTexture()) { // Draw the bound pip - last_event = mImagep->sLastFrameTime - mImagep->mLastBindTime; + last_event = mImagep->getTimePassedSinceLastBound(); if (last_event < 1.f) { clr = mImagep->getMissed() ? LLColor4::red : LLColor4::magenta1; @@ -334,7 +342,7 @@ void LLTextureBar::draw() // draw the image size at the end { std::string num_str = llformat("%3dx%3d (%d) %7d", mImagep->getWidth(), mImagep->getHeight(), - mImagep->getDiscardLevel(), mImagep->mTextureMemory); + mImagep->getDiscardLevel(), mImagep->hasGLTexture() ? mImagep->getTextureMemory() : 0); LLFontGL::getFontMonospace()->renderUTF8(num_str, 0, title_x4, getRect().getHeight(), color, LLFontGL::LEFT, LLFontGL::TOP); } @@ -366,13 +374,21 @@ LLRect LLTextureBar::getRequiredRect() class LLGLTexMemBar : public LLView { public: - LLGLTexMemBar(const std::string& name, LLTextureView* texview) - : LLView(name, FALSE), - mTextureView(texview) + struct Params : public LLInitParam::Block { - S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); - setRect(LLRect(0,0,100,line_height * 4)); - } + Mandatory texture_view; + Params() + : texture_view("texture_view") + { + S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); + rect(LLRect(0,0,100,line_height * 4)); + } + }; + + LLGLTexMemBar(const Params& p) + : LLView(p), + mTextureView(p.texture_view) + {} virtual void draw(); virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); @@ -384,13 +400,13 @@ private: void LLGLTexMemBar::draw() { - S32 bound_mem = BYTES_TO_MEGA_BYTES(LLViewerImage::sBoundTextureMemoryInBytes); - S32 max_bound_mem = LLViewerImage::sMaxBoundTextureMemInMegaBytes; - S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerImage::sTotalTextureMemoryInBytes); - S32 max_total_mem = LLViewerImage::sMaxTotalTextureMemInMegaBytes; - F32 discard_bias = LLViewerImage::sDesiredDiscardBias; + S32 bound_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sBoundTextureMemoryInBytes); + S32 max_bound_mem = LLViewerTexture::sMaxBoundTextureMemInMegaBytes; + S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sTotalTextureMemoryInBytes); + S32 max_total_mem = LLViewerTexture::sMaxTotalTextureMemInMegaBytes; + F32 discard_bias = LLViewerTexture::sDesiredDiscardBias; S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f); - + S32 h_offset = (S32)((texture_bar_height + 2.5f) * mTextureView->mNumTextureBars + 2.5f); //---------------------------------------------------------------------------- LLGLSUIDefault gls_ui; F32 text_color[] = {1.f, 1.f, 1.f, 0.75f}; @@ -403,13 +419,13 @@ void LLGLTexMemBar::draw() max_bound_mem, discard_bias); - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, line_height*3, + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*3, text_color, LLFontGL::LEFT, LLFontGL::TOP); //---------------------------------------------------------------------------- S32 bar_left = 380; S32 bar_width = 200; - S32 top = line_height*3 - 2; + S32 top = line_height*3 - 2 + h_offset; S32 bottom = top - 6; S32 left = bar_left; S32 right = left + bar_width; @@ -461,49 +477,49 @@ void LLGLTexMemBar::draw() //---------------------------------------------------------------------------- text = llformat("Textures: Count: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d(%d) RAW:%d mRaw:%d mAux:%d CB:%d", - gImageList.getNumImages(), + gTextureList.getNumImages(), LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(), LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount, LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(), LLLFSThread::sLocal->getPending(), LLImageWorker::sCount, LLImageWorker::getWorkerThread()->getNumDeletes(), - LLImageRaw::sRawImageCount, LLViewerImage::sRawCount, LLViewerImage::sAuxCount, - gImageList.mCallbackList.size()); + LLImageRaw::sRawImageCount, LLViewerFetchedTexture::sRawCount, LLViewerFetchedTexture::sAuxCount, + gTextureList.mCallbackList.size()); - LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, line_height*2, + LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*2, text_color, LLFontGL::LEFT, LLFontGL::TOP); S32 dx1 = 0; if (LLAppViewer::getTextureFetch()->mDebugPause) { - LLFontGL::getFontMonospace()->renderUTF8(std::string("!"), 0, title_x1, line_height, + LLFontGL::getFontMonospace()->renderUTF8(std::string("!"), 0, title_x1, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); dx1 += 8; } if (mTextureView->mFreezeView) { - LLFontGL::getFontMonospace()->renderUTF8(std::string("*"), 0, title_x1, line_height, + LLFontGL::getFontMonospace()->renderUTF8(std::string("*"), 0, title_x1, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); dx1 += 8; } if (mTextureView->mOrderFetch) { - LLFontGL::getFontMonospace()->renderUTF8(title_string1b, 0, title_x1+dx1, line_height, + LLFontGL::getFontMonospace()->renderUTF8(title_string1b, 0, title_x1+dx1, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } else { - LLFontGL::getFontMonospace()->renderUTF8(title_string1a, 0, title_x1+dx1, line_height, + LLFontGL::getFontMonospace()->renderUTF8(title_string1a, 0, title_x1+dx1, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } - LLFontGL::getFontMonospace()->renderUTF8(title_string2, 0, title_x2, line_height, + LLFontGL::getFontMonospace()->renderUTF8(title_string2, 0, title_x2, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); - LLFontGL::getFontMonospace()->renderUTF8(title_string3, 0, title_x3, line_height, + LLFontGL::getFontMonospace()->renderUTF8(title_string3, 0, title_x3, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); - LLFontGL::getFontMonospace()->renderUTF8(title_string4, 0, title_x4, line_height, + LLFontGL::getFontMonospace()->renderUTF8(title_string4, 0, title_x4, h_offset + line_height, text_color, LLFontGL::LEFT, LLFontGL::TOP); } @@ -521,8 +537,8 @@ LLRect LLGLTexMemBar::getRequiredRect() //////////////////////////////////////////////////////////////////////////// -LLTextureView::LLTextureView(const std::string& name, const LLRect& rect) - : LLContainerView(name, rect), +LLTextureView::LLTextureView(const LLTextureView::Params& p) + : LLContainerView(p), mFreezeView(FALSE), mOrderFetch(FALSE), mPrintList(FALSE), @@ -541,7 +557,7 @@ LLTextureView::~LLTextureView() mGLTexMemBar = 0; } -typedef std::pair decode_pair_t; +typedef std::pair decode_pair_t; struct compare_decode_pair { bool operator()(const decode_pair_t& a, const decode_pair_t& b) @@ -571,18 +587,19 @@ void LLTextureView::draw() llinfos << "ID\tMEM\tBOOST\tPRI\tWIDTH\tHEIGHT\tDISCARD" << llendl; } - for (LLViewerImageList::image_priority_list_t::iterator iter = gImageList.mImageList.begin(); - iter != gImageList.mImageList.end(); ) + for (LLViewerTextureList::image_priority_list_t::iterator iter = gTextureList.mImageList.begin(); + iter != gTextureList.mImageList.end(); ) { - LLPointer imagep = *iter++; + LLPointer imagep = *iter++; S32 cur_discard = imagep->getDiscardLevel(); S32 desired_discard = imagep->mDesiredDiscardLevel; if (mPrintList) { + S32 tex_mem = imagep->hasGLTexture() ? imagep->getTextureMemory() : 0 ; llinfos << imagep->getID() - << "\t" << imagep->mTextureMemory + << "\t" << tex_mem << "\t" << imagep->getBoostLevel() << "\t" << imagep->getDecodePriority() << "\t" << imagep->getWidth() @@ -627,8 +644,8 @@ void LLTextureView::draw() { struct f : public LLSelectedTEFunctor { - LLViewerImage* mImage; - f(LLViewerImage* image) : mImage(image) {} + LLViewerFetchedTexture* mImage; + f(LLViewerFetchedTexture* image) : mImage(image) {} virtual bool apply(LLViewerObject* object, S32 te) { return (mImage == object->getTEImage(te)); @@ -685,10 +702,11 @@ void LLTextureView::draw() static S32 max_count = 50; S32 count = 0; + mNumTextureBars = 0 ; for (display_list_t::iterator iter = display_image_list.begin(); iter != display_image_list.end(); iter++) { - LLViewerImage* imagep = iter->second; + LLViewerFetchedTexture* imagep = iter->second; S32 hilite = 0; F32 pri = iter->first; if (pri >= 1 * HIGH_PRIORITY) @@ -709,13 +727,16 @@ void LLTextureView::draw() else sortChildren(LLTextureBar::sort()); - mGLTexMemBar = new LLGLTexMemBar("gl texmem bar", this); + LLGLTexMemBar::Params tmbp; + tmbp.name("gl texmem bar"); + tmbp.texture_view(this); + mGLTexMemBar = LLUICtrlFactory::create(tmbp); addChild(mGLTexMemBar); reshape(getRect().getWidth(), getRect().getHeight(), TRUE); /* - count = gImageList.getNumImages(); + count = gTextureList.getNumImages(); std::string info_string; info_string = llformat("Global Info:\nTexture Count: %d", count); mInfoTextp->setText(info_string); @@ -737,7 +758,7 @@ void LLTextureView::draw() } -BOOL LLTextureView::addBar(LLViewerImage *imagep, S32 hilite) +BOOL LLTextureView::addBar(LLViewerFetchedTexture *imagep, S32 hilite) { llassert(imagep); @@ -746,7 +767,11 @@ BOOL LLTextureView::addBar(LLViewerImage *imagep, S32 hilite) mNumTextureBars++; - barp = new LLTextureBar("texture bar", r, this); + LLTextureBar::Params tbp; + tbp.name("texture bar"); + tbp.rect(r); + tbp.texture_view(this); + barp = LLUICtrlFactory::create(tbp); barp->mImagep = imagep; barp->mHilite = hilite; diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h index f91a296b97..20be17aef4 100644 --- a/indra/newview/lltextureview.h +++ b/indra/newview/lltextureview.h @@ -35,7 +35,7 @@ #include "llcontainerview.h" -class LLViewerImage; +class LLViewerFetchedTexture; class LLTextureBar; class LLGLTexMemBar; @@ -43,8 +43,10 @@ class LLTextureView : public LLContainerView { friend class LLTextureBar; friend class LLGLTexMemBar; +protected: + LLTextureView(const Params&); + friend class LLUICtrlFactory; public: - LLTextureView(const std::string& name, const LLRect& rect); ~LLTextureView(); /*virtual*/ void draw(); @@ -52,12 +54,12 @@ public: /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); - static void addDebugImage(LLViewerImage* image) { sDebugImages.insert(image); } - static void removeDebugImage(LLViewerImage* image) { sDebugImages.insert(image); } + static void addDebugImage(LLViewerFetchedTexture* image) { sDebugImages.insert(image); } + static void removeDebugImage(LLViewerFetchedTexture* image) { sDebugImages.insert(image); } static void clearDebugImages() { sDebugImages.clear(); } private: - BOOL addBar(LLViewerImage *image, BOOL hilight = FALSE); + BOOL addBar(LLViewerFetchedTexture *image, BOOL hilight = FALSE); void removeAllBars(); private: @@ -73,7 +75,7 @@ private: LLGLTexMemBar* mGLTexMemBar; public: - static std::set sDebugImages; + static std::set sDebugImages; }; extern LLTextureView *gTextureView; diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp new file mode 100644 index 0000000000..85814a98c9 --- /dev/null +++ b/indra/newview/lltoast.cpp @@ -0,0 +1,294 @@ +/** + * @file lltoast.cpp + * @brief This class implements a placeholder for any notification panel. + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "lltoast.h" + +#include "llbutton.h" +#include "llfocusmgr.h" +#include "llviewercontrol.h" + +using namespace LLNotificationsUI; + +//-------------------------------------------------------------------------- +LLToast::LLToast(LLToast::Params p) : LLFloater(LLSD()), + mPanel(p.panel), + mTimerValue(p.timer_period), + mID(p.id), + mCanFade(p.can_fade), + mCanBeStored(p.can_be_stored), + mHideBtnEnabled(p.enable_hide_btn), + mIsModal(p.is_modal), + mHideBtn(NULL), + mNotification(p.notification), + mHideBtnPressed(false) +{ + LLUICtrlFactory::getInstance()->buildFloater(this, "panel_toast.xml", NULL); + + if(mPanel) + { + insertPanel(mPanel); + } + + if(mHideBtnEnabled) + { + mHideBtn = getChild("hide_btn"); + mHideBtn->setClickedCallback(boost::bind(&LLToast::hide,this)); + } + + if(mIsModal) + { + gFocusMgr.setMouseCapture( this ); + gFocusMgr.setTopCtrl( this ); + setFocus(TRUE); + } + + + if(!p.on_toast_destroy.empty()) + mOnToastDestroy.connect(p.on_toast_destroy); + + if(!p.on_mouse_enter.empty()) + mOnMousEnter.connect(p.on_mouse_enter); +} + +//-------------------------------------------------------------------------- +BOOL LLToast::postBuild() +{ + if(mCanFade) + { + mTimer.start(); + } + else + { + mTimer.stop(); + } + + return TRUE; +} + +//-------------------------------------------------------------------------- +void LLToast::setHideButtonEnabled(bool enabled) +{ + if(mHideBtn) + mHideBtn->setEnabled(enabled); +} + +//-------------------------------------------------------------------------- +LLToast::~LLToast() +{ + if(mIsModal) + { + gFocusMgr.unlockFocus(); + gFocusMgr.releaseFocusIfNeeded( this ); + } +} + +//-------------------------------------------------------------------------- +void LLToast::setAndStartTimer(F32 period) +{ + if(mCanFade) + { + mTimerValue = period; + mTimer.start(); + } +} + +//-------------------------------------------------------------------------- +bool LLToast::timerHasExpired() +{ + if (mTimer.getStarted()) + { + F32 elapsed_time = mTimer.getElapsedTimeF32(); + if (elapsed_time > gSavedSettings.getS32("ToastOpaqueTime")) + { + setBackgroundOpaque(FALSE); + } + if (elapsed_time > mTimerValue) + { + return true; + } + } + return false; +} + +//-------------------------------------------------------------------------- +void LLToast::hide() +{ + setVisible(FALSE); + mTimer.stop(); + mOnFade(this); +} + +//-------------------------------------------------------------------------- +void LLToast::setCanFade(bool can_fade) +{ + mCanFade = can_fade; + if(!mCanFade) + mTimer.stop(); +} + +//-------------------------------------------------------------------------- +void LLToast::tick() +{ + if(mCanFade) + { + setVisible(FALSE); + mTimer.stop(); + mOnFade(this); + } +} + +//-------------------------------------------------------------------------- +void LLToast::insertPanel(LLPanel* panel) +{ + LLRect panel_rect, toast_rect; + + panel_rect = panel->getRect(); + reshape(panel_rect.getWidth(), panel_rect.getHeight()); + panel_rect.setLeftTopAndSize(0, panel_rect.getHeight(), panel_rect.getWidth(), panel_rect.getHeight()); + panel->setRect(panel_rect); + addChild(panel); +} + +//-------------------------------------------------------------------------- +void LLToast::draw() +{ + if(timerHasExpired()) + { + tick(); + } + + LLFloater::draw(); +} + +//-------------------------------------------------------------------------- +void LLToast::setModal(bool modal) +{ + mIsModal = modal; + if(mIsModal) + { + gFocusMgr.setMouseCapture( this ); + gFocusMgr.setTopCtrl( this ); + setFocus(TRUE); + } +} + +//-------------------------------------------------------------------------- +void LLToast::setVisible(BOOL show) +{ + if(show) + { + setBackgroundOpaque(TRUE); + } + LLPanel::setVisible(show); + if(mPanel) + { + if(!mPanel->isDead()) + { + mPanel->setVisible(show); + } + } +} + +//-------------------------------------------------------------------------- +void LLToast::onMouseEnter(S32 x, S32 y, MASK mask) +{ + mOnToastHover(this, MOUSE_ENTER); + + setBackgroundOpaque(TRUE); + if(mCanFade) + { + mTimer.stop(); + } + + sendChildToFront(mHideBtn); + if(mHideBtn && mHideBtn->getEnabled()) + mHideBtn->setVisible(TRUE); + mOnMousEnter(this); +} + +//-------------------------------------------------------------------------- +void LLToast::onMouseLeave(S32 x, S32 y, MASK mask) +{ + mOnToastHover(this, MOUSE_LEAVE); + + if(mCanFade) + { + mTimer.start(); + } + if(mHideBtn && mHideBtn->getEnabled()) + { + if( mHideBtnPressed ) + { + mHideBtnPressed = false; + return; + } + mHideBtn->setVisible(FALSE); + } +} + +//-------------------------------------------------------------------------- + +BOOL LLToast::handleMouseDown(S32 x, S32 y, MASK mask) +{ + if(mHideBtn && mHideBtn->getEnabled()) + { + mHideBtnPressed = mHideBtn->getRect().pointInRect(x, y); + } + + return LLFloater::handleMouseDown(x, y, mask); +} + +//-------------------------------------------------------------------------- +void LLToast::discardNotification() +{ + if(mNotification) + { + mNotification->setIgnored(TRUE); + mNotification->respond(mNotification->getResponseTemplate()); + } +} + +//-------------------------------------------------------------------------- +bool LLToast::getIsNotificationUnResponded() +{ + if(mNotification) + { + return !mNotification->isRespondedTo(); + } + return false; +} + +//-------------------------------------------------------------------------- + + diff --git a/indra/newview/lltoast.h b/indra/newview/lltoast.h new file mode 100644 index 0000000000..969f3fd1cb --- /dev/null +++ b/indra/newview/lltoast.h @@ -0,0 +1,170 @@ +/** + * @file lltoast.h + * @brief This class implements a placeholder for any notification panel. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTOAST_H +#define LL_LLTOAST_H + + +#include "llpanel.h" +#include "llfloater.h" +#include "lltimer.h" +#include "llnotifications.h" + +#include "llviewercontrol.h" + +#define MOUSE_LEAVE false +#define MOUSE_ENTER true + +namespace LLNotificationsUI +{ + +/** + * Represents toast pop-up. + * This is a parent view for all toast panels. + */ +class LLToast : public LLFloater +{ +public: + typedef boost::function toast_callback_t; + typedef boost::signals2::signal toast_signal_t; + + struct Params : public LLInitParam::Block + { + LLPanel* panel; + LLUUID id; //notification or message ID + LLNotificationPtr notification; + F32 timer_period; + toast_callback_t on_toast_destroy; + toast_callback_t on_mouse_enter; + bool can_fade; + bool can_be_stored; + bool enable_hide_btn; + bool is_modal; + bool is_tip; + + Params() : can_fade(true), + can_be_stored(true), + is_modal(false), + is_tip(false), + enable_hide_btn(true), + panel(NULL), + timer_period(gSavedSettings.getS32("NotificationToastTime")) + + {}; + }; + + LLToast(LLToast::Params p); + virtual ~LLToast(); + BOOL postBuild(); + + // Toast handlers + virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); + virtual void onMouseEnter(S32 x, S32 y, MASK mask); + virtual void onMouseLeave(S32 x, S32 y, MASK mask); + + // Operating with toasts + // insert a panel to a toast + void insertPanel(LLPanel* panel); + // get toast's panel + LLPanel* getPanel() { return mPanel; } + // discard notification + void discardNotification(); + // enable/disable Toast's Hide button + void setHideButtonEnabled(bool enabled); + // initialize and start Toast's timer + void setAndStartTimer(F32 period); + // + void resetTimer() { mTimer.start(); } + // + void stopTimer() { mTimer.stop(); } + // + virtual void draw(); + // + virtual void setVisible(BOOL show); + // + virtual void hide(); + + + + // get/set Toast's flags or states + // get information whether the notification corresponding to the toast is responded or not + bool getIsNotificationUnResponded(); + // + void setCanFade(bool can_fade); + // + void setCanBeStored(bool can_be_stored) { mCanBeStored = can_be_stored; } + // + bool getCanBeStored() { return mCanBeStored; } + // + void setModal(bool modal); + + + // Registers callbacks for events + toast_signal_t mOnFade; + toast_signal_t mOnMousEnter; + toast_signal_t mOnToastDestroy; + boost::signals2::connection setOnFadeCallback(toast_callback_t cb) { return mOnFade.connect(cb); } + boost::signals2::connection setOnMouseEnterCallback(toast_callback_t cb) { return mOnMousEnter.connect(cb); } + boost::signals2::connection setOnToastDestroyCallback(toast_callback_t cb) { return mOnToastDestroy.connect(cb); } + + typedef boost::function toast_hover_check_callback_t; + typedef boost::signals2::signal toast_hover_check_signal_t; + toast_hover_check_signal_t mOnToastHover; + boost::signals2::connection setOnToastHoverCallback(toast_hover_check_callback_t cb) { return mOnToastHover.connect(cb); } + + +private: + + // check timer + bool timerHasExpired(); + // on timer finished function + void tick(); + + LLUUID mID; + LLNotificationPtr mNotification; + + LLTimer mTimer; + F32 mTimerValue; + + LLPanel* mPanel; + LLButton* mHideBtn; + + LLColor4 mBgColor; + bool mCanFade; + bool mIsModal; + bool mCanBeStored; + bool mHideBtnEnabled; + bool mHideBtnPressed; +}; + +} +#endif diff --git a/indra/newview/lltoastalertpanel.cpp b/indra/newview/lltoastalertpanel.cpp new file mode 100644 index 0000000000..4309f56710 --- /dev/null +++ b/indra/newview/lltoastalertpanel.cpp @@ -0,0 +1,474 @@ +/** + * @file lltoastalertpanel.cpp + * @brief Panel for alert toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" // must be first include + +#include "linden_common.h" + +#include "llboost.h" + +#include "lltoastalertpanel.h" +#include "llfontgl.h" +#include "lltextbox.h" +#include "llbutton.h" +#include "llcheckboxctrl.h" +#include "llkeyboard.h" +#include "llfocusmgr.h" +#include "lliconctrl.h" +#include "llui.h" +#include "lllineeditor.h" +#include "lluictrlfactory.h" +#include "llnotifications.h" +#include "llfunctorregistry.h" + +const S32 MAX_ALLOWED_MSG_WIDTH = 400; +const F32 DEFAULT_BUTTON_DELAY = 0.5f; +const S32 MSG_PAD = 8; + +/*static*/ LLControlGroup* LLToastAlertPanel::sSettings = NULL; +/*static*/ LLToastAlertPanel::URLLoader* LLToastAlertPanel::sURLLoader; + +//----------------------------------------------------------------------------- +// Private methods + +static const S32 VPAD = 16; +static const S32 HPAD = 25; +static const S32 BTN_HPAD = 8; + +LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal) + : LLToastPanel(notification), + mDefaultOption( 0 ), + mCheck(NULL), + mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH), + mLabel(notification->getName()), + mLineEditor(NULL) +{ + const LLFontGL* font = LLFontGL::getFontSansSerif(); + const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); + const S32 EDITOR_HEIGHT = 20; + + LLNotificationFormPtr form = mNotification->getForm(); + std::string edit_text_name; + std::string edit_text_contents; + bool is_password = false; + + LLToastPanel::setBackgroundVisible(FALSE); + LLToastPanel::setBackgroundOpaque(TRUE); + + + typedef std::vector > options_t; + options_t supplied_options; + + // for now, get LLSD to iterator over form elements + LLSD form_sd = form->asLLSD(); + + S32 option_index = 0; + for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it) + { + std::string type = (*it)["type"].asString(); + if (type == "button") + { + if((*it)["default"]) + { + mDefaultOption = option_index; + } + + supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString())); + + ButtonData data; + if (option_index == mNotification->getURLOption()) + { + data.mURL = mNotification->getURL(); + data.mURLExternal = mNotification->getURLOpenExternally(); + } + + mButtonData.push_back(data); + option_index++; + } + else if (type == "text") + { + edit_text_contents = (*it)["value"].asString(); + edit_text_name = (*it)["name"].asString(); + } + else if (type == "password") + { + edit_text_contents = (*it)["value"].asString(); + edit_text_name = (*it)["name"].asString(); + is_password = true; + } + } + + // Buttons + options_t options; + if (supplied_options.empty()) + { + options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton"))); + + // add data for ok button. + ButtonData ok_button; + mButtonData.push_back(ok_button); + mDefaultOption = 0; + } + else + { + options = supplied_options; + } + + S32 num_options = options.size(); + + // Calc total width of buttons + S32 button_width = 0; + S32 sp = font->getWidth(std::string("OO")); + for( S32 i = 0; i < num_options; i++ ) + { + S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD; + button_width = llmax( w, button_width ); + } + S32 btn_total_width = button_width; + if( num_options > 1 ) + { + btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD); + } + + // Message: create text box using raw string, as text has been structure deliberately + // Use size of created text box to generate dialog box size + std::string msg = mNotification->getMessage(); + llwarns << "Alert: " << msg << llendl; + LLTextBox::Params params; + params.name("Alert message"); + params.font(font); + params.tab_stop(false); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + + LLTextBox * msg_box = LLUICtrlFactory::create (params); + // Compute max allowable height for the dialog text, so we can allocate + // space before wrapping the text to fit. + S32 max_allowed_msg_height = + gFloaterView->getRect().getHeight() + - LINE_HEIGHT // title bar + - 3*VPAD - BTN_HEIGHT; + msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height ); + msg_box->setWrappedText(msg, (F32)MAX_ALLOWED_MSG_WIDTH); + msg_box->reshapeToFitText(); + + const LLRect& text_rect = msg_box->getRect(); + S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD; + S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT; + + if (hasTitleBar()) + { + dialog_height += LINE_HEIGHT; // room for title bar + } + + // it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it + if (!edit_text_name.empty()) + { + dialog_height += EDITOR_HEIGHT + VPAD; + dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f)); + } + + if (mCaution) + { + // Make room for the caution icon. + dialog_width += 32 + HPAD; + } + + LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); + + S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD; + S32 msg_x = HPAD; + if (hasTitleBar()) + { + msg_y -= LINE_HEIGHT; // room for title + } + + static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor"); + static LLUIColor alert_text_color = LLUIColorTable::instance().getColor("AlertTextColor"); + if (mCaution) + { + LLIconCtrl::Params params; + params.name("icon"); + params.rect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32)); + params.mouse_opaque(false); + params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + params.tab_stop(false); + LLIconCtrl * icon = LLUICtrlFactory::create (params); + icon->setValue ("notify_caution_icon.tga"); + icon->setMouseOpaque(FALSE); + LLToastPanel::addChild(icon); + msg_x += 32 + HPAD; + msg_box->setColor( alert_caution_text_color ); + } + else + { + msg_box->setColor( alert_text_color ); + } + + LLRect rect; + rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() ); + msg_box->setRect( rect ); + LLToastPanel::addChild(msg_box); + + // Buttons + S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2; + + for( S32 i = 0; i < num_options; i++ ) + { + LLRect button_rect; + button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ); + + LLButton::Params p; + p.name(options[i].first); + p.rect(button_rect); + p.click_callback.function(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i)); + p.font(font); + p.label(options[i].second); + + LLButton* btn = LLUICtrlFactory::create(p); + mButtonData[i].mButton = btn; + + LLToastPanel::addChild(btn); + + if( i == mDefaultOption ) + { + btn->setFocus(TRUE); + } + + button_left += button_width + BTN_HPAD; + } + + // (Optional) Edit Box + if (!edit_text_name.empty()) + { + S32 y = VPAD + BTN_HEIGHT + VPAD/2; + + LLLineEditor::Params params; + params.name(edit_text_name); + params.rect(LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y)); + params.default_text(edit_text_contents); + params.max_length_bytes(STD_STRING_STR_LEN); + mLineEditor = LLUICtrlFactory::create (params); + + // make sure all edit keys get handled properly (DEV-22396) + mLineEditor->setHandleEditKeysDirectly(TRUE); + + LLToastPanel::addChild(mLineEditor); + } + + if (mLineEditor) + { + mLineEditor->setDrawAsterixes(is_password); + + setEditTextArgs(notification->getSubstitutions()); + } + + std::string ignore_label; + + if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label); + } + else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE) + { + setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label); + } + + // *TODO: check necessity of this code + //gFloaterView->adjustToFitScreen(this, FALSE); + if (mLineEditor) + { + mLineEditor->setFocus(TRUE); + mLineEditor->selectAll(); + } + if(mDefaultOption >= 0) + { + // delay before enabling default button + mDefaultBtnTimer.start(); + mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY); + } +} + +bool LLToastAlertPanel::setCheckBox( const std::string& check_title, const std::string& check_control ) +{ + const LLFontGL* font = LLFontGL::getFontSansSerif(); + const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f); + + // Extend dialog for "check next time" + S32 max_msg_width = LLToastPanel::getRect().getWidth() - 2 * HPAD; + S32 check_width = S32(font->getWidth(check_title) + 0.99f) + 16; + max_msg_width = llmax(max_msg_width, check_width); + S32 dialog_width = max_msg_width + 2 * HPAD; + + S32 dialog_height = LLToastPanel::getRect().getHeight(); + dialog_height += LINE_HEIGHT; + dialog_height += LINE_HEIGHT / 2; + + LLToastPanel::reshape( dialog_width, dialog_height, FALSE ); + + S32 msg_x = (LLToastPanel::getRect().getWidth() - max_msg_width) / 2; + + LLCheckBoxCtrl::Params p; + p.name("check"); + p.rect.left(msg_x).bottom(VPAD+BTN_HEIGHT+LINE_HEIGHT/2).width(max_msg_width).height(LINE_HEIGHT); + p.label(check_title); + p.font(font); + p.commit_callback.function(boost::bind(&LLToastAlertPanel::onClickIgnore, this, _1)); + mCheck = LLUICtrlFactory::create(p); + LLToastPanel::addChild(mCheck); + + return true; +} + +void LLToastAlertPanel::setVisible( BOOL visible ) +{ + // only make the "ding" sound if it's newly visible + if( visible && !LLToastPanel::getVisible() ) + { + make_ui_sound("UISndAlert"); + } + + LLToastPanel::setVisible( visible ); + +} + +LLToastAlertPanel::~LLToastAlertPanel() +{ +} + +BOOL LLToastAlertPanel::hasTitleBar() const +{ + // *TODO: check necessity of this code + /* + return (getCurrentTitle() != "" && getCurrentTitle() != " ") // has title + || isMinimizeable() + || isCloseable(); + */ + return false; +} + +BOOL LLToastAlertPanel::handleKeyHere(KEY key, MASK mask ) +{ + if( KEY_RETURN == key && mask == MASK_NONE ) + { + return TRUE; + } + else if (KEY_RIGHT == key) + { + LLToastPanel::focusNextItem(FALSE); + return TRUE; + } + else if (KEY_LEFT == key) + { + LLToastPanel::focusPrevItem(FALSE); + return TRUE; + } + else if (KEY_TAB == key && mask == MASK_NONE) + { + LLToastPanel::focusNextItem(FALSE); + return TRUE; + } + else if (KEY_TAB == key && mask == MASK_SHIFT) + { + LLToastPanel::focusPrevItem(FALSE); + return TRUE; + } + else + { + return TRUE; + } +} + +// virtual +void LLToastAlertPanel::draw() +{ + // if the default button timer has just expired, activate the default button + if(mDefaultBtnTimer.hasExpired() && mDefaultBtnTimer.getStarted()) + { + mDefaultBtnTimer.stop(); // prevent this block from being run more than once + LLToastPanel::setDefaultBtn(mButtonData[mDefaultOption].mButton); + } + + static LLUIColor shadow_color = LLUIColorTable::instance().getColor("ColorDropShadow"); + static LLUICachedControl shadow_lines ("DropShadowFloater"); + + gl_drop_shadow( 0, LLToastPanel::getRect().getHeight(), LLToastPanel::getRect().getWidth(), 0, + shadow_color, shadow_lines); + + LLToastPanel::draw(); +} + +void LLToastAlertPanel::setEditTextArgs(const LLSD& edit_args) +{ + if (mLineEditor) + { + std::string msg = mLineEditor->getText(); + mLineEditor->setText(msg); + } + else + { + llwarns << "LLToastAlertPanel::setEditTextArgs called on dialog with no line editor" << llendl; + } +} + +void LLToastAlertPanel::onButtonPressed( const LLSD& data, S32 button ) +{ + ButtonData* button_data = &mButtonData[button]; + + LLSD response = mNotification->getResponseTemplate(); + if (mLineEditor) + { + response[mLineEditor->getName()] = mLineEditor->getValue(); + } + response[button_data->mButton->getName()] = true; + + // If we declared a URL and chose the URL option, go to the url + if (!button_data->mURL.empty() && sURLLoader != NULL) + { + sURLLoader->load(button_data->mURL, button_data->mURLExternal); + } + + mNotification->respond(response); // new notification reponse +} + +void LLToastAlertPanel::onClickIgnore(LLUICtrl* ctrl) +{ + // checkbox sometimes means "hide and do the default" and + // other times means "warn me again". Yuck. JC + BOOL check = ctrl->getValue().asBoolean(); + if (mNotification->getForm()->getIgnoreType() == LLNotificationForm::IGNORE_SHOW_AGAIN) + { + // question was "show again" so invert value to get "ignore" + check = !check; + } + mNotification->setIgnored(check); +} diff --git a/indra/newview/lltoastalertpanel.h b/indra/newview/lltoastalertpanel.h new file mode 100644 index 0000000000..af0c9a9ddd --- /dev/null +++ b/indra/newview/lltoastalertpanel.h @@ -0,0 +1,122 @@ +/** + * @file lltoastalertpanel.h + * @brief Panel for alert toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_TOASTALERTPANEL_H +#define LL_TOASTALERTPANEL_H + +#include "lltoastpanel.h" +#include "llfloater.h" +#include "llui.h" +#include "llnotifications.h" + +class LLButton; +class LLCheckBoxCtrl; +class LLAlertDialogTemplate; +class LLLineEditor; + +/** + * Toast panel for alert notification. + * Alerts notifications doesn't require user interaction. + * + * Replaces class LLAlertDialog. + * https://wiki.lindenlab.com/mediawiki/index.php?title=LLAlertDialog&oldid=81388 + */ + +class LLToastAlertPanel + : public LLToastPanel +{ +public: + typedef bool (*display_callback_t)(S32 modal); + + class URLLoader + { + public: + virtual void load(const std::string& url, bool force_open_externally = 0 ) = 0; + virtual ~URLLoader() {} + }; + + static void setURLLoader(URLLoader* loader) + { + sURLLoader = loader; + } + +public: + // User's responsibility to call show() after creating these. + LLToastAlertPanel( LLNotificationPtr notep, bool is_modal ); + + virtual BOOL handleKeyHere(KEY key, MASK mask ); + + virtual void draw(); + virtual void setVisible( BOOL visible ); + + bool setCheckBox( const std::string&, const std::string& ); + void setCaution(BOOL val = TRUE) { mCaution = val; } + // If mUnique==TRUE only one copy of this message should exist + void setUnique(BOOL val = TRUE) { mUnique = val; } + void setEditTextArgs(const LLSD& edit_args); + + void onClickIgnore(LLUICtrl* ctrl); + void onButtonPressed(const LLSD& data, S32 button); + +private: + static std::map sUniqueActiveMap; + + virtual ~LLToastAlertPanel(); + // No you can't kill it. It can only kill itself. + + // Does it have a readable title label, or minimize or close buttons? + BOOL hasTitleBar() const; + +private: + static URLLoader* sURLLoader; + static LLControlGroup* sSettings; + + struct ButtonData + { + LLButton* mButton; + std::string mURL; + U32 mURLExternal; + }; + std::vector mButtonData; + + S32 mDefaultOption; + LLCheckBoxCtrl* mCheck; + BOOL mCaution; + BOOL mUnique; + LLUIString mLabel; + LLFrameTimer mDefaultBtnTimer; + // For Dialogs that take a line as text as input: + LLLineEditor* mLineEditor; + +}; + +#endif // LL_TOASTALERTPANEL_H diff --git a/indra/newview/lltoastgroupnotifypanel.cpp b/indra/newview/lltoastgroupnotifypanel.cpp new file mode 100644 index 0000000000..6f26b4077c --- /dev/null +++ b/indra/newview/lltoastgroupnotifypanel.cpp @@ -0,0 +1,209 @@ +/** + * @file lltoastgroupnotifypanel.cpp + * @brief Panel for group notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltoastgroupnotifypanel.h" + +#include "llfocusmgr.h" + +#include "llbutton.h" +#include "lliconctrl.h" +#include "llnotify.h" +#include "lltextbox.h" +#include "lltexteditor.h" +#include "lluiconstants.h" +#include "llui.h" +#include "llviewercontrol.h" +#include "lltrans.h" +#include "llstyle.h" + +#include "llglheaders.h" +#include "llagent.h" +#include "llavatariconctrl.h" +#include "llfloaterinventory.h" +#include "llinventorytype.h" + +LLToastGroupNotifyPanel::LLToastGroupNotifyPanel(LLNotificationPtr& notification) +: LLToastPanel(notification), + mInventoryOffer(NULL) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_group_notify.xml"); + const LLSD& payload = notification->getPayload(); + LLGroupData groupData; + if (!gAgent.getGroupData(payload["group_id"].asUUID(),groupData)) + { + llwarns << "Group notice for unkown group: " << payload["group_id"].asUUID() << llendl; + } + + static const LLUIColor textColor = LLUIColorTable::instance().getColor("GroupNotifyTextColor"); + + //group icon + LLIconCtrl* pGroupIcon = getChild("group_icon", TRUE); + pGroupIcon->setValue(groupData.mInsigniaID); + + //header title + const std::string& from_name = payload["sender_name"].asString(); + std::stringstream from; + from << from_name << "/" << groupData.mName; + LLTextBox* pTitleText = getChild("title"); + pTitleText->setValue(from.str()); + + //message body + const std::string& subject = payload["subject"].asString(); + const std::string& message = payload["message"].asString(); + + LLTextEditor* pMessageText = getChild("message"); + pMessageText->setValue(""); + pMessageText->setEnabled(FALSE); + + LLStyle::Params date_style; + date_style.color = textColor; + date_style.font.name = "SANSSERIF"; + + LLStyle::Params header_style_params; + header_style_params.color = textColor; + header_style_params.font = LLFontGL::getFontSansSerifBig(); + pMessageText->appendStyledText(subject + "\n",false,false,header_style_params); + + std::string timeStr = "["+LLTrans::getString("UTCTimeWeek")+"],[" + +LLTrans::getString("UTCTimeDay")+"] [" + +LLTrans::getString("UTCTimeMth")+"] [" + +LLTrans::getString("UTCTimeYr")+"] [" + +LLTrans::getString("UTCTimeHr")+"]:[" + +LLTrans::getString("UTCTimeMin")+"]:[" + +LLTrans::getString("UTCTimeSec")+"] [" + +LLTrans::getString("UTCTimeTimezone")+"]"; + const LLDate timeStamp = notification->getDate(); + LLDate notice_date = timeStamp.notNull() ? timeStamp : LLDate::now(); + LLSD substitution; + substitution["datetime"] = (S32) notice_date.secondsSinceEpoch(); + LLStringUtil::format(timeStr, substitution); + LLStyle::Params date_style_params; + date_style_params.color = textColor; + date_style_params.font = LLFontGL::getFontMonospace(); + pMessageText->appendStyledText(timeStr, false, false, date_style); + pMessageText->appendColoredText(std::string("\n\n") + message, false, + false, textColor); + + //attachment + BOOL hasInventory = payload["inventory_offer"].isDefined(); + LLTextBox * pAttachLink = getChild("attachment"); + pAttachLink->setVisible(hasInventory); + if (hasInventory) { + pAttachLink->setValue(payload["inventory_name"]); + mInventoryOffer = new LLOfferInfo(payload["inventory_offer"]); + childSetActionTextbox("attachment", boost::bind( + &LLToastGroupNotifyPanel::onClickAttachment, this)); + + //attachment icon + LLIconCtrl* pAttachIcon = getChild("attachment_icon", TRUE); + LLUIImagePtr attachIconImg = get_item_icon(mInventoryOffer->mType, + LLInventoryType::IT_TEXTURE, + 0, FALSE); + pAttachIcon->setValue(attachIconImg->getName()); + } + + //ok button + LLButton* pOkBtn = getChild("btn_ok"); + pOkBtn->setClickedCallback((boost::bind(&LLToastGroupNotifyPanel::onClickOk, this))); + setDefaultBtn(pOkBtn); +} + + +// virtual +LLToastGroupNotifyPanel::~LLToastGroupNotifyPanel() +{ +} + +void LLToastGroupNotifyPanel::close() +{ + // The group notice dialog may be an inventory offer. + // If it has an inventory save button and that button is still enabled + // Then we need to send the inventory declined message + if(mInventoryOffer != NULL) + { + mInventoryOffer->forceResponse(IOR_DECLINE); + mInventoryOffer = NULL; + } + + die(); +} + +void LLToastGroupNotifyPanel::onClickOk() +{ + LLSD response = mNotification->getResponseTemplate(); + mNotification->respond(response); + close(); +} + +void LLToastGroupNotifyPanel::onClickAttachment() +{ + if (mInventoryOffer != NULL) { + mInventoryOffer->forceResponse(IOR_ACCEPT); + + LLTextBox * pAttachLink = getChild ("attachment"); + static const LLUIColor textColor = LLUIColorTable::instance().getColor( + "GroupNotifyDimmedTextColor"); + pAttachLink->setColor(textColor); + + LLIconCtrl* pAttachIcon = + getChild ("attachment_icon", TRUE); + pAttachIcon->setEnabled(FALSE); + + //if attachment isn't openable - notify about saving + if (!isAttachmentOpenable(mInventoryOffer->mType)) { + LLNotifications::instance().add("AttachmentSaved"); + } + + mInventoryOffer = NULL; + } +} + +//static +bool LLToastGroupNotifyPanel::isAttachmentOpenable(LLAssetType::EType type) +{ + switch(type) + { + case LLAssetType::AT_LANDMARK: + case LLAssetType::AT_FAVORITE: + case LLAssetType::AT_NOTECARD: + case LLAssetType::AT_IMAGE_JPEG: + case LLAssetType::AT_IMAGE_TGA: + case LLAssetType::AT_TEXTURE: + case LLAssetType::AT_TEXTURE_TGA: + return true; + default: + return false; + } +} + diff --git a/indra/newview/lltoastgroupnotifypanel.h b/indra/newview/lltoastgroupnotifypanel.h new file mode 100644 index 0000000000..ba98531251 --- /dev/null +++ b/indra/newview/lltoastgroupnotifypanel.h @@ -0,0 +1,83 @@ +/** + * @file lltoastgroupnotifypanel.h + * @brief Panel for group notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLGROUPNOTIFY_H +#define LL_LLGROUPNOTIFY_H + +#include "llfontgl.h" +#include "lltoastpanel.h" +#include "lldarray.h" +#include "lltimer.h" +#include "llviewermessage.h" +#include "llnotifications.h" + +class LLButton; + +/** + * Toast panel for group notification. + * + * Replaces class LLGroupNotifyBox. + */ +class LLToastGroupNotifyPanel +: public LLToastPanel +{ +public: + void close(); + + static bool onNewNotification(const LLSD& notification); + + + // Non-transient messages. You can specify non-default button + // layouts (like one for script dialogs) by passing various + // numbers in for "layout". + LLToastGroupNotifyPanel(LLNotificationPtr& notification); + + /*virtual*/ ~LLToastGroupNotifyPanel(); +protected: + void onClickOk(); + void onClickAttachment(); +private: + static bool isAttachmentOpenable(LLAssetType::EType); + + LLButton* mSaveInventoryBtn; + + LLUUID mGroupID; + LLOfferInfo* mInventoryOffer; +}; + +// This view contains the stack of notification windows. +//extern LLView* gGroupNotifyBoxView; + +const S32 GROUP_LAYOUT_DEFAULT = 0; +const S32 GROUP_LAYOUT_SCRIPT_DIALOG = 1; + +#endif diff --git a/indra/newview/lltoastimpanel.cpp b/indra/newview/lltoastimpanel.cpp new file mode 100644 index 0000000000..e41181c9e1 --- /dev/null +++ b/indra/newview/lltoastimpanel.cpp @@ -0,0 +1,94 @@ +/** + * @file lltoastimpanel.cpp + * @brief Panel for IM toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" +#include "lltoastimpanel.h" +#include "llimpanel.h" + +const S32 LLToastIMPanel::MAX_MESSAGE_HEIGHT = 50; +const S32 LLToastIMPanel::CAPTION_HEIGHT = 30; +const S32 LLToastIMPanel::TOP_PAD = 5; + +//-------------------------------------------------------------------------- +LLToastIMPanel::LLToastIMPanel(LLToastIMPanel::Params &p) : LLToastPanel(p.notification), + mAvatar(NULL), mUserName(NULL), + mTime(NULL), mMessage(NULL), + mReplyBtn(NULL) +{ + LLUICtrlFactory::getInstance()->buildPanel(this, "panel_instant_message.xml"); + + mAvatar = getChild("avatar"); + mUserName = getChild("user_name"); + mTime = getChild("time_box"); + mMessage = getChild("message"); + mReplyBtn = getChild("reply"); + + mMessage->setValue(p.message); + mAvatar->setValue(p.avatar_id); + mUserName->setValue(p.from); + mTime->setValue(p.time); + mSessionID = p.session_id; + + mReplyBtn->setClickedCallback(boost::bind(&LLToastIMPanel::onClickReplyBtn, this)); + + snapToMessageHeight(); +} + +//-------------------------------------------------------------------------- +LLToastIMPanel::~LLToastIMPanel() +{ +} + +//-------------------------------------------------------------------------- +void LLToastIMPanel::snapToMessageHeight() +{ + S32 required_text_height = mMessage->getTextPixelHeight(); + S32 text_height = llmin(required_text_height, MAX_MESSAGE_HEIGHT); + LLRect text_rect = mMessage->getRect(); + LLRect btn_rect = mReplyBtn->getRect(); + + + mMessage->reshape( text_rect.getWidth(), text_height, TRUE); + mMessage->setValue(mMessage->getText()); + + S32 panel_height = CAPTION_HEIGHT + text_height + btn_rect.getHeight() + TOP_PAD*5; + reshape( getRect().getWidth(), panel_height, TRUE); +} + +//-------------------------------------------------------------------------- +void LLToastIMPanel::onClickReplyBtn() +{ + LLIMFloater::toggle(mSessionID); +} + +//-------------------------------------------------------------------------- + diff --git a/indra/newview/lltoastimpanel.h b/indra/newview/lltoastimpanel.h new file mode 100644 index 0000000000..7f5d6eca1d --- /dev/null +++ b/indra/newview/lltoastimpanel.h @@ -0,0 +1,79 @@ +/** + * @file lltoastimpanel.h + * @brief Panel for IM toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLTOASTIMPANEL_H_ +#define LLTOASTIMPANEL_H_ + + +#include "lltoastpanel.h" +#include "lltextbox.h" +#include "llbutton.h" +#include "llavatariconctrl.h" + + +class LLToastIMPanel: public LLToastPanel +{ +public: + struct Params : public LLInitParam::Block + { + LLNotificationPtr notification; + LLUUID avatar_id; + LLUUID session_id; + std::string from; + std::string time; + std::string message; + + Params() {} + }; + + LLToastIMPanel(LLToastIMPanel::Params &p); + virtual ~LLToastIMPanel(); + +private: + static const S32 MAX_MESSAGE_HEIGHT; + static const S32 CAPTION_HEIGHT; + static const S32 TOP_PAD; + + void onClickReplyBtn(); + void snapToMessageHeight(); + + LLUUID mSessionID; + LLAvatarIconCtrl* mAvatar; + LLTextBox* mUserName; + LLTextBox* mTime; + LLTextBox* mMessage; + LLButton* mReplyBtn; +}; + +#endif // LLTOASTIMPANEL_H_ + + diff --git a/indra/newview/lltoastnotifypanel.cpp b/indra/newview/lltoastnotifypanel.cpp new file mode 100644 index 0000000000..844c54da6a --- /dev/null +++ b/indra/newview/lltoastnotifypanel.cpp @@ -0,0 +1,432 @@ +/** + * @file lltoastnotifypanel.cpp + * @brief Panel for notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltoastnotifypanel.h" +#include "llviewercontrol.h" +#include "lluiconstants.h" +#include "llrect.h" +#include "lliconctrl.h" +#include "lltexteditor.h" +#include "lltextbox.h" +#include "lldbstrings.h" +#include "llchat.h" +#include "llfloaterchat.h" +#include "lltrans.h" +#include "lloverlaybar.h" + + +const S32 BOTTOM_PAD = VPAD * 3; + +//static +const LLFontGL* LLToastNotifyPanel::sFont = NULL; +const LLFontGL* LLToastNotifyPanel::sFontSmall = NULL; + +LLToastNotifyPanel::LLToastNotifyPanel(LLNotificationPtr& notification) : LLToastPanel(notification) { + mIsTip = notification->getType() == "notifytip"; + mNumOptions = 0; + mNumButtons = 0; + mIsScriptDialog = (notification->getName() == "ScriptDialog" + || notification->getName() == "ScriptDialogGroup"); + mAddedDefaultBtn = false; + + // clicking on a button does not steal current focus + setIsChrome(TRUE); + + // class init + if (!sFont) + { + sFont = LLFontGL::getFontSansSerif(); + sFontSmall = LLFontGL::getFontSansSerifSmall(); + } + + // setup paramaters + mMessage = notification->getMessage(); + + // initialize + setFocusRoot(!mIsTip); + + // caution flag can be set explicitly by specifying it in the + // notification payload, or it can be set implicitly if the + // notify xml template specifies that it is a caution + // + // tip-style notification handle 'caution' differently - + // they display the tip in a different color + mIsCaution = notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH; + + LLNotificationFormPtr form(notification->getForm()); + + mNumOptions = form->getNumElements(); + + LLRect rect = mIsTip ? getNotifyTipRect(mMessage) + : getNotifyRect(mNumOptions, mIsScriptDialog, mIsCaution); + setRect(rect); + setFollows(mIsTip ? (FOLLOWS_BOTTOM|FOLLOWS_RIGHT) : (FOLLOWS_TOP|FOLLOWS_RIGHT)); + setBackgroundVisible(FALSE); + setBackgroundOpaque(TRUE); + + LLIconCtrl* icon; + LLTextEditor* text; + + const S32 TOP = getRect().getHeight() - (mIsTip ? (S32)sFont->getLineHeight() : 32); + const S32 BOTTOM = (S32)sFont->getLineHeight(); + S32 x = HPAD + HPAD; + S32 y = TOP; + + LLIconCtrl::Params common_params; + common_params.rect(LLRect(x, y, x+32, TOP-32)); + common_params.mouse_opaque(false); + common_params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP); + + if (mIsTip) + { + // use the tip notification icon + common_params.image(LLUI::getUIImage("notify_tip_icon.tga")); + icon = LLUICtrlFactory::create (common_params); + } + else if (mIsCaution) + { + // use the caution notification icon + common_params.image(LLUI::getUIImage("notify_caution_icon.tga")); + icon = LLUICtrlFactory::create (common_params); + } + else + { + // use the default notification icon + common_params.image(LLUI::getUIImage("notify_box_icon.tga")); + icon = LLUICtrlFactory::create (common_params); + } + + icon->setMouseOpaque(FALSE); + addChild(icon); + + x += HPAD + HPAD + 32; + + // add a caution textbox at the top of a caution notification + LLTextBox* caution_box = NULL; + if (mIsCaution && !mIsTip) + { + S32 caution_height = ((S32)sFont->getLineHeight() * 2) + VPAD; + LLTextBox::Params params; + params.name("caution_box"); + params.rect(LLRect(x, y, getRect().getWidth() - 2, caution_height)); + params.font(sFont); + params.mouse_opaque(false); + params.font.style("BOLD"); + params.text_color(LLUIColorTable::instance().getColor("NotifyCautionWarnColor")); + params.background_color(LLUIColorTable::instance().getColor("NotifyCautionBoxColor")); + params.border_visible(false); + caution_box = LLUICtrlFactory::create (params); + caution_box->setWrappedText(notification->getMessage()); + + addChild(caution_box); + + // adjust the vertical position of the next control so that + // it appears below the caution textbox + y = y - caution_height; + } + else + { + + const S32 BTN_TOP = BOTTOM_PAD + (((mNumOptions-1+2)/3)) * (BTN_HEIGHT+VPAD); + + // Tokenization on \n is handled by LLTextBox + + const S32 MAX_LENGTH = 512 + 20 + + DB_FIRST_NAME_BUF_SIZE + + DB_LAST_NAME_BUF_SIZE + + DB_INV_ITEM_NAME_BUF_SIZE; // For script dialogs: add space for title. + + LLTextEditor::Params params; + params.name("box"); + params.rect(LLRect(x, y, getRect().getWidth()-2, mIsTip ? BOTTOM : BTN_TOP+16)); + params.max_text_length(MAX_LENGTH); + params.default_text(mMessage); + params.font(sFont); + params.embedded_items(false); + params.word_wrap(true); + params.tab_stop(false); + params.mouse_opaque(false); + params.bg_readonly_color(LLColor4::transparent); + params.text_readonly_color(LLUIColorTable::instance().getColor("NotifyTextColor")); + params.enabled(false); + params.hide_border(true); + text = LLUICtrlFactory::create (params); + addChild(text); + } + + if (mIsTip) + { + // TODO: Make a separate archive for these. + LLChat chat(mMessage); + chat.mSourceType = CHAT_SOURCE_SYSTEM; + LLFloaterChat::addChatHistory(chat); + } + else + { + LLButton::Params p; + p.name(std::string("next")); + p.rect(LLRect(getRect().getWidth()-26, BOTTOM_PAD + 20, getRect().getWidth()-2, BOTTOM_PAD)); + p.image_selected.name("notify_next.png"); + p.image_unselected.name("notify_next.png"); + p.font(sFont); + p.scale_image(true); + p.tool_tip(LLTrans::getString("next").c_str()); + + for (S32 i = 0; i < mNumOptions; i++) + { + + LLSD form_element = form->getElement(i); + if (form_element["type"].asString() != "button") + { + continue; + } + + addButton(form_element["name"].asString(), form_element["text"].asString(), TRUE, form_element["default"].asBoolean()); + } + + if (mNumButtons == 0) + { + addButton("OK", LLTrans::getString("ok"), FALSE, TRUE); + mAddedDefaultBtn = true; + } + + + } +} + +LLToastNotifyPanel::~LLToastNotifyPanel() { + std::for_each(mBtnCallbackData.begin(), mBtnCallbackData.end(), DeletePointer()); +} + + +LLRect LLToastNotifyPanel::getNotifyRect(S32 num_options, BOOL mIsScriptDialog, BOOL is_caution) +{ + S32 notify_height = gSavedSettings.getS32("NotifyBoxHeight"); + if (is_caution) + { + // make caution-style dialog taller to accomodate extra text, + // as well as causing the accept/decline buttons to be drawn + // in a different position, to help prevent "quick-click-through" + // of many permissions prompts + notify_height = gSavedSettings.getS32("PermissionsCautionNotifyBoxHeight"); + } + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + + const S32 TOP = getRect().getHeight(); + const S32 RIGHT =getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + if (num_options < 1) + { + num_options = 1; + } + + // Add two "blank" option spaces. + if (mIsScriptDialog) + { + num_options += 2; + } + + S32 additional_lines = (num_options-1) / 3; + + notify_height += additional_lines * (BTN_HEIGHT + VPAD); + + return LLRect(LEFT, TOP, RIGHT, TOP-notify_height); +} + +// static +LLRect LLToastNotifyPanel::getNotifyTipRect(const std::string &utf8message) +{ + S32 line_count = 1; + LLWString message = utf8str_to_wstring(utf8message); + S32 message_len = message.length(); + + const S32 NOTIFY_WIDTH = gSavedSettings.getS32("NotifyBoxWidth"); + // Make room for the icon area. + const S32 text_area_width = NOTIFY_WIDTH - HPAD * 4 - 32; + + const llwchar* wchars = message.c_str(); + const llwchar* start = wchars; + const llwchar* end; + S32 total_drawn = 0; + BOOL done = FALSE; + + do + { + line_count++; + + for (end=start; *end != 0 && *end != '\n'; end++) + ; + + if( *end == 0 ) + { + end = wchars + message_len; + done = TRUE; + } + + S32 remaining = end - start; + while( remaining ) + { + S32 drawn = sFont->maxDrawableChars( start, (F32)text_area_width, remaining, TRUE ); + + if( 0 == drawn ) + { + drawn = 1; // Draw at least one character, even if it doesn't all fit. (avoids an infinite loop) + } + + total_drawn += drawn; + start += drawn; + remaining -= drawn; + + if( total_drawn < message_len ) + { + if( (wchars[ total_drawn ] != '\n') ) + { + // wrap because line was too long + line_count++; + } + } + else + { + done = TRUE; + } + } + + total_drawn++; // for '\n' + end++; + start = end; + } while( !done ); + + const S32 MIN_NOTIFY_HEIGHT = 72; + const S32 MAX_NOTIFY_HEIGHT = 600; + S32 notify_height = llceil((F32) (line_count+1) * sFont->getLineHeight()); + if(gOverlayBar) + { + notify_height += gOverlayBar->getBoundingRect().mTop; + } + else + { + // *FIX: this is derived from the padding caused by the + // rounded rects, shouldn't be a const here. + notify_height += 10; + } + notify_height += VPAD; + notify_height = llclamp(notify_height, MIN_NOTIFY_HEIGHT, MAX_NOTIFY_HEIGHT); + + const S32 RIGHT = getRect().getWidth(); + const S32 LEFT = RIGHT - NOTIFY_WIDTH; + + return LLRect(LEFT, notify_height, RIGHT, 0); +} + + +// static +void LLToastNotifyPanel::onClickButton(void* data) +{ + InstanceAndS32* self_and_button = (InstanceAndS32*)data; + LLToastNotifyPanel* self = self_and_button->mSelf; + std::string button_name = self_and_button->mButtonName; + + LLSD response = self->mNotification->getResponseTemplate(); + if (!self->mAddedDefaultBtn && !button_name.empty()) + { + response[button_name] = true; + } + self->mNotification->respond(response); +} + +// virtual +LLButton* LLToastNotifyPanel::addButton(const std::string& name, const std::string& label, BOOL is_option, BOOL is_default) +{ + // make caution notification buttons slightly narrower + // so that 3 of them can fit without overlapping the "next" button + S32 btn_width = mIsCaution? 84 : 90; + + LLRect btn_rect; + LLButton* btn; + S32 btn_height= BTN_HEIGHT; + const LLFontGL* font = sFont; + S32 ignore_pad = 0; + S32 button_index = mNumButtons; + S32 index = button_index; + S32 x = (HPAD * 4) + 32; + + if (mIsScriptDialog) + { + // Add two "blank" option spaces, before the "Ignore" button + index = button_index + 2; + if (button_index == 0) + { + // Ignore button is smaller, less wide + btn_height = BTN_HEIGHT_SMALL; + font = sFontSmall; + ignore_pad = 10; + } + } + + btn_rect.setOriginAndSize(x + (index % 3) * (btn_width+HPAD+HPAD) + ignore_pad, + BOTTOM_PAD + (index / 3) * (BTN_HEIGHT+VPAD), + btn_width - 2*ignore_pad, + btn_height); + + InstanceAndS32* userdata = new InstanceAndS32; + userdata->mSelf = this; + userdata->mButtonName = is_option ? name : ""; + + mBtnCallbackData.push_back(userdata); + + LLButton::Params p; + p.name(name); + p.label(label); + p.rect(btn_rect); + p.click_callback.function(boost::bind(&LLToastNotifyPanel::onClickButton, userdata)); + p.font(font); + if (mIsCaution) + { + p.image_color(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + p.image_color_disabled(LLUIColorTable::instance().getColor("ButtonCautionImageColor")); + } + btn = LLUICtrlFactory::create(p); + + + addChild(btn, -1); + + if (is_default) + { + setDefaultBtn(btn); + } + + mNumButtons++; + return btn; +} diff --git a/indra/newview/lltoastnotifypanel.h b/indra/newview/lltoastnotifypanel.h new file mode 100644 index 0000000000..df58c06f25 --- /dev/null +++ b/indra/newview/lltoastnotifypanel.h @@ -0,0 +1,86 @@ +/** + * @file lltoastnotifypanel.h + * @brief Panel for notify toasts. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLTOASTNOTIFYPANEL_H_ +#define LLTOASTNOTIFYPANEL_H_ + +#include "llpanel.h" +#include "llfontgl.h" +#include "llnotifications.h" +#include "llbutton.h" +#include "lltoastpanel.h" + + +/** + * Toast panel for notification. + * Notification panel should be used for notifications that require a response from the user. + * + * Replaces class LLNotifyBox. + */ +class LLToastNotifyPanel: public LLToastPanel { +public: + LLToastNotifyPanel(LLNotificationPtr&); + virtual ~LLToastNotifyPanel(); + bool isTip() {return mIsTip;} + static LLToastNotifyPanel * buildNotifyPanel(LLNotificationPtr notification); + +protected: + LLButton* addButton(std::string const &name, const std::string& label, BOOL is_option, BOOL is_default); + // Used for callbacks + struct InstanceAndS32 + { + LLToastNotifyPanel* mSelf; + std::string mButtonName; + }; + std::vector mBtnCallbackData; + +private: + + // Returns the rect, relative to gNotifyView, where this + // notify box should be placed. + LLRect getNotifyRect(S32 num_options, BOOL layout_script_dialog, BOOL is_caution); + LLRect getNotifyTipRect(const std::string &message); + // internal handler for button being clicked + static void onClickButton(void* data); + bool mIsTip; + bool mAddedDefaultBtn; + bool mIsScriptDialog; + bool mIsCaution; // is this a caution notification? + std::string mMessage; + S32 mNumOptions; + S32 mNumButtons; + + static const LLFontGL* sFont; + static const LLFontGL* sFontSmall; +}; + +#endif /* LLTOASTNOTIFYPANEL_H_ */ diff --git a/indra/newview/lltoastpanel.cpp b/indra/newview/lltoastpanel.cpp new file mode 100644 index 0000000000..28052a33be --- /dev/null +++ b/indra/newview/lltoastpanel.cpp @@ -0,0 +1,53 @@ +/** + * @file lltoastpanel.cpp + * @brief Creates a panel of a specific kind for a toast + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lltoastpanel.h" + +LLToastPanel::LLToastPanel(LLNotificationPtr& notification) +{ + mNotification = notification; +} + +LLToastPanel::~LLToastPanel() +{ +} + +std::string LLToastPanel::getTitle() +{ + // *TODO: create Title and localize it. If it will be required. + return mNotification->getMessage(); +} + + + diff --git a/indra/newview/lltoastpanel.h b/indra/newview/lltoastpanel.h new file mode 100644 index 0000000000..2258eca273 --- /dev/null +++ b/indra/newview/lltoastpanel.h @@ -0,0 +1,58 @@ +/** + * @file lltoastpanel.h + * @brief Creates a panel of a specific kind for a toast. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLTOASTPANEL_H +#define LL_LLTOASTPANEL_H + +#include "llpanel.h" +#include "llnotifications.h" + +#include + +/** + * Base class for all panels that can be added to the toast. + * All toast panels should contain necessary logic for representing certain notification + * but shouldn't contain logic related to this panel lifetime control and positioning + * on the parent view. + */ +class LLToastPanel: public LLPanel { +public: + LLToastPanel(LLNotificationPtr&); + virtual ~LLToastPanel() = 0; + + virtual std::string getTitle(); + virtual const LLUUID& getID() { return mNotification->id();} +protected: + LLNotificationPtr mNotification; +}; + +#endif /* LL_TOASTPANEL_H */ diff --git a/indra/newview/lltool.cpp b/indra/newview/lltool.cpp index 6a3ada0474..7b058e9efa 100644 --- a/indra/newview/lltool.cpp +++ b/indra/newview/lltool.cpp @@ -91,7 +91,7 @@ BOOL LLTool::handleMouseUp(S32 x, S32 y, MASK mask) BOOL LLTool::handleHover(S32 x, S32 y, MASK mask) { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); lldebugst(LLERR_USER_INPUT) << "hover handled by a tool" << llendl; // by default, do nothing, say we handled it return TRUE; diff --git a/indra/newview/lltoolbar.cpp b/indra/newview/lltoolbar.cpp index 33edb3ef27..5478e0005a 100644 --- a/indra/newview/lltoolbar.cpp +++ b/indra/newview/lltoolbar.cpp @@ -36,20 +36,23 @@ #include "lltoolbar.h" #include "imageids.h" +#include "llfloaterreg.h" #include "llfontgl.h" +#include "llflyoutbutton.h" #include "llrect.h" #include "llparcel.h" #include "llagent.h" +#include "llagentwearables.h" #include "llbutton.h" #include "llfocusmgr.h" #include "llviewercontrol.h" #include "llmenucommands.h" #include "llimview.h" #include "lluiconstants.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "lltooldraganddrop.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llfloaterchatterbox.h" #include "llfloaterfriends.h" #include "llfloatersnapshot.h" @@ -57,6 +60,9 @@ #include "llui.h" #include "llviewermenu.h" #include "llfirstuse.h" +#include "llscrolllistctrl.h" +#include "llscrolllistitem.h" +#include "llscrolllistcell.h" #include "llviewerparcelmgr.h" #include "lluictrlfactory.h" #include "llviewerwindow.h" @@ -65,29 +71,12 @@ #include "llfloaterchat.h" #include "llfloatermute.h" #include "llimpanel.h" -#include "llscrolllistctrl.h" +#include "lllayoutstack.h" #if LL_DARWIN #include "llresizehandle.h" - // This class draws like an LLResizeHandle but has no interactivity. - // It's just there to provide a cue to the user that the lower right corner of the window functions as a resize handle. - class LLFakeResizeHandle : public LLResizeHandle - { - public: - LLFakeResizeHandle(const std::string& name, const LLRect& rect, S32 min_width, S32 min_height, ECorner corner = RIGHT_BOTTOM ) - : LLResizeHandle(name, rect, min_width, min_height, corner ) - { - - } - - virtual BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; - virtual BOOL handleMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; - - }; - #endif // LL_DARWIN // @@ -95,7 +84,6 @@ // LLToolBar *gToolBar = NULL; -S32 TOOL_BAR_HEIGHT = 20; // // Statics @@ -114,44 +102,13 @@ LLToolBar::LLToolBar() { setIsChrome(TRUE); setFocusRoot(TRUE); + + mCommitCallbackRegistrar.add("HandleCommunicate", &LLToolBar::onClickCommunicate); } BOOL LLToolBar::postBuild() { - childSetCommitCallback("communicate_btn", onClickCommunicate, this); - childSetControlName("communicate_btn", "ShowCommunicate"); - - childSetAction("chat_btn", onClickChat, this); - childSetControlName("chat_btn", "ChatVisible"); - - childSetAction("appearance_btn", onClickAppearance, this); - childSetControlName("appearance_btn", ""); - - childSetAction("fly_btn", onClickFly, this); - childSetControlName("fly_btn", "FlyBtnState"); - - childSetAction("sit_btn", onClickSit, this); - childSetControlName("sit_btn", "SitBtnState"); - - childSetAction("snapshot_btn", onClickSnapshot, this); - childSetControlName("snapshot_btn", ""); - - childSetAction("directory_btn", onClickDirectory, this); - childSetControlName("directory_btn", "ShowDirectory"); - - childSetAction("build_btn", onClickBuild, this); - childSetControlName("build_btn", "BuildBtnState"); - - childSetAction("radar_btn", onClickRadar, this); - childSetControlName("radar_btn", "ShowMiniMap"); - - childSetAction("map_btn", onClickMap, this); - childSetControlName("map_btn", "ShowWorldMap"); - - childSetAction("inventory_btn", onClickInventory, this); - childSetControlName("inventory_btn", "ShowInventory"); - for (child_list_const_iter_t child_iter = getChildList()->begin(); child_iter != getChildList()->end(); ++child_iter) { @@ -167,8 +124,14 @@ BOOL LLToolBar::postBuild() if(mResizeHandle == NULL) { LLRect rect(0, 0, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT); - mResizeHandle = new LLFakeResizeHandle(std::string(""), rect, RESIZE_HANDLE_WIDTH, RESIZE_HANDLE_HEIGHT); - this->addChildAtEnd(mResizeHandle); + LLResizeHandle::Params p; + p.name(""); + p.rect(rect); + p.min_width(RESIZE_HANDLE_WIDTH); + p.min_height(RESIZE_HANDLE_HEIGHT); + p.enabled(false); + mResizeHandle = LLUICtrlFactory::create(p); + addChildInBack(mResizeHandle); LLLayoutStack* toolbar_stack = getChild("toolbar_stack"); toolbar_stack->reshape(toolbar_stack->getRect().getWidth() - RESIZE_HANDLE_WIDTH, toolbar_stack->getRect().getHeight()); } @@ -194,20 +157,23 @@ BOOL LLToolBar::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, LLButton* inventory_btn = getChild("inventory_btn"); if (!inventory_btn) return FALSE; - LLInventoryView* active_inventory = LLInventoryView::getActiveInventory(); + LLFloaterInventory* active_inventory = LLFloaterInventory::getActiveInventory(); + + LLRect button_screen_rect; + inventory_btn->localRectToScreen(inventory_btn->getRect(),&button_screen_rect); if(active_inventory && active_inventory->getVisible()) { mInventoryAutoOpen = FALSE; } - else if (inventory_btn->getRect().pointInRect(x, y)) + else if (button_screen_rect.pointInRect(x, y)) { if (mInventoryAutoOpen) { if (!(active_inventory && active_inventory->getVisible()) && mInventoryAutoOpenTimer.getElapsedTimeF32() > sInventoryAutoOpenTime) { - LLInventoryView::showAgentInventory(); + LLFloaterInventory::showAgentInventory(); } } else @@ -287,21 +253,37 @@ void LLToolBar::refresh() BOOL sitting = FALSE; if (gAgent.getAvatarObject()) { - sitting = gAgent.getAvatarObject()->mIsSitting; + sitting = gAgent.getAvatarObject()->isSitting(); } - childSetEnabled("fly_btn", (gAgent.canFly() || gAgent.getFlying()) && !sitting ); - - childSetEnabled("build_btn", LLViewerParcelMgr::getInstance()->agentCanBuild() ); + if (!gAgent.canFly()) + { + gSavedSettings.setBOOL("FlyBtnEnabled", gAgent.getFlying() ? true : false); + gSavedSettings.setBOOL("FlyBtnState", false); + } + else + { + gSavedSettings.setBOOL("FlyBtnEnabled", sitting ? false : true); + } // Check to see if we're in build mode - BOOL build_mode = LLToolMgr::getInstance()->inEdit(); - // And not just clicking on a scripted object - if (LLToolGrab::getInstance()->getHideBuildHighlight()) + bool build_enabled = LLToolMgr::getInstance()->canEdit(); + if (build_enabled) + { + gSavedSettings.setBOOL("BuildBtnEnabled", true); + bool build_mode = LLToolMgr::getInstance()->inEdit(); + // HACK: Not in mouselook and not just clicking on a scripted object + if (gAgent.cameraMouselook() || LLToolGrab::getInstance()->getHideBuildHighlight()) { build_mode = FALSE; } gSavedSettings.setBOOL("BuildBtnState", build_mode); + } + else + { + gSavedSettings.setBOOL("BuildBtnEnabled", false); + gSavedSettings.setBOOL("BuildBtnState", false); + } if (isInVisibleChain()) { @@ -319,30 +301,42 @@ void LLToolBar::updateCommunicateList() LLFloater* frontmost_floater = LLFloaterChatterBox::getInstance()->getActiveFloater(); LLScrollListItem* itemp = NULL; - itemp = communicate_button->add(LLFloaterMyFriends::getInstance()->getShortTitle(), LLSD("contacts"), ADD_TOP); + LLSD contact_sd; + contact_sd["value"] = "contacts"; + contact_sd["columns"][0]["value"] = LLFloaterMyFriends::getInstance()->getShortTitle(); if (LLFloaterMyFriends::getInstance() == frontmost_floater) { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); + contact_sd["columns"][0]["font"]["style"] = "BOLD"; // make sure current tab is selected in list if (selected.isUndefined()) { - selected = itemp->getValue(); + selected = "contacts"; } } - itemp = communicate_button->add(LLFloaterChat::getInstance()->getShortTitle(), LLSD("local chat"), ADD_TOP); + itemp = communicate_button->addElement(contact_sd, ADD_TOP); + + LLSD communicate_sd; + communicate_sd["value"] = "local chat"; + communicate_sd["columns"][0]["value"] = LLFloaterChat::getInstance()->getShortTitle(); + if (LLFloaterChat::getInstance() == frontmost_floater) { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); + communicate_sd["columns"][0]["font"]["style"] = "BOLD"; if (selected.isUndefined()) { - selected = itemp->getValue(); + selected = "local chat"; } } + itemp = communicate_button->addElement(communicate_sd, ADD_TOP); + communicate_button->addSeparator(ADD_TOP); communicate_button->add(getString("Redock Windows"), LLSD("redock"), ADD_TOP); communicate_button->addSeparator(ADD_TOP); - communicate_button->add(LLFloaterMute::getInstance()->getShortTitle(), LLSD("mute list"), ADD_TOP); - + LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance("mute"); + if(mute_instance) + { + communicate_button->add(mute_instance->getShortTitle(), LLSD("mute list"), ADD_TOP); + } std::set >::const_iterator floater_handle_it; if (gIMMgr->getIMFloaterHandles().size() > 0) @@ -357,165 +351,79 @@ void LLToolBar::updateCommunicateList() { std::string floater_title = im_floaterp->getNumUnreadMessages() > 0 ? "*" : ""; floater_title.append(im_floaterp->getShortTitle()); - itemp = communicate_button->add(floater_title, im_floaterp->getSessionID(), ADD_TOP); + LLSD im_sd; + im_sd["value"] = im_floaterp->getSessionID(); + im_sd["columns"][0]["value"] = floater_title; if (im_floaterp == frontmost_floater) { - ((LLScrollListText*)itemp->getColumn(0))->setFontStyle(LLFontGL::BOLD); + im_sd["columns"][0]["font"]["style"] = "BOLD"; if (selected.isUndefined()) { - selected = itemp->getValue(); + selected = im_floaterp->getSessionID(); } } + itemp = communicate_button->addElement(im_sd, ADD_TOP); } } - communicate_button->setToggleState(gSavedSettings.getBOOL("ShowCommunicate")); communicate_button->setValue(selected); } // static -void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, void* user_data) +void LLToolBar::onClickCommunicate(LLUICtrl* ctrl, const LLSD& user_data) { - LLToolBar* toolbar = (LLToolBar*)user_data; - LLFlyoutButton* communicate_button = toolbar->getChild("communicate_btn"); + LLFlyoutButton* communicate_button = dynamic_cast(ctrl); + llassert_always(communicate_button); LLSD selected_option = communicate_button->getValue(); if (selected_option.asString() == "contacts") { - LLFloaterMyFriends::showInstance(); + LLFloaterReg::showInstance("contacts", "friends"); } else if (selected_option.asString() == "local chat") { - LLFloaterChat::showInstance(); + LLFloaterReg::showInstance("communicate", "local"); } else if (selected_option.asString() == "redock") { - LLFloaterChatterBox::getInstance()->addFloater(LLFloaterMyFriends::getInstance(), FALSE); - LLFloaterChatterBox::getInstance()->addFloater(LLFloaterChat::getInstance(), FALSE); - LLUUID session_to_show; - - std::set >::const_iterator floater_handle_it; - for(floater_handle_it = gIMMgr->getIMFloaterHandles().begin(); floater_handle_it != gIMMgr->getIMFloaterHandles().end(); ++floater_handle_it) + LLFloaterChatterBox* chatterbox_instance = LLFloaterChatterBox::getInstance(); + if(chatterbox_instance) { - LLFloater* im_floaterp = floater_handle_it->get(); - if (im_floaterp) + chatterbox_instance->addFloater(LLFloaterMyFriends::getInstance(), FALSE); + chatterbox_instance->addFloater(LLFloaterChat::getInstance(), FALSE); + + LLUUID session_to_show; + + std::set >::const_iterator floater_handle_it; + for(floater_handle_it = gIMMgr->getIMFloaterHandles().begin(); floater_handle_it != gIMMgr->getIMFloaterHandles().end(); ++floater_handle_it) { - if (im_floaterp->isFrontmost()) + LLFloater* im_floaterp = floater_handle_it->get(); + if (im_floaterp) { - session_to_show = ((LLFloaterIMPanel*)im_floaterp)->getSessionID(); + if (im_floaterp->isFrontmost()) + { + session_to_show = ((LLFloaterIMPanel*)im_floaterp)->getSessionID(); + } + chatterbox_instance->addFloater(im_floaterp, FALSE); } - LLFloaterChatterBox::getInstance()->addFloater(im_floaterp, FALSE); } + LLFloaterReg::showInstance("communicate", session_to_show); } - - LLFloaterChatterBox::showInstance(session_to_show); } else if (selected_option.asString() == "mute list") { - LLFloaterMute::showInstance(); + LLFloaterReg::showInstance("mute"); } else if (selected_option.isUndefined()) // user just clicked the communicate button, treat as toggle { - if (LLFloaterChatterBox::getInstance()->getFloaterCount() == 0) - { - LLFloaterMyFriends::toggleInstance(); + LLFloaterReg::toggleInstance("communicate"); } - else - { - LLFloaterChatterBox::toggleInstance(); - } - } - else // otherwise selection_option is a specific IM session id + else // otherwise selection_option is undifined or a specific IM session id { - LLFloaterChatterBox::showInstance(selected_option); + LLFloaterReg::showInstance("communicate", selected_option); } } -// static -void LLToolBar::onClickChat(void* user_data) -{ - handle_chat(NULL); -} - -// static -void LLToolBar::onClickAppearance(void*) -{ - if (gAgent.areWearablesLoaded()) - { - gAgent.changeCameraToCustomizeAvatar(); - } -} - - -// static -void LLToolBar::onClickFly(void*) -{ - gAgent.toggleFlying(); -} - - -// static -void LLToolBar::onClickSit(void*) -{ - if (!(gAgent.getControlFlags() & AGENT_CONTROL_SIT_ON_GROUND)) - { - // sit down - gAgent.setFlying(FALSE); - gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); - - // Might be first sit - LLFirstUse::useSit(); - } - else - { - // stand up - gAgent.setFlying(FALSE); - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); - } -} - - -// static -void LLToolBar::onClickSnapshot(void*) -{ - LLFloaterSnapshot::show (0); -} - - -// static -void LLToolBar::onClickDirectory(void*) -{ - handle_find(NULL); -} - - -// static -void LLToolBar::onClickBuild(void*) -{ - toggle_build_mode(); -} - - -// static -void LLToolBar::onClickRadar(void*) -{ - handle_mini_map(NULL); -} - - -// static -void LLToolBar::onClickMap(void*) -{ - handle_map(NULL); -} - - -// static -void LLToolBar::onClickInventory(void*) -{ - handle_inventory(NULL); -} - diff --git a/indra/newview/lltoolbar.h b/indra/newview/lltoolbar.h index 094d016e39..954c6270a6 100644 --- a/indra/newview/lltoolbar.h +++ b/indra/newview/lltoolbar.h @@ -37,12 +37,7 @@ #include "llframetimer.h" -// "Constants" loaded from settings.xml at start time -extern S32 TOOL_BAR_HEIGHT; - -#if LL_DARWIN - class LLFakeResizeHandle; -#endif // LL_DARWIN +class LLResizeHandle; class LLToolBar : public LLPanel @@ -71,17 +66,7 @@ public: void refresh(); // callbacks - static void onClickCommunicate(LLUICtrl*, void*); - static void onClickChat(void* data); - static void onClickAppearance(void* data); - static void onClickFly(void*); - static void onClickSit(void*); - static void onClickSnapshot(void* data); - static void onClickDirectory(void* data); - static void onClickBuild(void* data); - static void onClickRadar(void* data); - static void onClickMap(void* data); - static void onClickInventory(void* data); + static void onClickCommunicate(LLUICtrl*, const LLSD&); static F32 sInventoryAutoOpenTime; @@ -94,7 +79,7 @@ private: LLFrameTimer mInventoryAutoOpenTimer; S32 mNumUnreadIMs; #if LL_DARWIN - LLFakeResizeHandle *mResizeHandle; + LLResizeHandle *mResizeHandle; #endif // LL_DARWIN }; diff --git a/indra/newview/lltoolbrush.cpp b/indra/newview/lltoolbrush.cpp index c42693d03f..0088a6a2a4 100644 --- a/indra/newview/lltoolbrush.cpp +++ b/indra/newview/lltoolbrush.cpp @@ -412,7 +412,7 @@ BOOL LLToolBrushLand::handleHover( S32 x, S32 y, MASK mask ) mMouseX = x; mMouseY = y; mGotHover = TRUE; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLLAND); + gViewerWindow->setCursor(UI_CURSOR_TOOLLAND); return TRUE; } diff --git a/indra/newview/lltoolcomp.cpp b/indra/newview/lltoolcomp.cpp index b6090bc986..fff18df442 100644 --- a/indra/newview/lltoolcomp.cpp +++ b/indra/newview/lltoolcomp.cpp @@ -34,6 +34,7 @@ #include "lltoolcomp.h" +#include "llfloaterreg.h" #include "llgl.h" #include "indra_constants.h" @@ -295,7 +296,7 @@ BOOL LLToolCompTranslate::handleDoubleClick(S32 x, S32 y, MASK mask) { // You should already have an object selected from the mousedown. // If so, show its properties - gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); + LLFloaterReg::showInstance("build", "Content"); return TRUE; } // Nothing selected means the first mouse click was probably @@ -412,8 +413,7 @@ BOOL LLToolCompScale::handleDoubleClick(S32 x, S32 y, MASK mask) { // You should already have an object selected from the mousedown. // If so, show its properties - gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); - //gBuildView->setPropertiesPanelOpen(TRUE); + LLFloaterReg::showInstance("build", "Content"); return TRUE; } else @@ -610,8 +610,7 @@ BOOL LLToolCompRotate::handleDoubleClick(S32 x, S32 y, MASK mask) { // You should already have an object selected from the mousedown. // If so, show its properties - gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); - //gBuildView->setPropertiesPanelOpen(TRUE); + LLFloaterReg::showInstance("build", "Content"); return TRUE; } else @@ -766,10 +765,6 @@ void LLToolCompGun::onMouseCaptureLost() return; } mCur->onMouseCaptureLost(); - - // JC - I don't know if this is necessary. Maybe we could lose capture - // if someone ALT-Tab's out when in mouselook. - setCurrentTool( (LLTool*) mGun ); } void LLToolCompGun::handleSelect() diff --git a/indra/newview/lltoolcomp.h b/indra/newview/lltoolcomp.h index b24ba25d5a..81ed0ba8e4 100644 --- a/indra/newview/lltoolcomp.h +++ b/indra/newview/lltoolcomp.h @@ -229,6 +229,7 @@ public: virtual void onMouseCaptureLost(); virtual void handleSelect(); virtual void handleDeselect(); + virtual LLTool* getOverrideTool(MASK mask) { return NULL; } protected: LLToolGun* mGun; diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 156093a21a..c58457d599 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -35,10 +35,12 @@ #include "message.h" #include "lltooldraganddrop.h" +#include "llfloaterreg.h" #include "llinstantmessage.h" #include "lldir.h" #include "llagent.h" +#include "llagentwearables.h" #include "llviewercontrol.h" #include "llfirstuse.h" #include "llfloater.h" @@ -47,8 +49,8 @@ #include "llgesturemgr.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llinventoryview.h" #include "llmutelist.h" #include "llnotify.h" #include "llpreviewnotecard.h" @@ -56,19 +58,20 @@ #include "lltoolmgr.h" #include "lltrans.h" #include "llui.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvolume.h" #include "llworld.h" #include "object_flags.h" #include "llimview.h" - +#include "llrootview.h" +#include "llagentui.h" // MAX ITEMS is based on (sizeof(uuid)+2) * count must be < MTUBYTES // or 18 * count < 1200 => count < 1200/18 => 66. I've cut it down a @@ -383,8 +386,8 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT] { &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF - &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR - &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT + &LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR + &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT &LLToolDragAndDrop::dad3dNULL, // Dest: DT_LAND }, // Source: DAD_LANDMARK @@ -469,6 +472,14 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT] &LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND }, + // Source: DAD_LINK + { + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_AVATAR + &LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT + &LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND + }, }; LLToolDragAndDrop::LLToolDragAndDrop() @@ -846,7 +857,7 @@ void LLToolDragAndDrop::dragOrDrop( S32 x, S32 y, MASK mask, BOOL drop, { handled = TRUE; - LLView* root_view = gViewerWindow->getRootView(); + LLRootView* root_view = gViewerWindow->getRootView(); for (mCurItemIndex = 0; mCurItemIndex < (S32)mCargoIDs.size(); mCurItemIndex++) { @@ -1142,7 +1153,7 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, { return; } - LLViewerImage* image = gImageList.getImage(asset_id); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT ); S32 num_faces = hit_obj->getNumTEs(); for( S32 face = 0; face < num_faces; face++ ) @@ -1160,7 +1171,7 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj, void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item) { if (hit_face == -1) return; - LLViewerImage* image = gImageList.getImage(item->getAssetUUID()); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(item->getAssetUUID()); avatar->userSetOptionalTE( hit_face, image); } @@ -1185,7 +1196,7 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj, return; } // update viewer side image in anticipation of update from simulator - LLViewerImage* image = gImageList.getImage(asset_id); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id); LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT ); hit_obj->setTEImage(hit_face, image); dialog_refresh_all(); @@ -1461,10 +1472,10 @@ void LLToolDragAndDrop::dropInventory(LLViewerObject* hit_obj, } } hit_obj->updateInventory(new_item, TASK_INVENTORY_ITEM_KEY, true); - if (gFloaterTools->getVisible()) + if (LLFloaterReg::instanceVisible("build")) { // *FIX: only show this if panel not expanded? - gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); + LLFloaterReg::showInstance("build", "Content"); } // VEFFECT: AddToInventory @@ -1551,7 +1562,7 @@ void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent, { if(!item) return; std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); LLUUID transaction_id; transaction_id.generate(); const S32 BUCKET_SIZE = sizeof(U8) + UUID_BYTES; @@ -1594,6 +1605,8 @@ void LLToolDragAndDrop::commitGiveInventoryItem(const LLUUID& to_agent, gIMMgr->addSystemMessage(im_session_id, "inventory_item_offered", args); } + // add buddy to recent people list + LLRecentPeople::instance().add(to_agent); } void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent, @@ -1718,6 +1731,9 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, llinfos << "LLToolDragAndDrop::commitGiveInventoryCategory() - " << cat->getUUID() << llendl; + // add buddy to recent people list + LLRecentPeople::instance().add(to_agent); + // Test out how many items are being given. LLViewerInventoryCategory::cat_array_t cats; LLViewerInventoryItem::item_array_t items; @@ -1745,7 +1761,7 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent, else { std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); LLUUID transaction_id; transaction_id.generate(); S32 bucket_size = (sizeof(U8) + UUID_BYTES) * (count + 1); @@ -1827,7 +1843,7 @@ BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item) BOOL copyable = FALSE; if(item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE; - LLVOAvatar* my_avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* my_avatar = gAgent.getAvatarObject(); if(!my_avatar) { return FALSE; @@ -1836,9 +1852,6 @@ BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item) BOOL acceptable = TRUE; switch(item->getType()) { - case LLAssetType::AT_CALLINGCARD: - acceptable = FALSE; - break; case LLAssetType::AT_OBJECT: if(my_avatar->isWearingAttachment(item->getUUID())) { @@ -1847,7 +1860,7 @@ BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item) break; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: - if(!copyable && gAgent.isWearingItem(item->getUUID())) + if(!copyable && gAgentWearables.isWearingItem(item->getUUID())) { acceptable = FALSE; } @@ -1877,7 +1890,7 @@ BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item) return FALSE; } - LLVOAvatar* my_avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* my_avatar = gAgent.getAvatarObject(); if(!my_avatar) { return FALSE; @@ -1886,11 +1899,8 @@ BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item) BOOL acceptable = TRUE; switch(item->getType()) { - case LLAssetType::AT_CALLINGCARD: - acceptable = FALSE; - break; case LLAssetType::AT_OBJECT: - if(my_avatar->isWearingAttachment(item->getUUID())) + if(my_avatar->isWearingAttachment(item->getUUID(), TRUE)) { acceptable = FALSE; } @@ -1924,7 +1934,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL // gAgent.getGroupID()) // && (obj->mPermModify || obj->mFlagAllowInventoryAdd)); BOOL worn = FALSE; - LLVOAvatar* my_avatar = NULL; + LLVOAvatarSelf* my_avatar = NULL; switch(item->getType()) { case LLAssetType::AT_OBJECT: @@ -1936,7 +1946,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL break; case LLAssetType::AT_BODYPART: case LLAssetType::AT_CLOTHING: - if(gAgent.isWearingItem(item->getUUID())) + if(gAgentWearables.isWearingItem(item->getUUID())) { worn = TRUE; } @@ -1991,6 +2001,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ case DAD_BODYPART: case DAD_ANIMATION: case DAD_GESTURE: + case DAD_CALLINGCARD: { LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data; if(gInventory.getItem(inv_item->getUUID()) @@ -2035,7 +2046,6 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_ } break; } - case DAD_CALLINGCARD: default: *accept = ACCEPT_NO; break; @@ -2080,7 +2090,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv( } // must not be already wearing it - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if( !avatar || avatar->isWearingAttachment(item->getUUID()) ) { return ACCEPT_NO; @@ -2122,7 +2132,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand( locateInventory(item, cat); if(!item || !item->isComplete()) return ACCEPT_NO; - LLVOAvatar* my_avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* my_avatar = gAgent.getAvatarObject(); if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) { return ACCEPT_NO; @@ -2185,7 +2195,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject( LLViewerInventoryCategory* cat; locateInventory(item, cat); if(!item || !item->isComplete()) return ACCEPT_NO; - LLVOAvatar* my_avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* my_avatar = gAgent.getAvatarObject(); if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) ) { return ACCEPT_NO; @@ -2383,7 +2393,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem( { // Don't wear anything until initial wearables are loaded, can // destroy clothing items. - if (!gAgent.areWearablesLoaded()) + if (!gAgentWearables.areWearablesLoaded()) { LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return ACCEPT_NO; @@ -2452,7 +2462,7 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture( } else { - gGestureManager.activateGesture(item->getUUID()); + LLGestureManager::instance().activateGesture(item->getUUID()); gInventory.updateItem(item); gInventory.notifyObservers(); } @@ -2478,7 +2488,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory( { // Don't wear anything until initial wearables are loaded, can // destroy clothing items. - if (!gAgent.areWearablesLoaded()) + if (!gAgentWearables.areWearablesLoaded()) { LLNotifications::instance().add("CanNotChangeAppearanceUntilLoaded"); return ACCEPT_NO; @@ -2679,7 +2689,7 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject( // cannot give away no-transfer objects return ACCEPT_NO; } - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if(avatar && avatar->isWearingAttachment( item->getUUID() ) ) { // You can't give objects that are attached to you @@ -2897,11 +2907,10 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory( } else if(mSource == SOURCE_NOTECARD) { - LLPreviewNotecard* card; - card = (LLPreviewNotecard*)LLPreview::find(mSourceID); - if(card) + LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance("preview_notecard", mSourceID); + if(preview) { - item = (LLViewerInventoryItem*)card->getDragItem(); + item = (LLViewerInventoryItem*)preview->getDragItem(); } } if(item) return item; diff --git a/indra/newview/lltoolface.cpp b/indra/newview/lltoolface.cpp index d06e41c771..1d78dc5019 100644 --- a/indra/newview/lltoolface.cpp +++ b/indra/newview/lltoolface.cpp @@ -36,14 +36,12 @@ #include "lltoolface.h" // Library includes +#include "llfloaterreg.h" #include "v3math.h" // Viewer includes -#include "llagent.h" -//#include "llbuildview.h" #include "llviewercontrol.h" #include "llselectmgr.h" -#include "lltoolview.h" #include "llviewerobject.h" #include "llviewerwindow.h" #include "llfloatertools.h" @@ -67,9 +65,7 @@ BOOL LLToolFace::handleDoubleClick(S32 x, S32 y, MASK mask) { // You should already have an object selected from the mousedown. // If so, show its properties - //gBuildView->showFacePanel(); - gFloaterTools->showPanel( LLFloaterTools::PANEL_FACE ); - //gBuildView->showMore(LLBuildView::PANEL_FACE); + LLFloaterReg::showInstance("build", "Texture"); return TRUE; } else diff --git a/indra/newview/lltoolfocus.cpp b/indra/newview/lltoolfocus.cpp index 4e8274a6ef..297cf2c667 100644 --- a/indra/newview/lltoolfocus.cpp +++ b/indra/newview/lltoolfocus.cpp @@ -54,8 +54,10 @@ #include "llviewercamera.h" #include "llviewerobject.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llmorphview.h" +#include "llfloaterreg.h" +#include "llfloatercamera.h" // Globals BOOL gCameraBtnZoom = TRUE; @@ -254,7 +256,11 @@ void LLToolCamera::releaseMouse() gViewerWindow->showCursor(); - LLToolMgr::getInstance()->clearTransientTool(); + //for the situation when left click was performed on the Agent + if (!LLFloaterCamera::inFreeCameraMode()) + { + LLToolMgr::getInstance()->clearTransientTool(); + } mMouseSteering = FALSE; mValidClickPoint = FALSE; @@ -359,7 +365,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) // Orbit tool if (hasMouseCapture()) { - const F32 RADIANS_PER_PIXEL = 360.f * DEG_TO_RAD / gViewerWindow->getWindowWidth(); + const F32 RADIANS_PER_PIXEL = 360.f * DEG_TO_RAD / gViewerWindow->getWorldViewWidth(); if (dx != 0) { @@ -387,7 +393,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) F32 dist = (F32) camera_to_focus.normVec(); // Fudge factor for pan - F32 meters_per_pixel = 3.f * dist / gViewerWindow->getWindowWidth(); + F32 meters_per_pixel = 3.f * dist / gViewerWindow->getWorldViewWidth(); if (dx != 0) { @@ -409,7 +415,7 @@ BOOL LLToolCamera::handleHover(S32 x, S32 y, MASK mask) if (hasMouseCapture()) { - const F32 RADIANS_PER_PIXEL = 360.f * DEG_TO_RAD / gViewerWindow->getWindowWidth(); + const F32 RADIANS_PER_PIXEL = 360.f * DEG_TO_RAD / gViewerWindow->getWorldViewWidth(); if (dx != 0) { diff --git a/indra/newview/lltoolgrab.cpp b/indra/newview/lltoolgrab.cpp index d9811dac6c..abadd251c1 100644 --- a/indra/newview/lltoolgrab.cpp +++ b/indra/newview/lltoolgrab.cpp @@ -46,7 +46,6 @@ // newview headers #include "llagent.h" -//#include "llfloateravatarinfo.h" #include "lldrawable.h" #include "llfloatertools.h" #include "llhudeffect.h" @@ -61,7 +60,7 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llworld.h" const S32 SLOP_DIST_SQ = 4; @@ -511,8 +510,8 @@ void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask) const F32 RADIANS_PER_PIXEL_X = 0.01f; const F32 RADIANS_PER_PIXEL_Y = 0.01f; - S32 dx = x - (gViewerWindow->getWindowWidth() / 2); - S32 dy = y - (gViewerWindow->getWindowHeight() / 2); + S32 dx = x - (gViewerWindow->getWorldViewWidth() / 2); + S32 dy = y - (gViewerWindow->getWorldViewHeight() / 2); if (dx != 0 || dy != 0) { @@ -632,10 +631,10 @@ void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask) // Handle auto-rotation at screen edge. LLVector3 grab_pos_agent = gAgent.getPosAgentFromGlobal( grab_point_global ); - LLCoordGL grab_center_gl( gViewerWindow->getWindowWidth() / 2, gViewerWindow->getWindowHeight() / 2); + LLCoordGL grab_center_gl( gViewerWindow->getWorldViewWidth() / 2, gViewerWindow->getWorldViewHeight() / 2); LLViewerCamera::getInstance()->projectPosAgentToScreen(grab_pos_agent, grab_center_gl); - const S32 ROTATE_H_MARGIN = gViewerWindow->getWindowWidth() / 20; + const S32 ROTATE_H_MARGIN = gViewerWindow->getWorldViewWidth() / 20; const F32 ROTATE_ANGLE_PER_SECOND = 30.f * DEG_TO_RAD; const F32 rotate_angle = ROTATE_ANGLE_PER_SECOND / gFPSClamped; // ...build mode moves camera about focus point @@ -650,7 +649,7 @@ void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask) gAgent.cameraOrbitAround(rotate_angle); } } - else if (grab_center_gl.mX > gViewerWindow->getWindowWidth() - ROTATE_H_MARGIN) + else if (grab_center_gl.mX > gViewerWindow->getWorldViewWidth() - ROTATE_H_MARGIN) { if (gAgent.getFocusOnAvatar()) { @@ -663,7 +662,7 @@ void LLToolGrab::handleHoverActive(S32 x, S32 y, MASK mask) } // Don't move above top of screen or below bottom - if ((grab_center_gl.mY < gViewerWindow->getWindowHeight() - 6) + if ((grab_center_gl.mY < gViewerWindow->getWorldViewHeight() - 6) && (grab_center_gl.mY > 24)) { // Transmit update to simulator @@ -885,7 +884,7 @@ void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask) // Look for cursor against the edge of the screen // Only works in fullscreen - if (gSavedSettings.getBOOL("FullScreen")) + if (gSavedSettings.getBOOL("WindowFullScreen")) { if (gAgent.cameraThirdPerson() ) { @@ -894,7 +893,7 @@ void LLToolGrab::handleHoverInactive(S32 x, S32 y, MASK mask) gAgent.yaw(rotate_angle); //gAgent.setControlFlags(AGENT_CONTROL_YAW_POS); } - else if (x == (gViewerWindow->getWindowWidth() - 1) ) + else if (x == (gViewerWindow->getWorldViewWidth() - 1) ) { gAgent.yaw(-rotate_angle); //gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG); diff --git a/indra/newview/lltoolgrab.h b/indra/newview/lltoolgrab.h index cf2405cafc..16ccb3f24f 100644 --- a/indra/newview/lltoolgrab.h +++ b/indra/newview/lltoolgrab.h @@ -36,7 +36,7 @@ #include "lltool.h" #include "v3math.h" #include "llquaternion.h" -#include "llmemory.h" +#include "llsingleton.h" #include "lluuid.h" #include "llviewerwindow.h" // for LLPickInfo diff --git a/indra/newview/lltoolgun.cpp b/indra/newview/lltoolgun.cpp index d21fd49647..8accf6babf 100644 --- a/indra/newview/lltoolgun.cpp +++ b/indra/newview/lltoolgun.cpp @@ -42,14 +42,18 @@ #include "llresmgr.h" #include "llfontgl.h" #include "llui.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewercamera.h" #include "llhudmanager.h" #include "lltoolmgr.h" #include "lltoolgrab.h" +// Linden library includes +#include "llwindow.h" // setMouseClipping() + LLToolGun::LLToolGun( LLToolComposite* composite ) -: LLTool( std::string("gun"), composite ) +: LLTool( std::string("gun"), composite ), + mIsSelected(FALSE) { } @@ -58,6 +62,7 @@ void LLToolGun::handleSelect() gViewerWindow->hideCursor(); gViewerWindow->moveCursorToCenter(); gViewerWindow->mWindow->setMouseClipping(TRUE); + mIsSelected = TRUE; } void LLToolGun::handleDeselect() @@ -65,6 +70,7 @@ void LLToolGun::handleDeselect() gViewerWindow->moveCursorToCenter(); gViewerWindow->showCursor(); gViewerWindow->mWindow->setMouseClipping(FALSE); + mIsSelected = FALSE; } BOOL LLToolGun::handleMouseDown(S32 x, S32 y, MASK mask) @@ -77,7 +83,7 @@ BOOL LLToolGun::handleMouseDown(S32 x, S32 y, MASK mask) BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) { - if( gAgent.cameraMouselook() ) + if( gAgent.cameraMouselook() && mIsSelected ) { const F32 NOMINAL_MOUSE_SENSITIVITY = 0.0025f; @@ -132,9 +138,9 @@ void LLToolGun::draw() { if( gSavedSettings.getBOOL("ShowCrosshairs") ) { - LLUIImagePtr crosshair = LLUI::getUIImage("UIImgCrosshairsUUID"); + LLUIImagePtr crosshair = LLUI::getUIImage("crosshairs.tga"); crosshair->draw( - ( gViewerWindow->getWindowWidth() - crosshair->getWidth() ) / 2, - ( gViewerWindow->getWindowHeight() - crosshair->getHeight() ) / 2); + ( gViewerWindow->getWorldViewWidth() - crosshair->getWidth() ) / 2, + ( gViewerWindow->getWorldViewHeight() - crosshair->getHeight() ) / 2); } } diff --git a/indra/newview/lltoolgun.h b/indra/newview/lltoolgun.h index 4e945d796c..4644e686b7 100644 --- a/indra/newview/lltoolgun.h +++ b/indra/newview/lltoolgun.h @@ -52,6 +52,8 @@ public: virtual LLTool* getOverrideTool(MASK mask) { return NULL; } virtual BOOL clipMouseWhenDown() { return FALSE; } +private: + BOOL mIsSelected; }; #endif diff --git a/indra/newview/lltoolindividual.cpp b/indra/newview/lltoolindividual.cpp index 8382e0d72d..163c7cbd9b 100644 --- a/indra/newview/lltoolindividual.cpp +++ b/indra/newview/lltoolindividual.cpp @@ -41,6 +41,7 @@ #include "llviewerprecompiledheaders.h" #include "lltoolindividual.h" +#include "llfloaterreg.h" #include "llselectmgr.h" #include "llviewerobject.h" #include "llviewerwindow.h" @@ -93,9 +94,7 @@ BOOL LLToolIndividual::handleDoubleClick(S32 x, S32 y, MASK mask) { // You should already have an object selected from the mousedown. // If so, show its inventory. - //gBuildView->showInventoryPanel(); - //gBuildView->showPanel(LLBuildView::PANEL_CONTENTS); - gFloaterTools->showPanel(LLFloaterTools::PANEL_CONTENTS); + LLFloaterReg::showInstance("build", "Content"); return TRUE; } else diff --git a/indra/newview/lltoolmgr.cpp b/indra/newview/lltoolmgr.cpp index 5ba7217c99..d52e0b4b80 100644 --- a/indra/newview/lltoolmgr.cpp +++ b/indra/newview/lltoolmgr.cpp @@ -34,8 +34,13 @@ #include "lltoolmgr.h" -#include "lltool.h" +#include "lluictrl.h" +#include "llmenugl.h" +#include "llfloaterreg.h" + +#include "llfirstuse.h" // tools and manipulators +#include "lltool.h" #include "llmanipscale.h" #include "llselectmgr.h" #include "lltoolbrush.h" @@ -47,12 +52,14 @@ #include "lltoolindividual.h" #include "lltoolmorph.h" #include "lltoolpie.h" -#include "lltoolplacer.h" #include "lltoolselectland.h" #include "lltoolobjpicker.h" #include "lltoolpipette.h" #include "llagent.h" #include "llviewercontrol.h" +#include "llviewerjoystick.h" +#include "llviewermenu.h" +#include "llviewerparcelmgr.h" // Used when app not active to avoid processing hover. @@ -76,6 +83,11 @@ LLToolMgr::LLToolMgr() mSelectedTool( NULL ), mCurrentToolset( NULL ) { + // Not a panel, register these callbacks globally. + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Active", boost::bind(&LLToolMgr::inEdit, this)); + LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Build.Enabled", boost::bind(&LLToolMgr::canEdit, this)); + LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Build.Toggle", boost::bind(&LLToolMgr::toggleBuildMode, this)); + gToolNull = new LLTool(LLStringUtil::null); // Does nothing setCurrentTool(gToolNull); @@ -168,11 +180,13 @@ void LLToolMgr::setCurrentTool( LLTool* tool ) mBaseTool = tool; updateToolStatus(); + + mSavedTool = NULL; } LLTool* LLToolMgr::getCurrentTool() { - MASK override_mask = gKeyboard->currentMask(TRUE); + MASK override_mask = gKeyboard ? gKeyboard->currentMask(TRUE) : 0; LLTool* cur_tool = NULL; // always use transient tools if available @@ -226,11 +240,77 @@ void LLToolMgr::updateToolStatus() getCurrentTool(); } -BOOL LLToolMgr::inEdit() +bool LLToolMgr::inEdit() { return mBaseTool != LLToolPie::getInstance() && mBaseTool != gToolNull; } +bool LLToolMgr::canEdit() +{ + return LLViewerParcelMgr::getInstance()->agentCanBuild(); +} + +void LLToolMgr::toggleBuildMode() +{ + if (inBuildMode()) + { + if (gSavedSettings.getBOOL("EditCameraMovement")) + { + // just reset the view, will pull us out of edit mode + handle_reset_view(); + } + else + { + // manually disable edit mode, but do not affect the camera + gAgent.resetView(false); + LLFloaterReg::hideInstance("build"); + gViewerWindow->showCursor(); + } + // avoid spurious avatar movements pulling out of edit mode + LLViewerJoystick::getInstance()->setNeedsReset(); + } + else + { + ECameraMode camMode = gAgent.getCameraMode(); + if (CAMERA_MODE_MOUSELOOK == camMode || CAMERA_MODE_CUSTOMIZE_AVATAR == camMode) + { + // pull the user out of mouselook or appearance mode when entering build mode + handle_reset_view(); + } + + if (gSavedSettings.getBOOL("EditCameraMovement")) + { + // camera should be set + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { + handle_toggle_flycam(); + } + + if (gAgent.getFocusOnAvatar()) + { + // zoom in if we're looking at the avatar + gAgent.setFocusOnAvatar(FALSE, ANIMATE); + gAgent.setFocusGlobal(gAgent.getPositionGlobal() + 2.0 * LLVector3d(gAgent.getAtAxis())); + gAgent.cameraZoomIn(0.666f); + gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD ); + } + } + + + setCurrentToolset(gBasicToolset); + getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); + + // Could be first use + LLFirstUse::useBuild(); + + gAgent.resetView(false); + + // avoid spurious avatar movements + LLViewerJoystick::getInstance()->setNeedsReset(); + + } +} + bool LLToolMgr::inBuildMode() { // when entering mouselook inEdit() immediately returns true before @@ -277,22 +357,20 @@ void LLToolMgr::clearTransientTool() } -// The "gun tool", used for handling mouselook, captures the mouse and -// locks it within the window. When the app loses focus we need to -// release this locking. void LLToolMgr::onAppFocusLost() { - mSavedTool = mBaseTool; - mBaseTool = gToolNull; + if (mSelectedTool) + { + mSelectedTool->handleDeselect(); + } updateToolStatus(); } void LLToolMgr::onAppFocusGained() { - if (mSavedTool) + if (mSelectedTool) { - mBaseTool = mSavedTool; - mSavedTool = NULL; + mSelectedTool->handleSelect(); } updateToolStatus(); } @@ -396,8 +474,6 @@ void LLToolset::selectPrevTool() } } -void select_tool( void *tool_pointer ) -{ - LLTool *tool = (LLTool *)tool_pointer; - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( tool ); -} +//////////////////////////////////////////////////////////////////////////// + + diff --git a/indra/newview/lltoolmgr.h b/indra/newview/lltoolmgr.h index 92647c99de..22aec97864 100644 --- a/indra/newview/lltoolmgr.h +++ b/indra/newview/lltoolmgr.h @@ -58,7 +58,9 @@ public: LLTool* getCurrentTool(); // returns active tool, taking into account keyboard state LLTool* getBaseTool(); // returns active tool when overrides are deactivated - BOOL inEdit(); + bool inEdit(); + bool canEdit(); + void toggleBuildMode(); /* Determines if we are in Build mode or not. */ bool inBuildMode(); @@ -115,10 +117,6 @@ protected: tool_list_t mToolList; }; -// Handy callbacks for switching tools -void select_tool(void *tool); - - // Globals extern LLToolset* gBasicToolset; diff --git a/indra/newview/lltoolmorph.cpp b/indra/newview/lltoolmorph.cpp index 75e19645a6..d7d7b5f44b 100644 --- a/indra/newview/lltoolmorph.cpp +++ b/indra/newview/lltoolmorph.cpp @@ -37,7 +37,7 @@ #include "llrender.h" // Library includes -#include "audioengine.h" +#include "llaudioengine.h" #include "llviewercontrol.h" #include "llfontgl.h" #include "sound_ids.h" @@ -56,13 +56,12 @@ #include "llsky.h" #include "lltexlayer.h" #include "lltoolmgr.h" -#include "lltoolview.h" #include "llui.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobject.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "pipeline.h" @@ -82,7 +81,7 @@ LLVisualParamHint::LLVisualParamHint( LLViewerVisualParam *param, F32 param_weight) : - LLDynamicTexture(width, height, 3, LLDynamicTexture::ORDER_MIDDLE, TRUE ), + LLViewerDynamicTexture(width, height, 3, LLViewerDynamicTexture::ORDER_MIDDLE, TRUE ), mNeedsUpdate( TRUE ), mIsVisible( FALSE ), mJointMesh( mesh ), @@ -145,7 +144,7 @@ BOOL LLVisualParamHint::needsRender() void LLVisualParamHint::preRender(BOOL clear_depth) { - LLVOAvatar* avatarp = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); mLastParamWeight = avatarp->getVisualParamWeight(mVisualParam); avatarp->setVisualParamWeight(mVisualParam, mVisualParamWeight); @@ -156,7 +155,7 @@ void LLVisualParamHint::preRender(BOOL clear_depth) avatarp->updateGeometry(avatarp->mDrawable); avatarp->updateLOD(); - LLDynamicTexture::preRender(clear_depth); + LLViewerDynamicTexture::preRender(clear_depth); } //----------------------------------------------------------------------------- @@ -170,7 +169,7 @@ BOOL LLVisualParamHint::render() glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); - glOrtho(0.0f, mWidth, 0.0f, mHeight, -1.0f, 1.0f); + glOrtho(0.0f, mFullWidth, 0.0f, mFullHeight, -1.0f, 1.0f); glMatrixMode(GL_MODELVIEW); glPushMatrix(); @@ -178,7 +177,7 @@ BOOL LLVisualParamHint::render() LLGLSUIDefault gls_ui; //LLGLState::verify(TRUE); - mBackgroundp->draw(0, 0, mWidth, mHeight); + mBackgroundp->draw(0, 0, mFullWidth, mFullHeight); glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -225,13 +224,13 @@ BOOL LLVisualParamHint::render() gGL.flush(); - LLViewerCamera::getInstance()->setAspect((F32)mWidth / (F32)mHeight); + LLViewerCamera::getInstance()->setAspect((F32)mFullWidth / (F32)mFullHeight); LLViewerCamera::getInstance()->setOriginAndLookAt( camera_pos, // camera LLVector3(0.f, 0.f, 1.f), // up target_pos ); // point of interest - LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mWidth, mHeight, FALSE); + LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE); if (avatarp->mDrawable.notNull()) { @@ -245,7 +244,7 @@ BOOL LLVisualParamHint::render() } avatarp->setVisualParamWeight(mVisualParam, mLastParamWeight); gGL.color4f(1,1,1,1); - mTexture->setGLTextureCreated(true); + mGLTexturep->setGLTextureCreated(true); return TRUE; } @@ -257,7 +256,7 @@ void LLVisualParamHint::draw() { if (!mIsVisible) return; - gGL.getTexUnit(0)->bind(getTexture()); + gGL.getTexUnit(0)->bind(this); gGL.color4f(1.f, 1.f, 1.f, 1.f); @@ -265,13 +264,13 @@ void LLVisualParamHint::draw() gGL.begin(LLRender::QUADS); { gGL.texCoord2i(0, 1); - gGL.vertex2i(0, mHeight); + gGL.vertex2i(0, mFullHeight); gGL.texCoord2i(0, 0); gGL.vertex2i(0, 0); gGL.texCoord2i(1, 0); - gGL.vertex2i(mWidth, 0); + gGL.vertex2i(mFullWidth, 0); gGL.texCoord2i(1, 1); - gGL.vertex2i(mWidth, mHeight); + gGL.vertex2i(mFullWidth, mFullHeight); } gGL.end(); @@ -281,7 +280,7 @@ void LLVisualParamHint::draw() //----------------------------------------------------------------------------- // LLVisualParamReset() //----------------------------------------------------------------------------- -LLVisualParamReset::LLVisualParamReset() : LLDynamicTexture(1, 1, 1, ORDER_RESET, FALSE) +LLVisualParamReset::LLVisualParamReset() : LLViewerDynamicTexture(1, 1, 1, ORDER_RESET, FALSE) { } @@ -292,7 +291,7 @@ BOOL LLVisualParamReset::render() { if (sDirty) { - LLVOAvatar* avatarp = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatarp = gAgent.getAvatarObject(); avatarp->updateComposites(); avatarp->updateVisualParams(); avatarp->updateGeometry(avatarp->mDrawable); diff --git a/indra/newview/lltoolmorph.h b/indra/newview/lltoolmorph.h index 11de8160eb..b7df718ba2 100644 --- a/indra/newview/lltoolmorph.h +++ b/indra/newview/lltoolmorph.h @@ -42,7 +42,7 @@ #include "llstrider.h" #include "llviewervisualparam.h" #include "llframetimer.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLViewerJointMesh; class LLPolyMesh; @@ -51,17 +51,18 @@ class LLViewerObject; //----------------------------------------------------------------------------- // LLVisualParamHint //----------------------------------------------------------------------------- -class LLVisualParamHint -: public LLDynamicTexture +class LLVisualParamHint : public LLViewerDynamicTexture { +protected: + virtual ~LLVisualParamHint(); + public: LLVisualParamHint( S32 pos_x, S32 pos_y, S32 width, S32 height, LLViewerJointMesh *mesh, LLViewerVisualParam *param, - F32 param_weight); - virtual ~LLVisualParamHint(); + F32 param_weight); BOOL needsRender(); void preRender(BOOL clear_depth); @@ -94,13 +95,15 @@ protected: LLUIImagePtr mBackgroundp; - typedef std::set instance_list_t; + typedef std::set< LLVisualParamHint* > instance_list_t; static instance_list_t sInstances; }; // this class resets avatar data at the end of an update cycle -class LLVisualParamReset : public LLDynamicTexture +class LLVisualParamReset : public LLViewerDynamicTexture { +protected: + /*virtual */ ~LLVisualParamReset(){} public: LLVisualParamReset(); /*virtual */ BOOL render(); diff --git a/indra/newview/lltoolobjpicker.cpp b/indra/newview/lltoolobjpicker.cpp index d69688706f..b2088a8232 100644 --- a/indra/newview/lltoolobjpicker.cpp +++ b/indra/newview/lltoolobjpicker.cpp @@ -48,6 +48,7 @@ #include "llviewercamera.h" #include "llviewerwindow.h" #include "lldrawable.h" +#include "llrootview.h" LLToolObjPicker::LLToolObjPicker() @@ -62,7 +63,7 @@ LLToolObjPicker::LLToolObjPicker() // returns TRUE if an object was selected BOOL LLToolObjPicker::handleMouseDown(S32 x, S32 y, MASK mask) { - LLView* viewp = gViewerWindow->getRootView(); + LLRootView* viewp = gViewerWindow->getRootView(); BOOL handled = viewp->handleMouseDown(x, y, mask); mHitObjectID.setNull(); @@ -131,7 +132,7 @@ BOOL LLToolObjPicker::handleHover(S32 x, S32 y, MASK mask) cursor = UI_CURSOR_TOOLPICKOBJECT3; - gViewerWindow->getWindow()->setCursor(cursor); + gViewerWindow->setCursor(cursor); } return handled; } diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp index 986555db49..235d4acf9d 100644 --- a/indra/newview/lltoolpie.cpp +++ b/indra/newview/lltoolpie.cpp @@ -36,14 +36,14 @@ #include "indra_constants.h" #include "llclickaction.h" -#include "llmediabase.h" // for status codes #include "llparcel.h" #include "llagent.h" #include "llviewercontrol.h" +#include "llfocusmgr.h" #include "llfirstuse.h" -#include "llfloateravatarinfo.h" #include "llfloaterland.h" +#include "llfloaterreg.h" #include "llfloaterscriptdebug.h" #include "llhoverview.h" #include "llhudeffecttrail.h" @@ -63,7 +63,8 @@ #include "llviewerparcelmgr.h" #include "llviewerwindow.h" #include "llviewermedia.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llviewermediafocus.h" #include "llworld.h" #include "llui.h" #include "llweb.h" @@ -72,14 +73,15 @@ extern void handle_buy(void*); extern BOOL gDebugClicks; +static bool handle_media_click(const LLPickInfo& info); +static bool handle_media_hover(const LLPickInfo& info); static void handle_click_action_play(); static void handle_click_action_open_media(LLPointer objectp); static ECursorType cursor_from_parcel_media(U8 click_action); LLToolPie::LLToolPie() -: LLTool(std::string("Select")), - mPieMouseButtonDown( FALSE ), +: LLTool(std::string("Pie")), mGrabMouseButtonDown( FALSE ), mMouseOutsideSlop( FALSE ), mClickAction(0) @@ -98,32 +100,44 @@ BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask) void LLToolPie::leftMouseCallback(const LLPickInfo& pick_info) { LLToolPie::getInstance()->mPick = pick_info; - LLToolPie::getInstance()->pickAndShowMenu(FALSE); + LLToolPie::getInstance()->pickLeftMouseDownCallback(); } +// Spawn context menus on right mouse down so you can drag over and select +// an item. BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask) { // don't pick transparent so users can't "pay" transparent objects gViewerWindow->pickAsync(x, y, mask, rightMouseCallback, FALSE, TRUE); - mPieMouseButtonDown = TRUE; - // don't steal focus from UI + // claim not handled so UI focus stays same return FALSE; } +BOOL LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask) +{ + LLToolMgr::getInstance()->clearTransientTool(); + return LLTool::handleRightMouseUp(x, y, mask); +} + +BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + return LLViewerMediaFocus::getInstance()->handleScrollWheel(x, y, clicks); +} + // static void LLToolPie::rightMouseCallback(const LLPickInfo& pick_info) { LLToolPie::getInstance()->mPick = pick_info; - LLToolPie::getInstance()->pickAndShowMenu(TRUE); + LLToolPie::getInstance()->pickRightMouseDownCallback(); } // True if you selected an object. -BOOL LLToolPie::pickAndShowMenu(BOOL always_show) +BOOL LLToolPie::pickLeftMouseDownCallback() { S32 x = mPick.mMousePt.mX; S32 y = mPick.mMousePt.mY; MASK mask = mPick.mKeyMask; - if (!always_show && mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL) + if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL) { LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel(); if (parcel) @@ -139,10 +153,11 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) else { // not selling passes, get info - LLFloaterLand::showInstance(); + LLFloaterReg::showInstance("about_land"); } } + gFocusMgr.setKeyboardFocus(NULL); return LLTool::handleMouseDown(x, y, mask); } @@ -160,11 +175,13 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) parent = object->getRootEdit(); } + BOOL touchable = (object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch()); + // If it's a left-click, and we have a special action, do it. - if (useClickAction(always_show, mask, object, parent)) + if (useClickAction(mask, object, parent)) { mClickAction = 0; if (object && object->getClickAction()) @@ -182,9 +199,11 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) // touch behavior down below... break; case CLICK_ACTION_SIT: - if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->mIsSitting)) // agent not already sitting + if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->isSitting())) // agent not already sitting { handle_sit_or_stand(); + // put focus in world when sitting on an object + gFocusMgr.setKeyboardFocus(NULL); return TRUE; } // else nothing (fall through to touch) @@ -237,11 +256,19 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) } } + if (handle_media_click(mPick)) + { + return FALSE; + } + + // put focus back "in world" + gFocusMgr.setKeyboardFocus(NULL); + // Switch to grab tool if physical or triggerable if (object && !object->isAvatar() && - ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) && - !always_show) + ((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) + ) { gGrabTransientTool = this; LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() ); @@ -256,8 +283,7 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) // If left-click never selects or spawns a menu // Eat the event. - if (!gSavedSettings.getBOOL("LeftClickShowMenu") - && !always_show) + if (!gSavedSettings.getBOOL("LeftClickShowMenu")) { // mouse already released if (!mGrabMouseButtonDown) @@ -285,14 +311,16 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) return TRUE; } - // Could be first left-click on nothing - LLFirstUse::useLeftClickNoHit(); - + ////////// + // // Could be first left-click on nothing + // LLFirstUse::useLeftClickNoHit(); + ///////// + // Eat the event return LLTool::handleMouseDown(x, y, mask); } - if (!always_show && gAgent.leftButtonGrabbed()) + if (gAgent.leftButtonGrabbed()) { // if the left button is grabbed, don't put up the pie menu return LLTool::handleMouseDown(x, y, mask); @@ -302,116 +330,15 @@ BOOL LLToolPie::pickAndShowMenu(BOOL always_show) LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE); // Spawn pie menu - if (mPick.mPickType == LLPickInfo::PICK_LAND) - { - LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal ); - gMenuHolder->setParcelSelection(selection); - gPieLand->show(x, y, mPieMouseButtonDown); - - // VEFFECT: ShowPie - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE); - effectp->setPositionGlobal(mPick.mPosGlobal); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - effectp->setDuration(0.25f); - } - else if (mPick.mObjectID == gAgent.getID() ) - { - if(!gPieSelf) - { - //either at very early startup stage or at late quitting stage, - //this event is ignored. - return TRUE ; - } - - gPieSelf->show(x, y, mPieMouseButtonDown); - } - else if (object) - { - gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); - - if (object->isAvatar() - || (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner())) - { - // Find the attachment's avatar - while( object && object->isAttachment()) - { - object = (LLViewerObject*)object->getParent(); - } - - // Object is an avatar, so check for mute by id. - LLVOAvatar* avatar = (LLVOAvatar*)object; - std::string name = avatar->getFullname(); - if (LLMuteList::getInstance()->isMuted(avatar->getID(), name)) - { - gMenuHolder->childSetText("Avatar Mute", std::string("Unmute")); // *TODO:Translate - //gMutePieMenu->setLabel("Unmute"); - } - else - { - gMenuHolder->childSetText("Avatar Mute", std::string("Mute")); // *TODO:Translate - //gMutePieMenu->setLabel("Mute"); - } - - gPieAvatar->show(x, y, mPieMouseButtonDown); - } - else if (object->isAttachment()) - { - gPieAttachment->show(x, y, mPieMouseButtonDown); - } - else - { - // BUG: What about chatting child objects? - std::string name; - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node) - { - name = node->mName; - } - if (LLMuteList::getInstance()->isMuted(object->getID(), name)) - { - gMenuHolder->childSetText("Object Mute", std::string("Unmute")); // *TODO:Translate - //gMuteObjectPieMenu->setLabel("Unmute"); - } - else - { - gMenuHolder->childSetText("Object Mute", std::string("Mute")); // *TODO:Translate - //gMuteObjectPieMenu->setLabel("Mute"); - } - - gPieObject->show(x, y, mPieMouseButtonDown); - - // VEFFECT: ShowPie object - // Don't show when you click on someone else, it freaks them - // out. - LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE); - effectp->setPositionGlobal(mPick.mPosGlobal); - effectp->setColor(LLColor4U(gAgent.getEffectColor())); - effectp->setDuration(0.25f); - } - } - - if (always_show) - { - // ignore return value - LLTool::handleRightMouseDown(x, y, mask); - } - else - { - // ignore return value - LLTool::handleMouseDown(x, y, mask); - } - - // We handled the event. + LLTool::handleRightMouseDown(x, y, mask); return TRUE; } -BOOL LLToolPie::useClickAction(BOOL always_show, - MASK mask, +BOOL LLToolPie::useClickAction(MASK mask, LLViewerObject* object, LLViewerObject* parent) { - return !always_show - && mask == MASK_NONE + return mask == MASK_NONE && object && !object->isAttachment() && LLPrimitive::isPrimitive(object->getPCode()) @@ -454,7 +381,7 @@ ECursorType cursor_from_object(LLViewerObject* object) switch(click_action) { case CLICK_ACTION_SIT: - if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->mIsSitting)) // not already sitting? + if ((gAgent.getAvatarObject() != NULL) && (!gAgent.getAvatarObject()->isSitting())) // not already sitting? { cursor = UI_CURSOR_TOOLSIT; } @@ -524,7 +451,7 @@ void LLToolPie::selectionPropertiesReceived() handle_give_money_dialog(); break; case CLICK_ACTION_OPEN: - handle_object_open(); + LLFloaterReg::showInstance("openobject"); break; default: break; @@ -554,41 +481,55 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask) mMouseOutsideSlop = TRUE; } */ - + + // FIXME: This was in the pluginapi branch, but I don't think it's correct. +// gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + LLViewerObject *object = NULL; LLViewerObject *parent = NULL; - if (gHoverView) - { - object = gViewerWindow->getHoverPick().getObject(); - } + object = gViewerWindow->getHoverPick().getObject(); if (object) { parent = object->getRootEdit(); } - if (object && useClickAction(FALSE, mask, object, parent)) + if (object && useClickAction(mask, object, parent)) { ECursorType cursor = cursor_from_object(object); - gViewerWindow->getWindow()->setCursor(cursor); + gViewerWindow->setCursor(cursor); + lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; + } + else if (handle_media_hover(gViewerWindow->getHoverPick())) + { + // cursor set by media object lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else if ((object && !object->isAvatar() && object->usePhysics()) || (parent && !parent->isAvatar() && parent->usePhysics())) { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLGRAB); + gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else if ( (object && object->flagHandleTouch()) || (parent && parent->flagHandleTouch())) { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_HAND); + gViewerWindow->setCursor(UI_CURSOR_HAND); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; } else { - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPie (inactive)" << llendl; + + if(!object) + { + // We need to clear media hover flag + if (LLViewerMediaFocus::getInstance()->getMouseOverFlag()) + { + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + } + } } return TRUE; @@ -610,7 +551,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) // the world. Keep the cursor an arrow, assuming that // after the user moves off the UI, they won't be on the // same object anymore. - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); // Make sure the hover-picked object is ignored. gHoverView->resetLastHoverObject(); break; @@ -624,13 +565,6 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask) return LLTool::handleMouseUp(x, y, mask); } -BOOL LLToolPie::handleRightMouseUp(S32 x, S32 y, MASK mask) -{ - mPieMouseButtonDown = FALSE; - LLToolMgr::getInstance()->clearTransientTool(); - return LLTool::handleRightMouseUp(x, y, mask); -} - BOOL LLToolPie::handleDoubleClick(S32 x, S32 y, MASK mask) { @@ -744,14 +678,14 @@ static void handle_click_action_play() LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); if (!parcel) return; - LLMediaBase::EStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { - case LLMediaBase::STATUS_STARTED: + case LLViewerMediaImpl::MEDIA_PLAYING: LLViewerParcelMedia::pause(); break; - case LLMediaBase::STATUS_PAUSED: + case LLViewerMediaImpl::MEDIA_PAUSED: LLViewerParcelMedia::start(); break; @@ -761,6 +695,111 @@ static void handle_click_action_play() } } +static bool handle_media_click(const LLPickInfo& pick) +{ + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + LLPointer objectp = pick.getObject(); + + + if (!parcel || + objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs()) + { + LLSelectMgr::getInstance()->deselect(); + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; + } + + + + // HACK: This is directly referencing an impl name. BAD! + // This can be removed when we have a truly generic media browser that only + // builds an impl based on the type of url it is passed. + + // is media playing on this face? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + if (tep + && media_impl.notNull() + && media_impl->hasMedia() + && gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + LLObjectSelectionHandle selection = LLViewerMediaFocus::getInstance()->getSelection(); + if (! selection->contains(pick.getObject(), pick.mObjectFace)) + { + LLViewerMediaFocus::getInstance()->setFocusFace(TRUE, pick.getObject(), pick.mObjectFace, media_impl); + } + else + { + media_impl->mouseDown(pick.mXYCoords.mX, pick.mXYCoords.mY); + media_impl->mouseCapture(); // the mouse-up will happen when capture is lost + } + + return true; + } + + LLSelectMgr::getInstance()->deselect(); + LLViewerMediaFocus::getInstance()->clearFocus(); + + return false; +} + +static bool handle_media_hover(const LLPickInfo& pick) +{ + //FIXME: how do we handle object in different parcel than us? + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (!parcel) return false; + + LLPointer objectp = pick.getObject(); + + // Early out cases. Must clear mouse over media focus flag + // did not hit an object or did not hit a valid face + if ( objectp.isNull() || + pick.mObjectFace < 0 || + pick.mObjectFace >= objectp->getNumTEs() ) + { + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + return false; + } + + + // HACK: This is directly referencing an impl name. BAD! + // This can be removed when we have a truly generic media browser that only + // builds an impl based on the type of url it is passed. + + // is media playing on this face? + const LLTextureEntry* tep = objectp->getTE(pick.mObjectFace); + viewer_media_t media_impl = LLViewerMedia::getMediaImplFromTextureID(tep->getID()); + if (tep + && media_impl.notNull() + && media_impl->hasMedia() + && gSavedSettings.getBOOL("MediaOnAPrimUI")) + { + if(LLViewerMediaFocus::getInstance()->getFocus()) + { + media_impl->mouseMove(pick.mXYCoords.mX, pick.mXYCoords.mY); + } + + // Set mouse over flag if unset + if (! LLViewerMediaFocus::getInstance()->getMouseOverFlag()) + { + LLSelectMgr::getInstance()->setHoverObject(objectp, pick.mObjectFace); + LLViewerMediaFocus::getInstance()->setMouseOverFlag(true, media_impl); + LLViewerMediaFocus::getInstance()->setPickInfo(pick); + } + + return true; + } + LLViewerMediaFocus::getInstance()->setMouseOverFlag(false); + + return false; +} + + static void handle_click_action_open_media(LLPointer objectp) { //FIXME: how do we handle object in different parcel than us? @@ -775,7 +814,7 @@ static void handle_click_action_open_media(LLPointer objectp) if( face < 0 || face >= objectp->getNumTEs() ) return; // is media playing on this face? - if (!LLViewerMedia::isActiveMediaTexture(objectp->getTE(face)->getID())) + if (LLViewerMedia::getMediaImplFromTextureID(objectp->getTE(face)->getID()) != NULL) { handle_click_action_play(); return; @@ -785,18 +824,7 @@ static void handle_click_action_open_media(LLPointer objectp) std::string media_type = std::string ( parcel->getMediaType() ); LLStringUtil::trim(media_url); - // Get the scheme, see if that is handled as well. - LLURI uri(media_url); - std::string media_scheme = uri.scheme() != "" ? uri.scheme() : "http"; - - // HACK: This is directly referencing an impl name. BAD! - // This can be removed when we have a truly generic media browser that only - // builds an impl based on the type of url it is passed. - - if( LLMediaManager::getInstance()->supportsMediaType( "LLMediaImplLLMozLib", media_scheme, media_type ) ) - { - LLWeb::loadURL(media_url); - } + LLWeb::loadURL(media_url); } static ECursorType cursor_from_parcel_media(U8 click_action) @@ -814,21 +842,127 @@ static ECursorType cursor_from_parcel_media(U8 click_action) std::string media_type = std::string ( parcel->getMediaType() ); LLStringUtil::trim(media_url); - // Get the scheme, see if that is handled as well. - LLURI uri(media_url); - std::string media_scheme = uri.scheme() != "" ? uri.scheme() : "http"; + open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - if( LLMediaManager::getInstance()->supportsMediaType( "LLMediaImplLLMozLib", media_scheme, media_type ) ) - { - open_cursor = UI_CURSOR_TOOLMEDIAOPEN; - } - - LLMediaBase::EStatus status = LLViewerParcelMedia::getStatus(); + LLViewerMediaImpl::EMediaStatus status = LLViewerParcelMedia::getStatus(); switch(status) { - case LLMediaBase::STATUS_STARTED: + case LLViewerMediaImpl::MEDIA_PLAYING: return click_action == CLICK_ACTION_PLAY ? UI_CURSOR_TOOLPAUSE : open_cursor; default: return UI_CURSOR_TOOLPLAY; } } + + +// True if we handled the event. +BOOL LLToolPie::pickRightMouseDownCallback() +{ + S32 x = mPick.mMousePt.mX; + S32 y = mPick.mMousePt.mY; + MASK mask = mPick.mKeyMask; + + if (mPick.mPickType != LLPickInfo::PICK_LAND) + { + LLViewerParcelMgr::getInstance()->deselectLand(); + } + + // didn't click in any UI object, so must have clicked in the world + LLViewerObject *object = mPick.getObject(); + LLViewerObject *parent = NULL; + if(object) + parent = object->getRootEdit(); + + // Can't ignore children here. + LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE); + + // Spawn pie menu + if (mPick.mPickType == LLPickInfo::PICK_LAND) + { + LLParcelSelectionHandle selection = LLViewerParcelMgr::getInstance()->selectParcelAt( mPick.mPosGlobal ); + gMenuHolder->setParcelSelection(selection); + gPieLand->show(x, y); + + showVisualContextMenuEffect(); + + } + else if (mPick.mObjectID == gAgent.getID() ) + { + if(!gPieSelf) + { + //either at very early startup stage or at late quitting stage, + //this event is ignored. + return TRUE ; + } + + gPieSelf->show(x, y); + } + else if (object) + { + gMenuHolder->setObjectSelection(LLSelectMgr::getInstance()->getSelection()); + + if (object->isAvatar() + || (object->isAttachment() && !object->isHUDAttachment() && !object->permYouOwner())) + { + // Find the attachment's avatar + while( object && object->isAttachment()) + { + object = (LLViewerObject*)object->getParent(); + } + + // Object is an avatar, so check for mute by id. + LLVOAvatar* avatar = (LLVOAvatar*)object; + std::string name = avatar->getFullname(); + if (LLMuteList::getInstance()->isMuted(avatar->getID(), avatar->getFullname())) + { + gMenuHolder->childSetText("Avatar Mute", std::string("Unmute")); // *TODO:Translate + } + else + { + gMenuHolder->childSetText("Avatar Mute", std::string("Mute")); // *TODO:Translate + } + + gPieAvatar->show(x, y); + } + else if (object->isAttachment()) + { + gPieAttachment->show(x, y); + } + else + { + // BUG: What about chatting child objects? + std::string name; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); + if (node) + { + name = node->mName; + } + if (LLMuteList::getInstance()->isMuted(object->getID(), name)) + { + gMenuHolder->childSetText("Object Mute", std::string("Unmute")); // *TODO:Translate + } + else + { + gMenuHolder->childSetText("Object Mute", std::string("Mute")); // *TODO:Translate + } + + gPieObject->show(x, y); + + showVisualContextMenuEffect(); + } + } + + LLTool::handleRightMouseDown(x, y, mask); + // We handled the event. + return TRUE; +} + +void LLToolPie::showVisualContextMenuEffect() +{ + // VEFFECT: ShowPie + LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE); + effectp->setPositionGlobal(mPick.mPosGlobal); + effectp->setColor(LLColor4U(gAgent.getEffectColor())); + effectp->setDuration(0.25f); + +} diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h index 83df03cda2..a55e435282 100644 --- a/indra/newview/lltoolpie.h +++ b/indra/newview/lltoolpie.h @@ -51,6 +51,7 @@ public: virtual BOOL handleRightMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask); + virtual BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); virtual void render(); @@ -73,13 +74,13 @@ public: private: - BOOL outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y); - BOOL pickAndShowMenu(BOOL edit_menu); - BOOL useClickAction(BOOL always_show, MASK mask, LLViewerObject* object, - LLViewerObject* parent); + BOOL outsideSlop (S32 x, S32 y, S32 start_x, S32 start_y); + BOOL pickLeftMouseDownCallback(); + BOOL pickRightMouseDownCallback(); + BOOL useClickAction (MASK mask, LLViewerObject* object,LLViewerObject* parent); + void showVisualContextMenuEffect(); private: - BOOL mPieMouseButtonDown; BOOL mGrabMouseButtonDown; BOOL mMouseOutsideSlop; // for this drag, has mouse moved outside slop region LLPickInfo mPick; diff --git a/indra/newview/lltoolpipette.cpp b/indra/newview/lltoolpipette.cpp index 9d95ccc06f..878ed0f9a9 100644 --- a/indra/newview/lltoolpipette.cpp +++ b/indra/newview/lltoolpipette.cpp @@ -55,8 +55,6 @@ LLToolPipette::LLToolPipette() : LLTool(std::string("Pipette")), mSuccess(TRUE) { - mSelectCallback = NULL; - mUserData = NULL; } @@ -106,6 +104,15 @@ BOOL LLToolPipette::handleToolTip(S32 x, S32 y, std::string& msg, LLRect *sticky return TRUE; } +void LLToolPipette::setTextureEntry(const LLTextureEntry* entry) +{ + if (entry) + { + mTextureEntry = *entry; + mSignal(mTextureEntry); + } +} + void LLToolPipette::pickCallback(const LLPickInfo& pick_info) { LLViewerObject* hit_obj = pick_info.getObject(); @@ -118,20 +125,11 @@ void LLToolPipette::pickCallback(const LLPickInfo& pick_info) { //TODO: this should highlight the selected face only LLSelectMgr::getInstance()->highlightObjectOnly(hit_obj); - LLToolPipette::getInstance()->mTextureEntry = *hit_obj->getTE(pick_info.mObjectFace); - if (LLToolPipette::getInstance()->mSelectCallback) - { - LLToolPipette::getInstance()->mSelectCallback(LLToolPipette::getInstance()->mTextureEntry, LLToolPipette::getInstance()->mUserData); - } + const LLTextureEntry* entry = hit_obj->getTE(pick_info.mObjectFace); + LLToolPipette::getInstance()->setTextureEntry(entry); } } -void LLToolPipette::setSelectCallback(select_callback callback, void* user_data) -{ - mSelectCallback = callback; - mUserData = user_data; -} - void LLToolPipette::setResult(BOOL success, const std::string& msg) { mTooltipMsg = msg; diff --git a/indra/newview/lltoolpipette.h b/indra/newview/lltoolpipette.h index 54c24e9467..3b6ebec67e 100644 --- a/indra/newview/lltoolpipette.h +++ b/indra/newview/lltoolpipette.h @@ -40,6 +40,8 @@ #include "lltool.h" #include "lltextureentry.h" +#include +#include class LLViewerObject; class LLPickInfo; @@ -56,18 +58,19 @@ public: virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect *sticky_rect_screen); - typedef void (*select_callback)(const LLTextureEntry& te, void *data); - void setSelectCallback(select_callback callback, void* user_data); + // Note: Don't return connection; use boost::bind + boost::signals2::trackable to disconnect slots + typedef boost::signals2::signal signal_t; + void setToolSelectCallback(const signal_t::slot_type& cb) { mSignal.connect(cb); } void setResult(BOOL success, const std::string& msg); - + + void setTextureEntry(const LLTextureEntry* entry); static void pickCallback(const LLPickInfo& pick_info); protected: LLTextureEntry mTextureEntry; - select_callback mSelectCallback; + signal_t mSignal; BOOL mSuccess; std::string mTooltipMsg; - void* mUserData; }; #endif //LL_LLTOOLPIPETTE_H diff --git a/indra/newview/lltoolplacer.cpp b/indra/newview/lltoolplacer.cpp index 88fddd9336..de68dd6153 100644 --- a/indra/newview/lltoolplacer.cpp +++ b/indra/newview/lltoolplacer.cpp @@ -35,9 +35,6 @@ // self header #include "lltoolplacer.h" -// linden library headers -#include "llprimitive.h" - // viewer headers #include "llbutton.h" #include "llviewercontrol.h" @@ -59,19 +56,23 @@ #include "llvolumemessage.h" #include "llhudmanager.h" #include "llagent.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llhudeffecttrail.h" #include "llviewerobjectlist.h" #include "llviewercamera.h" #include "llviewerstats.h" +// linden library headers +#include "llprimitive.h" +#include "llwindow.h" // incBusyCount() + const LLVector3 DEFAULT_OBJECT_SCALE(0.5f, 0.5f, 0.5f); //static LLPCode LLToolPlacer::sObjectType = LL_PCODE_CUBE; LLToolPlacer::LLToolPlacer() -: LLTool( std::string("Create") ) +: LLTool( "Create" ) { } @@ -521,7 +522,7 @@ BOOL LLToolPlacer::placeObject(S32 x, S32 y, MASK mask) BOOL LLToolPlacer::handleHover(S32 x, S32 y, MASK mask) { lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolPlacer" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_TOOLCREATE); + gViewerWindow->setCursor(UI_CURSOR_TOOLCREATE); return TRUE; } @@ -534,92 +535,3 @@ void LLToolPlacer::handleDeselect() { } -////////////////////////////////////////////////////// -// LLToolPlacerPanel - -// static -LLPCode LLToolPlacerPanel::sCube = LL_PCODE_CUBE; -LLPCode LLToolPlacerPanel::sPrism = LL_PCODE_PRISM; -LLPCode LLToolPlacerPanel::sPyramid = LL_PCODE_PYRAMID; -LLPCode LLToolPlacerPanel::sTetrahedron = LL_PCODE_TETRAHEDRON; -LLPCode LLToolPlacerPanel::sCylinder = LL_PCODE_CYLINDER; -LLPCode LLToolPlacerPanel::sCylinderHemi= LL_PCODE_CYLINDER_HEMI; -LLPCode LLToolPlacerPanel::sCone = LL_PCODE_CONE; -LLPCode LLToolPlacerPanel::sConeHemi = LL_PCODE_CONE_HEMI; -LLPCode LLToolPlacerPanel::sTorus = LL_PCODE_TORUS; -LLPCode LLToolPlacerPanel::sSquareTorus = LLViewerObject::LL_VO_SQUARE_TORUS; -LLPCode LLToolPlacerPanel::sTriangleTorus = LLViewerObject::LL_VO_TRIANGLE_TORUS; -LLPCode LLToolPlacerPanel::sSphere = LL_PCODE_SPHERE; -LLPCode LLToolPlacerPanel::sSphereHemi = LL_PCODE_SPHERE_HEMI; -LLPCode LLToolPlacerPanel::sTree = LL_PCODE_LEGACY_TREE; -LLPCode LLToolPlacerPanel::sGrass = LL_PCODE_LEGACY_GRASS; - -S32 LLToolPlacerPanel::sButtonsAdded = 0; -LLButton* LLToolPlacerPanel::sButtons[ TOOL_PLACER_NUM_BUTTONS ]; - -LLToolPlacerPanel::LLToolPlacerPanel(const std::string& name, const LLRect& rect) - : - LLPanel( name, rect ) -{ - /* DEPRECATED - JC - addButton( "UIImgCubeUUID", "UIImgCubeSelectedUUID", &LLToolPlacerPanel::sCube ); - addButton( "UIImgPrismUUID", "UIImgPrismSelectedUUID", &LLToolPlacerPanel::sPrism ); - addButton( "UIImgPyramidUUID", "UIImgPyramidSelectedUUID", &LLToolPlacerPanel::sPyramid ); - addButton( "UIImgTetrahedronUUID", "UIImgTetrahedronSelectedUUID", &LLToolPlacerPanel::sTetrahedron ); - addButton( "UIImgCylinderUUID", "UIImgCylinderSelectedUUID", &LLToolPlacerPanel::sCylinder ); - addButton( "UIImgHalfCylinderUUID", "UIImgHalfCylinderSelectedUUID",&LLToolPlacerPanel::sCylinderHemi ); - addButton( "UIImgConeUUID", "UIImgConeSelectedUUID", &LLToolPlacerPanel::sCone ); - addButton( "UIImgHalfConeUUID", "UIImgHalfConeSelectedUUID", &LLToolPlacerPanel::sConeHemi ); - addButton( "UIImgSphereUUID", "UIImgSphereSelectedUUID", &LLToolPlacerPanel::sSphere ); - addButton( "UIImgHalfSphereUUID", "UIImgHalfSphereSelectedUUID", &LLToolPlacerPanel::sSphereHemi ); - addButton( "UIImgTreeUUID", "UIImgTreeSelectedUUID", &LLToolPlacerPanel::sTree ); - addButton( "UIImgGrassUUID", "UIImgGrassSelectedUUID", &LLToolPlacerPanel::sGrass ); - addButton( "ObjectTorusImageID", "ObjectTorusActiveImageID", &LLToolPlacerPanel::sTorus ); - addButton( "ObjectTubeImageID", "ObjectTubeActiveImageID", &LLToolPlacerPanel::sSquareTorus ); - */ -} - -void LLToolPlacerPanel::addButton( const std::string& up_state, const std::string& down_state, LLPCode* pcode ) -{ - const S32 TOOL_SIZE = 32; - const S32 HORIZ_SPACING = TOOL_SIZE + 5; - const S32 VERT_SPACING = TOOL_SIZE + 5; - const S32 VPAD = 10; - const S32 HPAD = 7; - - S32 row = sButtonsAdded / 4; - S32 column = sButtonsAdded % 4; - - LLRect help_rect = gSavedSettings.getRect("ToolHelpRect"); - - // Build the rectangle, recalling the origin is at lower left - // and we want the icons to build down from the top. - LLRect rect; - rect.setLeftTopAndSize( - HPAD + (column * HORIZ_SPACING), - help_rect.mBottom - VPAD - (row * VERT_SPACING), - TOOL_SIZE, - TOOL_SIZE ); - - LLButton* btn = new LLButton( - std::string("ToolPlacerOptBtn"), - rect, - up_state, - down_state, - LLStringUtil::null, &LLToolPlacerPanel::setObjectType, - pcode, - LLFontGL::getFontSansSerif()); - btn->setFollowsBottom(); - btn->setFollowsLeft(); - addChild(btn); - - sButtons[sButtonsAdded] = btn; - sButtonsAdded++; -} - -// static -void LLToolPlacerPanel::setObjectType( void* data ) -{ - LLPCode pcode = *(LLPCode*) data; - LLToolPlacer::setObjectType( pcode ); -} diff --git a/indra/newview/lltoolplacer.h b/indra/newview/lltoolplacer.h index d478f7b1c2..b7422380d4 100644 --- a/indra/newview/lltoolplacer.h +++ b/indra/newview/lltoolplacer.h @@ -67,43 +67,4 @@ private: BOOL addDuplicate(S32 x, S32 y); }; -//////////////////////////////////////////////////// -// LLToolPlacerPanel - - -const S32 TOOL_PLACER_NUM_BUTTONS = 14; - - -class LLToolPlacerPanel : public LLPanel -{ -public: - - LLToolPlacerPanel(const std::string& name, const LLRect& rect); - - static void setObjectType( void* data ); - - static LLPCode sCube; - static LLPCode sPrism; - static LLPCode sPyramid; - static LLPCode sTetrahedron; - static LLPCode sCylinder; - static LLPCode sCylinderHemi; - static LLPCode sCone; - static LLPCode sConeHemi; - static LLPCode sTorus; - static LLPCode sSquareTorus; - static LLPCode sTriangleTorus; - static LLPCode sSphere; - static LLPCode sSphereHemi; - static LLPCode sTree; - static LLPCode sGrass; - -private: - void addButton( const std::string& up_state, const std::string& down_state, LLPCode* pcode ); - -private: - static S32 sButtonsAdded; - static LLButton* sButtons[ TOOL_PLACER_NUM_BUTTONS ]; -}; - #endif diff --git a/indra/newview/lltoolselect.cpp b/indra/newview/lltoolselect.cpp index 80e99174c7..97e2865179 100644 --- a/indra/newview/lltoolselect.cpp +++ b/indra/newview/lltoolselect.cpp @@ -48,11 +48,11 @@ #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llworld.h" // Globals -extern BOOL gAllowSelectAvatar; +//extern BOOL gAllowSelectAvatar; const F32 SELECTION_ROTATION_TRESHOLD = 0.1f; @@ -87,7 +87,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi BOOL select_movable = gSavedSettings.getBOOL("SelectMovableOnly"); // *NOTE: These settings must be cleaned up at bottom of function. - if (temp_select || gAllowSelectAvatar) + if (temp_select || LLSelectMgr::getInstance()->mAllowSelectAvatar) { gSavedSettings.setBOOL("SelectOwnedOnly", FALSE); gSavedSettings.setBOOL("SelectMovableOnly", FALSE); @@ -217,7 +217,7 @@ LLObjectSelectionHandle LLToolSelect::handleObjectSelection(const LLPickInfo& pi } //if(!object) // Cleanup temp select settings above. - if (temp_select || gAllowSelectAvatar) + if (temp_select ||LLSelectMgr::getInstance()->mAllowSelectAvatar) { gSavedSettings.setBOOL("SelectOwnedOnly", select_owned); gSavedSettings.setBOOL("SelectMovableOnly", select_movable); diff --git a/indra/newview/lltoolselectland.cpp b/indra/newview/lltoolselectland.cpp index 91223904b7..5c8b08db3b 100644 --- a/indra/newview/lltoolselectland.cpp +++ b/indra/newview/lltoolselectland.cpp @@ -38,12 +38,10 @@ #include "llparcel.h" // Viewer includes -#include "llagent.h" #include "llviewercontrol.h" #include "llfloatertools.h" #include "llselectmgr.h" #include "llstatusbar.h" -#include "lltoolview.h" #include "llviewerparcelmgr.h" #include "llviewerwindow.h" @@ -177,13 +175,13 @@ BOOL LLToolSelectLand::handleHover(S32 x, S32 y, MASK mask) roundXY(mEastNorthTop); lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, land)" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); } else { mDragEndValid = FALSE; lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, no land)" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_NO); + gViewerWindow->setCursor(UI_CURSOR_NO); } mDragEndX = x; @@ -192,13 +190,13 @@ BOOL LLToolSelectLand::handleHover(S32 x, S32 y, MASK mask) else { lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (active, in slop)" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); } } else { lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectLand (inactive)" << llendl; - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); } return TRUE; diff --git a/indra/newview/lltoolselectrect.cpp b/indra/newview/lltoolselectrect.cpp index d544bff992..f87d1480d7 100644 --- a/indra/newview/lltoolselectrect.cpp +++ b/indra/newview/lltoolselectrect.cpp @@ -44,7 +44,6 @@ #include "llviewercontrol.h" #include "llui.h" #include "llselectmgr.h" -#include "lltoolview.h" #include "lltoolmgr.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" @@ -159,7 +158,7 @@ BOOL LLToolSelectRect::handleHover(S32 x, S32 y, MASK mask) lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolSelectRect (inactive)" << llendl; } - gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW); + gViewerWindow->setCursor(UI_CURSOR_ARROW); return TRUE; } diff --git a/indra/newview/lltoolview.cpp b/indra/newview/lltoolview.cpp index 9f6a77d245..f8393ebc47 100644 --- a/indra/newview/lltoolview.cpp +++ b/indra/newview/lltoolview.cpp @@ -65,9 +65,9 @@ LLToolContainer::~LLToolContainer() LLToolView::LLToolView(const std::string& name, const LLRect& rect) -: LLView(name, rect, MOUSE_OPAQUE), - mButtonCount(0) +: mButtonCount(0) { + LLView::init(LLView::Params().name(name).rect(rect).mouse_opaque(true)); } diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index d54cc798d2..5929ecd928 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -39,7 +39,7 @@ #include "llgl.h" #include "llrender.h" #include "llinventory.h" -#include "llmemory.h" +#include "llpointer.h" #include "llstring.h" #include "lluuid.h" #include "v3math.h" @@ -51,7 +51,6 @@ #include "lltracker.h" #include "llagent.h" #include "llcallingcard.h" -#include "llcolorscheme.h" #include "llfloaterworldmap.h" #include "llhudtext.h" #include "llhudview.h" @@ -113,12 +112,14 @@ void LLTracker::stopTracking(void* userdata) // static virtual void LLTracker::drawHUDArrow() { + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + /* tracking autopilot destination has been disabled -- 2004.01.09, Leviathan // Draw dot for autopilot target if (gAgent.getAutoPilot()) { - instance()->drawMarker( gAgent.getAutoPilotTargetGlobal(), gTrackColor ); + instance()->drawMarker( gAgent.getAutoPilotTargetGlobal(), map_track_color ); return; } */ @@ -128,12 +129,12 @@ void LLTracker::drawHUDArrow() // Tracked avatar if(LLAvatarTracker::instance().haveTrackingInfo()) { - instance()->drawMarker( LLAvatarTracker::instance().getGlobalPos(), gTrackColor ); + instance()->drawMarker( LLAvatarTracker::instance().getGlobalPos(), map_track_color ); } break; case TRACKING_LANDMARK: - instance()->drawMarker( getTrackedPositionGlobal(), gTrackColor ); + instance()->drawMarker( getTrackedPositionGlobal(), map_track_color ); break; case TRACKING_LOCATION: @@ -145,7 +146,7 @@ void LLTracker::drawHUDArrow() + 0.1f * (LLWorld::getInstance()->resolveLandHeightGlobal(getTrackedPositionGlobal()) + 1.5f); #endif instance()->mTrackedPositionGlobal.mdV[VZ] = llclamp((F32)instance()->mTrackedPositionGlobal.mdV[VZ], LLWorld::getInstance()->resolveLandHeightGlobal(getTrackedPositionGlobal()) + 1.5f, (F32)instance()->getTrackedPositionGlobal().mdV[VZ]); - instance()->drawMarker( getTrackedPositionGlobal(), gTrackColor ); + instance()->drawMarker( getTrackedPositionGlobal(), map_track_color ); break; default: @@ -161,7 +162,9 @@ void LLTracker::render3D() { return; } - + + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + // Arbitary location beacon if( instance()->mIsTrackingLocation ) { @@ -181,7 +184,7 @@ void LLTracker::render3D() } else { - renderBeacon( instance()->mTrackedPositionGlobal, gTrackColor, + renderBeacon( instance()->mTrackedPositionGlobal, map_track_color, instance()->mBeaconText, instance()->mTrackedLocationName ); } } @@ -223,7 +226,7 @@ void LLTracker::render3D() // and back again instance()->mHasReachedLandmark = FALSE; } - renderBeacon( instance()->mTrackedPositionGlobal, gTrackColor, + renderBeacon( instance()->mTrackedPositionGlobal, map_track_color, instance()->mBeaconText, instance()->mTrackedLandmarkName ); } } @@ -252,7 +255,7 @@ void LLTracker::render3D() } else { - renderBeacon( av_tracker.getGlobalPos(), gTrackColor, + renderBeacon( av_tracker.getGlobalPos(), map_track_color, instance()->mBeaconText, av_tracker.getName() ); } } diff --git a/indra/newview/lltracker.h b/indra/newview/lltracker.h index 2850365272..bfe9d6c6b5 100644 --- a/indra/newview/lltracker.h +++ b/indra/newview/lltracker.h @@ -40,7 +40,7 @@ #define LL_LLTRACKER_H #include "lldarray.h" -#include "llmemory.h" +#include "llpointer.h" #include "llstring.h" #include "lluuid.h" #include "v3dmath.h" diff --git a/indra/newview/lluploaddialog.cpp b/indra/newview/lluploaddialog.cpp index 7f63972c8d..153e3e7382 100644 --- a/indra/newview/lluploaddialog.cpp +++ b/indra/newview/lluploaddialog.cpp @@ -41,6 +41,7 @@ #include "llkeyboard.h" #include "llfocusmgr.h" #include "llviewercontrol.h" +#include "llrootview.h" // static LLUploadDialog* LLUploadDialog::sDialog = NULL; @@ -64,8 +65,7 @@ void LLUploadDialog::modalUploadFinished() // Private methods LLUploadDialog::LLUploadDialog( const std::string& msg) - : - LLPanel( std::string("Uploading..."), LLRect(0,100,100,0) ) // dummy rect. Will reshape below. + : LLPanel() { setBackgroundVisible( TRUE ); @@ -75,11 +75,16 @@ LLUploadDialog::LLUploadDialog( const std::string& msg) } LLUploadDialog::sDialog = this; - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); LLRect msg_rect; for (int line_num=0; line_num<16; ++line_num) { - mLabelBox[line_num] = new LLTextBox( std::string("Filename"), msg_rect, std::string("Filename"), font ); + LLTextBox::Params params; + params.name("Filename"); + params.rect(msg_rect); + params.text("Filename"); + params.font(font); + mLabelBox[line_num] = LLUICtrlFactory::create (params); addChild(mLabelBox[line_num]); } @@ -91,7 +96,7 @@ LLUploadDialog::LLUploadDialog( const std::string& msg) void LLUploadDialog::setMessage( const std::string& msg) { - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); const S32 VPAD = 16; const S32 HPAD = 25; @@ -139,7 +144,7 @@ void LLUploadDialog::setMessage( const std::string& msg) msg_rect.setOriginAndSize( msg_x, msg_y, max_msg_width, line_height ); mLabelBox[line_num]->setRect(msg_rect); mLabelBox[line_num]->setText(cur_line); - mLabelBox[line_num]->setColor( gColors.getColor( "LabelTextColor" ) ); + mLabelBox[line_num]->setColor( LLUIColorTable::instance().getColor( "LabelTextColor" ) ); mLabelBox[line_num]->setVisible(TRUE); msg_y -= line_height; ++line_num; diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 85ab44bc13..cb68045310 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -36,12 +36,14 @@ // viewer includes #include "llagent.h" // teleportViaLocation() #include "llcommandhandler.h" -#include "llfloaterurldisplay.h" #include "llfloaterdirectory.h" -#include "llfloaterhtml.h" +#include "llfloatermediabrowser.h" +#include "llfloaterreg.h" +#include "llfloaterurldisplay.h" #include "llfloaterworldmap.h" -#include "llfloaterhtmlhelp.h" #include "llpanellogin.h" +#include "llsidetray.h" +#include "llslurl.h" #include "llstartup.h" // gStartupState #include "llurlsimstring.h" #include "llweb.h" @@ -50,22 +52,11 @@ // library includes #include "llsd.h" -const std::string SLURL_SL_HELP_PREFIX = "secondlife://app."; -const std::string SLURL_SL_PREFIX = "sl://"; -const std::string SLURL_SECONDLIFE_PREFIX = "secondlife://"; -const std::string SLURL_SLURL_PREFIX = "http://slurl.com/secondlife/"; - -const std::string SLURL_APP_TOKEN = "app/"; - class LLURLDispatcherImpl { public: - static bool isSLURL(const std::string& url); - - static bool isSLURLCommand(const std::string& url); - static bool dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // returns true if handled or explicitly blocked. @@ -74,7 +65,7 @@ public: private: static bool dispatchCore(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // handles both left and right click @@ -84,7 +75,7 @@ private: static bool dispatchApp(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // Handles secondlife:///app/agent//about and similar // by showing panel in Search floater. @@ -104,39 +95,13 @@ private: // Called by LLWorldMap when a region name has been resolved to a // location in-world, used by places-panel display. - static bool matchPrefix(const std::string& url, const std::string& prefix); - - static std::string stripProtocol(const std::string& url); - friend class LLTeleportHandler; }; -// static -bool LLURLDispatcherImpl::isSLURL(const std::string& url) -{ - if (matchPrefix(url, SLURL_SL_HELP_PREFIX)) return true; - if (matchPrefix(url, SLURL_SL_PREFIX)) return true; - if (matchPrefix(url, SLURL_SECONDLIFE_PREFIX)) return true; - if (matchPrefix(url, SLURL_SLURL_PREFIX)) return true; - return false; -} - -// static -bool LLURLDispatcherImpl::isSLURLCommand(const std::string& url) -{ - if (matchPrefix(url, SLURL_SL_PREFIX + SLURL_APP_TOKEN) - || matchPrefix(url, SLURL_SECONDLIFE_PREFIX + "/" + SLURL_APP_TOKEN) - || matchPrefix(url, SLURL_SLURL_PREFIX + SLURL_APP_TOKEN) ) - { - return true; - } - return false; -} - // static bool LLURLDispatcherImpl::dispatchCore(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { if (url.empty()) return false; @@ -156,7 +121,7 @@ bool LLURLDispatcherImpl::dispatchCore(const std::string& url, // static bool LLURLDispatcherImpl::dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { llinfos << "url: " << url << llendl; @@ -169,7 +134,7 @@ bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url) { llinfos << "url: " << url << llendl; const bool right_click = true; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; return dispatchCore(url, right_click, web, trusted_browser); } @@ -178,7 +143,7 @@ bool LLURLDispatcherImpl::dispatchRightClick(const std::string& url) bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse) { #if LL_LIBXUL_ENABLED - if (matchPrefix(url, SLURL_SL_HELP_PREFIX)) + if (LLSLURL::isURLHelp(url)) { gViewerHtmlHelp.show(); return true; @@ -190,10 +155,10 @@ bool LLURLDispatcherImpl::dispatchHelp(const std::string& url, bool right_mouse) // static bool LLURLDispatcherImpl::dispatchApp(const std::string& url, bool right_mouse, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { - if (!isSLURL(url)) + if (!LLSLURL::isSLURL(url)) { return false; } @@ -211,7 +176,7 @@ bool LLURLDispatcherImpl::dispatchApp(const std::string& url, // static bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mouse) { - if (!isSLURL(url)) + if (!LLSLURL::isSLURL(url)) { return false; } @@ -230,15 +195,16 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mous return true; } - std::string sim_string = stripProtocol(url); + std::string sim_string = LLSLURL::stripProtocol(url); std::string region_name; S32 x = 128; S32 y = 128; S32 z = 0; LLURLSimString::parse(sim_string, ®ion_name, &x, &y, &z); - LLFloaterURLDisplay* url_displayp = LLFloaterURLDisplay::getInstance(LLSD()); - url_displayp->setName(region_name); + // LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray. + //LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance("preview_url",LLSD()); + //if(url_displayp) url_displayp->setName(region_name); // Request a region handle by name LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, @@ -251,7 +217,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mous /*static*/ void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport) { - std::string sim_string = stripProtocol(url); + std::string sim_string = LLSLURL::stripProtocol(url); std::string region_name; S32 x = 128; S32 y = 128; @@ -289,7 +255,7 @@ void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::strin /* static */ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport) { - std::string sim_string = stripProtocol(url); + std::string sim_string = LLSLURL::stripProtocol(url); std::string region_name; S32 x = 128; S32 y = 128; @@ -309,63 +275,43 @@ void LLURLDispatcherImpl::regionHandleCallback(U64 region_handle, const std::str local_pos.mV[VY] = (F32)local_y; local_pos.mV[VZ] = (F32)z; - + LLVector3d global_pos = from_region_handle(region_handle); + global_pos += LLVector3d(local_pos); if (teleport) - { - LLVector3d global_pos = from_region_handle(region_handle); - global_pos += LLVector3d(local_pos); + { gAgent.teleportViaLocation(global_pos); - if(gFloaterWorldMap) + LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); + if(instance) { - gFloaterWorldMap->trackLocation(global_pos); + instance->trackLocation(global_pos); } } else { - // display informational floater, allow user to click teleport btn - LLFloaterURLDisplay* url_displayp = LLFloaterURLDisplay::getInstance(LLSD()); + LLSD key; + key["type"] = "remote_place"; + key["x"] = global_pos.mdV[VX]; + key["y"] = global_pos.mdV[VY]; + key["z"] = global_pos.mdV[VZ]; + LLSideTray::getInstance()->showPanel("panel_places", key); - url_displayp->displayParcelInfo(region_handle, local_pos); - if(snapshot_id.notNull()) - { - url_displayp->setSnapshotDisplay(snapshot_id); - } - std::string locationString = llformat("%s %d, %d, %d", region_name.c_str(), x, y, z); - url_displayp->setLocationString(locationString); - } -} + // LLFloaterURLDisplay functionality moved to LLPanelPlaces in Side Tray. -// static -bool LLURLDispatcherImpl::matchPrefix(const std::string& url, const std::string& prefix) -{ - std::string test_prefix = url.substr(0, prefix.length()); - LLStringUtil::toLower(test_prefix); - return test_prefix == prefix; -} - -// static -std::string LLURLDispatcherImpl::stripProtocol(const std::string& url) -{ - std::string stripped = url; - if (matchPrefix(stripped, SLURL_SL_HELP_PREFIX)) - { - stripped.erase(0, SLURL_SL_HELP_PREFIX.length()); +// // display informational floater, allow user to click teleport btn +// LLFloaterURLDisplay* url_displayp = LLFloaterReg::getTypedInstance("preview_url",LLSD()); +// if(url_displayp) +// { +// url_displayp->displayParcelInfo(region_handle, local_pos); +// if(snapshot_id.notNull()) +// { +// url_displayp->setSnapshotDisplay(snapshot_id); +// } +// std::string locationString = llformat("%s %d, %d, %d", region_name.c_str(), x, y, z); +// url_displayp->setLocationString(locationString); +// } } - else if (matchPrefix(stripped, SLURL_SL_PREFIX)) - { - stripped.erase(0, SLURL_SL_PREFIX.length()); - } - else if (matchPrefix(stripped, SLURL_SECONDLIFE_PREFIX)) - { - stripped.erase(0, SLURL_SECONDLIFE_PREFIX.length()); - } - else if (matchPrefix(stripped, SLURL_SLURL_PREFIX)) - { - stripped.erase(0, SLURL_SLURL_PREFIX.length()); - } - return stripped; } //--------------------------------------------------------------------------- @@ -380,7 +326,7 @@ public: LLTeleportHandler() : LLCommandHandler("teleport", true) { } bool handle(const LLSD& tokens, const LLSD& query_map, - LLWebBrowserCtrl* web) + LLMediaCtrl* web) { // construct a "normal" SLURL, resolve the region to // a global position, and teleport to it @@ -390,7 +336,7 @@ public: std::string region_name = LLURLSimString::unescapeRegionName(tokens[0]); // build secondlife://De%20Haro/123/45/67 for use in callback - std::string url = SLURL_SECONDLIFE_PREFIX; + std::string url = LLSLURL::PREFIX_SECONDLIFE; for (int i = 0; i < tokens.size(); ++i) { url += tokens[i].asString() + "/"; @@ -406,21 +352,9 @@ LLTeleportHandler gTeleportHandler; //--------------------------------------------------------------------------- -// static -bool LLURLDispatcher::isSLURL(const std::string& url) -{ - return LLURLDispatcherImpl::isSLURL(url); -} - -// static -bool LLURLDispatcher::isSLURLCommand(const std::string& url) -{ - return LLURLDispatcherImpl::isSLURLCommand(url); -} - // static bool LLURLDispatcher::dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser) { return LLURLDispatcherImpl::dispatch(url, web, trusted_browser); @@ -442,15 +376,6 @@ bool LLURLDispatcher::dispatchFromTextEditor(const std::string& url) // click on it. // *TODO: Make this trust model more refined. JC const bool trusted_browser = true; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; return LLURLDispatcherImpl::dispatch(url, web, trusted_browser); } - -// static -std::string LLURLDispatcher::buildSLURL(const std::string& regionname, - S32 x, S32 y, S32 z) -{ - std::string slurl = SLURL_SLURL_PREFIX + regionname + llformat("/%d/%d/%d",x,y,z); - slurl = LLWeb::escapeURL( slurl ); - return slurl; -} diff --git a/indra/newview/llurldispatcher.h b/indra/newview/llurldispatcher.h index a4f6866a07..ff8a351253 100644 --- a/indra/newview/llurldispatcher.h +++ b/indra/newview/llurldispatcher.h @@ -32,20 +32,14 @@ #ifndef LLURLDISPATCHER_H #define LLURLDISPATCHER_H -class LLWebBrowserCtrl; +class LLMediaCtrl; class LLURLDispatcher { public: - static bool isSLURL(const std::string& url); - // Is this any sort of secondlife:// or sl:// URL? - - static bool isSLURLCommand(const std::string& url); - // Is this a special secondlife://app/ URL? - static bool dispatch(const std::string& url, - LLWebBrowserCtrl* web, + LLMediaCtrl* web, bool trusted_browser); // At startup time and on clicks in internal web browsers, // teleport, open map, or run requested command. @@ -54,7 +48,7 @@ public: // secondlife:///app/agent/3d6181b0-6a4b-97ef-18d8-722652995cf1/show // sl://app/foo/bar // @param web - // Pointer to LLWebBrowserCtrl sending URL, can be NULL + // Pointer to LLMediaCtrl sending URL, can be NULL // @param trusted_browser // True if coming inside the app AND from a brower instance // that navigates to trusted (Linden Lab) pages. @@ -63,9 +57,6 @@ public: static bool dispatchRightClick(const std::string& url); static bool dispatchFromTextEditor(const std::string& url); - - static std::string buildSLURL(const std::string& regionname, S32 x, S32 y, S32 z); - // builds: http://slurl.com/secondlife/RegionName/x/y/z/ }; #endif diff --git a/indra/newview/llurllineeditorctrl.cpp b/indra/newview/llurllineeditorctrl.cpp new file mode 100644 index 0000000000..046b3e619b --- /dev/null +++ b/indra/newview/llurllineeditorctrl.cpp @@ -0,0 +1,97 @@ +/** + * @file llurllineeditorctrl.cpp + * @brief LLURLLineEditor base class + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llclipboard.h" +#include "lluictrlfactory.h" + +#include "llurllineeditorctrl.h" + +#include "llweb.h" + +//Constructor +LLURLLineEditor::LLURLLineEditor(const LLLineEditor::Params& p) +: LLLineEditor(p){ + +} + +// copy selection to clipboard +void LLURLLineEditor::copy() +{ + if( canCopy() ) + { + copyEscapedURLToClipboard(); + } +} + +// cut selection to clipboard +void LLURLLineEditor::cut() +{ + if( canCut() ) + { + // Prepare for possible rollback + LLURLLineEditorRollback rollback( this ); + + copyEscapedURLToClipboard(); + + deleteSelection(); + + // Validate new string and rollback the if needed. + BOOL need_to_rollback = ( mPrevalidateFunc && !mPrevalidateFunc( mText.getWString() ) ); + if( need_to_rollback ) + { + rollback.doRollback( this ); + reportBadKeystroke(); + } + else + if( mKeystrokeCallback ) + { + mKeystrokeCallback( this ); + } + } +} +// Copies escaped URL to clipboard +void LLURLLineEditor::copyEscapedURLToClipboard() +{ + S32 left_pos = llmin( mSelectionStart, mSelectionEnd ); + S32 length = llabs( mSelectionStart - mSelectionEnd ); + + const std::string unescaped_text = wstring_to_utf8str(mText.getWString().substr(left_pos, length)); + LLWString selected_escaped_text = utf8str_to_wstring(LLWeb::escapeURL(unescaped_text)); + gClipboard.copyFromString( selected_escaped_text ); +} +// Makes UISndBadKeystroke sound +void LLURLLineEditor::reportBadKeystroke() +{ + make_ui_sound("UISndBadKeystroke"); +} diff --git a/indra/newview/llurllineeditorctrl.h b/indra/newview/llurllineeditorctrl.h new file mode 100644 index 0000000000..618f29dfbf --- /dev/null +++ b/indra/newview/llurllineeditorctrl.h @@ -0,0 +1,100 @@ +/** + * @file llurllineeditorctrl.h + * @brief Combobox-like location input control + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLURLLINEEDITOR_H_ +#define LLURLLINEEDITOR_H_ + +#include "linden_common.h" + +#include "lllineeditor.h" +#include "lluictrl.h" + +// LLURLLineEditor class performing escaping of an URL while copying or cutting the target text +class LLURLLineEditor: public LLLineEditor { + LOG_CLASS( LLURLLineEditor); + +public: + // LLLineEditor overrides to do necessary escaping + /*virtual*/ void copy(); + /*virtual*/ void cut(); + +protected: + LLURLLineEditor(const Params&); + friend class LLUICtrlFactory; + friend class LLFloaterEditUI; + +private: + // util function to escape selected text and copy it to clipboard + void copyEscapedURLToClipboard(); + // send a beep signal if keystroke is bad. As it is private at LLLineEditor we need own function + void reportBadKeystroke(); + + // Helper class to do rollback if needed + class LLURLLineEditorRollback + { + public: + LLURLLineEditorRollback( LLURLLineEditor* ed ) + : + mCursorPos( ed->mCursorPos ), + mScrollHPos( ed->mScrollHPos ), + mIsSelecting( ed->mIsSelecting ), + mSelectionStart( ed->mSelectionStart ), + mSelectionEnd( ed->mSelectionEnd ) + { + mText = ed->getText(); + } + + void doRollback( LLURLLineEditor* ed ) + { + ed->mCursorPos = mCursorPos; + ed->mScrollHPos = mScrollHPos; + ed->mIsSelecting = mIsSelecting; + ed->mSelectionStart = mSelectionStart; + ed->mSelectionEnd = mSelectionEnd; + ed->mText = mText; + ed->mPrevText = mText; + } + + std::string getText() { return mText; } + + private: + std::string mText; + S32 mCursorPos; + S32 mScrollHPos; + BOOL mIsSelecting; + S32 mSelectionStart; + S32 mSelectionEnd; + }; // end class LLURLLineEditorRollback + +}; + +#endif /* LLURLLINEEDITOR_H_ */ diff --git a/indra/newview/llviewchildren.cpp b/indra/newview/llviewchildren.cpp index 1a66b24891..842ffc7f9a 100644 --- a/indra/newview/llviewchildren.cpp +++ b/indra/newview/llviewchildren.cpp @@ -94,10 +94,10 @@ void LLViewChildren::setBadge(const std::string& id, Badge badge, bool visible) switch (badge) { default: - case BADGE_OK: child->setImage(std::string("badge_ok.j2c")); break; - case BADGE_NOTE: child->setImage(std::string("badge_note.j2c")); break; - case BADGE_WARN: child->setImage(std::string("badge_warn.j2c")); break; - case BADGE_ERROR: child->setImage(std::string("badge_error.j2c")); break; + case BADGE_OK: child->setValue(std::string("badge_ok.j2c")); break; + case BADGE_NOTE: child->setValue(std::string("badge_note.j2c")); break; + case BADGE_WARN: child->setValue(std::string("badge_warn.j2c")); break; + case BADGE_ERROR: child->setValue(std::string("badge_error.j2c")); break; } } } diff --git a/indra/newview/llviewerassetstorage.h b/indra/newview/llviewerassetstorage.h index 15c11c7025..512b590a1b 100644 --- a/indra/newview/llviewerassetstorage.h +++ b/indra/newview/llviewerassetstorage.h @@ -47,6 +47,7 @@ public: LLViewerAssetStorage(LLMessageSystem *msg, LLXferManager *xfer, LLVFS *vfs); + using LLAssetStorage::storeAssetData; virtual void storeAssetData( const LLTransactionID& tid, LLAssetType::EType atype, diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index a1e55c1137..49506db173 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -32,7 +32,7 @@ #include "llviewerprecompiledheaders.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llappviewer.h" #include "llvieweraudio.h" @@ -128,7 +128,6 @@ void audio_update_volume(bool force_update) gAudiop->setMasterGain ( master_volume ); gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler")); - gAudiop->setDistanceFactor(gSavedSettings.getF32("AudioLevelDistance")); gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff")); #ifdef kAUDIO_ENABLE_WIND gAudiop->enableWind(!mute_audio); diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp index 72d1494d96..3f3c10a7c7 100644 --- a/indra/newview/llviewercamera.cpp +++ b/indra/newview/llviewercamera.cpp @@ -31,18 +31,12 @@ */ #include "llviewerprecompiledheaders.h" + #include "llviewercamera.h" -#include // for setprecision - -#include "llquaternion.h" - +// Viewer includes #include "llagent.h" #include "llviewercontrol.h" -#include "lldrawable.h" -#include "llface.h" -#include "llgl.h" -#include "llglheaders.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llviewerwindow.h" @@ -51,6 +45,17 @@ #include "lltoolmgr.h" #include "llviewerjoystick.h" +// Linden library includes +#include "lldrawable.h" +#include "llface.h" +#include "llgl.h" +#include "llglheaders.h" +#include "llquaternion.h" +#include "llwindow.h" // getPixelAspectRatio() + +// System includes +#include // for setprecision + //glu pick matrix implementation borrowed from Mesa3D glh::matrix4f gl_pick_matrix(GLfloat x, GLfloat y, GLfloat width, GLfloat height, GLint* viewport) { @@ -106,6 +111,7 @@ LLViewerCamera::LLViewerCamera() : LLCamera() mScreenPixelArea = 0; mZoomFactor = 1.f; mZoomSubregion = 1; + gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2)); } void LLViewerCamera::updateCameraLocation(const LLVector3 ¢er, @@ -452,8 +458,15 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord } } + LLRect world_view_rect = gViewerWindow->getWorldViewRect(); + S32 viewport[4]; + viewport[0] = world_view_rect.mLeft; + viewport[1] = world_view_rect.mBottom; + viewport[2] = world_view_rect.getWidth(); + viewport[3] = world_view_rect.getHeight(); + if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], - gGLModelView, gGLProjection, (GLint*)gGLViewport, + gGLModelView, gGLProjection, (GLint*)viewport, &x, &y, &z)) { // convert screen coordinates to virtual UI coordinates @@ -461,9 +474,9 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord y /= gViewerWindow->getDisplayScale().mV[VY]; // should now have the x,y coords of grab_point in screen space - const LLRect& window_rect = gViewerWindow->getWindowRect(); + LLRect world_view_rect = gViewerWindow->getVirtualWorldViewRect(); - // ...sanity check + // convert to pixel coordinates S32 int_x = lltrunc(x); S32 int_y = lltrunc(y); @@ -471,14 +484,14 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord if (clamp) { - if (int_x < window_rect.mLeft) + if (int_x < world_view_rect.mLeft) { - out_point.mX = window_rect.mLeft; + out_point.mX = world_view_rect.mLeft; valid = FALSE; } - else if (int_x > window_rect.mRight) + else if (int_x > world_view_rect.mRight) { - out_point.mX = window_rect.mRight; + out_point.mX = world_view_rect.mRight; valid = FALSE; } else @@ -486,14 +499,14 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord out_point.mX = int_x; } - if (int_y < window_rect.mBottom) + if (int_y < world_view_rect.mBottom) { - out_point.mY = window_rect.mBottom; + out_point.mY = world_view_rect.mBottom; valid = FALSE; } - else if (int_y > window_rect.mTop) + else if (int_y > world_view_rect.mTop) { - out_point.mY = window_rect.mTop; + out_point.mY = world_view_rect.mTop; valid = FALSE; } else @@ -507,19 +520,19 @@ BOOL LLViewerCamera::projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoord out_point.mX = int_x; out_point.mY = int_y; - if (int_x < window_rect.mLeft) + if (int_x < world_view_rect.mLeft) { valid = FALSE; } - else if (int_x > window_rect.mRight) + else if (int_x > world_view_rect.mRight) { valid = FALSE; } - if (int_y < window_rect.mBottom) + if (int_y < world_view_rect.mBottom) { valid = FALSE; } - else if (int_y > window_rect.mTop) + else if (int_y > world_view_rect.mTop) { valid = FALSE; } @@ -548,24 +561,30 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, in_front = FALSE; } + LLRect world_view_rect = gViewerWindow->getWorldViewRect(); + S32 viewport[4]; + viewport[0] = world_view_rect.mLeft; + viewport[1] = world_view_rect.mBottom; + viewport[2] = world_view_rect.getWidth(); + viewport[3] = world_view_rect.getHeight(); GLdouble x, y, z; // object's window coords, GL-style if (GL_TRUE == gluProject(pos_agent.mV[VX], pos_agent.mV[VY], pos_agent.mV[VZ], gGLModelView, - gGLProjection, (GLint*)gGLViewport, + gGLProjection, (GLint*)viewport, &x, &y, &z)) { x /= gViewerWindow->getDisplayScale().mV[VX]; y /= gViewerWindow->getDisplayScale().mV[VY]; // should now have the x,y coords of grab_point in screen space - const LLRect& window_rect = gViewerWindow->getVirtualWindowRect(); + const LLRect& world_rect = gViewerWindow->getVirtualWorldViewRect(); // ...sanity check S32 int_x = lltrunc(x); S32 int_y = lltrunc(y); // find the center - GLdouble center_x = (GLdouble)(0.5f * (window_rect.mLeft + window_rect.mRight)); - GLdouble center_y = (GLdouble)(0.5f * (window_rect.mBottom + window_rect.mTop)); + GLdouble center_x = (GLdouble)world_rect.getCenterX(); + GLdouble center_y = (GLdouble)world_rect.getCenterY(); if (x == center_x && y == center_y) { @@ -586,41 +605,41 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, // the slope of the line is undefined if (line_y > 0.f) { - int_y = window_rect.mTop; + int_y = world_rect.mTop; } else { - int_y = window_rect.mBottom; + int_y = world_rect.mBottom; } } - else if (0 == window_rect.getWidth()) + else if (0 == world_rect.getWidth()) { // the diagonal slope of the view is undefined - if (y < window_rect.mBottom) + if (y < world_rect.mBottom) { - int_y = window_rect.mBottom; + int_y = world_rect.mBottom; } - else if ( y > window_rect.mTop) + else if ( y > world_rect.mTop) { - int_y = window_rect.mTop; + int_y = world_rect.mTop; } } else { F32 line_slope = (F32)(line_y / line_x); - F32 rect_slope = ((F32)window_rect.getHeight()) / ((F32)window_rect.getWidth()); + F32 rect_slope = ((F32)world_rect.getHeight()) / ((F32)world_rect.getWidth()); if (fabs(line_slope) > rect_slope) { if (line_y < 0.f) { // bottom - int_y = window_rect.mBottom; + int_y = world_rect.mBottom; } else { // top - int_y = window_rect.mTop; + int_y = world_rect.mTop; } int_x = lltrunc(((GLdouble)int_y - center_y) / line_slope + center_x); } @@ -629,12 +648,12 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, if (line_x < 0.f) { // left - int_x = window_rect.mLeft; + int_x = world_rect.mLeft; } else { // right - int_x = window_rect.mRight; + int_x = world_rect.mRight; } int_y = lltrunc(((GLdouble)int_x - center_x) * line_slope + center_y); } @@ -643,29 +662,30 @@ BOOL LLViewerCamera::projectPosAgentToScreenEdge(const LLVector3 &pos_agent, // exactly parallel ==> push to the corners if (line_x > 0.f) { - int_x = window_rect.mRight; + int_x = world_rect.mRight; } else { - int_x = window_rect.mLeft; + int_x = world_rect.mLeft; } if (line_y > 0.0f) { - int_y = window_rect.mTop; + int_y = world_rect.mTop; } else { - int_y = window_rect.mBottom; + int_y = world_rect.mBottom; } } } if (!in_front) { - int_x = window_rect.mLeft + window_rect.mRight - int_x; - int_y = window_rect.mBottom + window_rect.mTop - int_y; + int_x = world_rect.mLeft + world_rect.mRight - int_x; + int_y = world_rect.mBottom + world_rect.mTop - int_y; } - out_point.mX = int_x; - out_point.mY = int_y; + + out_point.mX = int_x + world_rect.mLeft; + out_point.mY = int_y + world_rect.mBottom; return TRUE; } return FALSE; @@ -803,3 +823,11 @@ void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) { mCameraFOVDefault = vertical_fov_rads; } + +// static +void LLViewerCamera::updateCameraAngle( void* user_data, const LLSD& value) +{ + LLViewerCamera* self=(LLViewerCamera*)user_data; + self->setDefaultFOV(value.asReal()); +} + diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h index 6a0c42beec..b99dd39584 100644 --- a/indra/newview/llviewercamera.h +++ b/indra/newview/llviewercamera.h @@ -34,8 +34,9 @@ #define LL_LLVIEWERCAMERA_H #include "llcamera.h" -#include "lltimer.h" +#include "llsingleton.h" #include "llstat.h" +#include "lltimer.h" #include "m4math.h" class LLCoordGL; @@ -61,6 +62,7 @@ public: const LLVector3 &point_of_interest); static void updateFrustumPlanes(LLCamera& camera, BOOL ortho = FALSE, BOOL zflip = FALSE, BOOL no_hacks = FALSE); + static void updateCameraAngle(void* user_data, const LLSD& value); void setPerspective(BOOL for_selection, S32 x, S32 y_from_bot, S32 width, S32 height, BOOL limit_select_distance, F32 z_near = 0, F32 z_far = 0); const LLMatrix4 &getProjection() const; diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index eb8cdd82b3..2c1707e49f 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -35,24 +35,25 @@ #include "llviewercontrol.h" -#include "indra_constants.h" +// Library includes +#include "llwindow.h" // getGamma() // For Listeners -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llconsole.h" #include "lldrawpoolterrain.h" #include "llflexibleobject.h" #include "llfeaturemanager.h" #include "llviewershadermgr.h" -#include "llpanelgeneral.h" -#include "llpanelinput.h" + #include "llsky.h" #include "llvieweraudio.h" -#include "llviewerimagelist.h" +#include "llviewermenu.h" +#include "llviewertexturelist.h" #include "llviewerthrottle.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvoiceclient.h" #include "llvosky.h" #include "llvotree.h" @@ -77,11 +78,10 @@ BOOL gHackGodmode = FALSE; #endif -std::map gSettings; -LLControlGroup gSavedSettings; // saved at end of session -LLControlGroup gSavedPerAccountSettings; // saved at end of session -LLControlGroup gColors; // read-only -LLControlGroup gCrashSettings; // saved at end of session +LLControlGroup gSavedSettings("Global"); // saved at end of session +LLControlGroup gSavedPerAccountSettings("PerAccount"); // saved at end of session +LLControlGroup gCrashSettings("CrashSettings"); // saved at end of session +LLControlGroup gWarningSettings("Warnings"); // persists ignored dialogs/warnings std::string gLastRunVersion; std::string gCurrentVersion; @@ -121,7 +121,7 @@ static bool handleSetShaderChanged(const LLSD& newvalue) static bool handleSetSelfInvisible( const LLSD& newvalue) { - LLVOAvatar::onChangeSelfInvisible( newvalue.asBoolean() ); + LLVOAvatarSelf::onChangeSelfInvisible( newvalue.asBoolean() ); return true; } @@ -213,7 +213,7 @@ static bool handleMaxPartCountChanged(const LLSD& newvalue) static bool handleVideoMemoryChanged(const LLSD& newvalue) { - gImageList.updateMaxResidentTexMem(newvalue.asInteger()); + gTextureList.updateMaxResidentTexMem(newvalue.asInteger()); return true; } @@ -378,7 +378,7 @@ static bool handleRenderUseImpostorsChanged(const LLSD& newvalue) static bool handleRenderDebugGLChanged(const LLSD& newvalue) { - gDebugGL = newvalue.asBoolean(); + gDebugGL = newvalue.asBoolean() || gDebugSession; gGL.clearErrors(); return true; } @@ -427,6 +427,16 @@ bool handleVectorizeChanged(const LLSD& newvalue) return true; } +bool handleHighResSnapshotChanged(const LLSD& newvalue) +{ + // High Res Snapshot active, must uncheck RenderUIInSnapshot + if (newvalue.asBoolean()) + { + gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE ); + } + return true; +} + bool handleVoiceClientPrefsChanged(const LLSD& newvalue) { if(gVoiceClient) @@ -436,217 +446,163 @@ bool handleVoiceClientPrefsChanged(const LLSD& newvalue) return true; } +bool handleVelocityInterpolate(const LLSD& newvalue) +{ + LLMessageSystem* msg = gMessageSystem; + if ( newvalue.asBoolean() ) + { + msg->newMessageFast(_PREHASH_VelocityInterpolateOn); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + llinfos << "Velocity Interpolation On" << llendl; + } + else + { + msg->newMessageFast(_PREHASH_VelocityInterpolateOff); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + gAgent.sendReliableMessage(); + llinfos << "Velocity Interpolation Off" << llendl; + } + return true; +} + //////////////////////////////////////////////////////////////////////////// void settings_setup_listeners() { - gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _1)); - gSavedSettings.getControl("RenderFarClip")->getSignal()->connect(boost::bind(&handleRenderFarClipChanged, _1)); - gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _1)); - gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); - gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); - gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("EnableRippleWater")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); - gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("RenderAvatarMaxVisible")->getSignal()->connect(boost::bind(&handleAvatarMaxVisibleChanged, _1)); - gSavedSettings.getControl("RenderAvatarInvisible")->getSignal()->connect(boost::bind(&handleSetSelfInvisible, _1)); - gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _1)); - gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _1)); - gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _1)); - gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _1)); - gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _1)); - gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _1)); - gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _1)); - gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _1)); - gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _1)); - gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _1)); - gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); - gSavedSettings.getControl("RenderFastAlpha")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); - gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); - gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _1)); - gSavedSettings.getControl("RenderUseFBO")->getSignal()->connect(boost::bind(&handleRenderUseFBOChanged, _1)); - gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _1)); - gSavedSettings.getControl("RenderUseImpostors")->getSignal()->connect(boost::bind(&handleRenderUseImpostorsChanged, _1)); - gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _1)); - gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _1)); - gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _1)); - gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _1)); - gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _1)); - gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _1)); - gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _1)); - gSavedSettings.getControl("ConsoleMaxLines")->getSignal()->connect(boost::bind(&handleConsoleMaxLinesChanged, _1)); - gSavedSettings.getControl("UploadBakedTexOld")->getSignal()->connect(boost::bind(&handleUploadBakedTexOldChanged, _1)); - gSavedSettings.getControl("UseOcclusion")->getSignal()->connect(boost::bind(&handleUseOcclusionChanged, _1)); - gSavedSettings.getControl("AudioLevelMaster")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelSFX")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelDistance")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _1)); - gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _1)); - gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _1)); - gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _1)); - gSavedSettings.getControl("RenderLightingDetail")->getSignal()->connect(boost::bind(&handleRenderLightingDetailChanged, _1)); - gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _1)); - gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("JoystickAxis6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisScale6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("FlycamAxisDeadZone6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("AvatarAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("BuildAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _1)); - gSavedSettings.getControl("DebugViews")->getSignal()->connect(boost::bind(&handleDebugViewsChanged, _1)); - gSavedSettings.getControl("UserLogFile")->getSignal()->connect(boost::bind(&handleLogFileChanged, _1)); - gSavedSettings.getControl("RenderHideGroupTitle")->getSignal()->connect(boost::bind(handleHideGroupTitleChanged, _1)); - gSavedSettings.getControl("EffectColor")->getSignal()->connect(boost::bind(handleEffectColorChanged, _1)); - gSavedSettings.getControl("VectorizePerfTest")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _1)); - gSavedSettings.getControl("VectorizeEnable")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _1)); - gSavedSettings.getControl("VectorizeProcessor")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _1)); - gSavedSettings.getControl("VectorizeSkin")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _1)); - gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("PTTCurrentlyEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("PushToTalkButton")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("PushToTalkToggle")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("VoiceEarLocation")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("VoiceInputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("VoiceOutputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _1)); + gSavedSettings.getControl("FirstPersonAvatarVisible")->getSignal()->connect(boost::bind(&handleRenderAvatarMouselookChanged, _2)); + gSavedSettings.getControl("RenderFarClip")->getSignal()->connect(boost::bind(&handleRenderFarClipChanged, _2)); + gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _2)); + gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); + gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("EnableRippleWater")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("RenderGlowResolutionPow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); + gSavedSettings.getControl("RenderAvatarCloth")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("WindLightUseAtmosShaders")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("RenderGammaFull")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("RenderAvatarMaxVisible")->getSignal()->connect(boost::bind(&handleAvatarMaxVisibleChanged, _2)); + gSavedSettings.getControl("RenderAvatarInvisible")->getSignal()->connect(boost::bind(&handleSetSelfInvisible, _2)); + gSavedSettings.getControl("RenderVolumeLODFactor")->getSignal()->connect(boost::bind(&handleVolumeLODChanged, _2)); + gSavedSettings.getControl("RenderAvatarLODFactor")->getSignal()->connect(boost::bind(&handleAvatarLODChanged, _2)); + gSavedSettings.getControl("RenderTerrainLODFactor")->getSignal()->connect(boost::bind(&handleTerrainLODChanged, _2)); + gSavedSettings.getControl("RenderTreeLODFactor")->getSignal()->connect(boost::bind(&handleTreeLODChanged, _2)); + gSavedSettings.getControl("RenderFlexTimeFactor")->getSignal()->connect(boost::bind(&handleFlexLODChanged, _2)); + gSavedSettings.getControl("ThrottleBandwidthKBPS")->getSignal()->connect(boost::bind(&handleBandwidthChanged, _2)); + gSavedSettings.getControl("RenderGamma")->getSignal()->connect(boost::bind(&handleGammaChanged, _2)); + gSavedSettings.getControl("RenderFogRatio")->getSignal()->connect(boost::bind(&handleFogRatioChanged, _2)); + gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2)); + gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2)); + gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderFastAlpha")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2)); + gSavedSettings.getControl("RenderUseFBO")->getSignal()->connect(boost::bind(&handleRenderUseFBOChanged, _2)); + gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2)); + gSavedSettings.getControl("RenderUseImpostors")->getSignal()->connect(boost::bind(&handleRenderUseImpostorsChanged, _2)); + gSavedSettings.getControl("RenderDebugGL")->getSignal()->connect(boost::bind(&handleRenderDebugGLChanged, _2)); + gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2)); + gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2)); + gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2)); + gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2)); + gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2)); + gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _2)); + gSavedSettings.getControl("ConsoleMaxLines")->getSignal()->connect(boost::bind(&handleConsoleMaxLinesChanged, _2)); + gSavedSettings.getControl("UploadBakedTexOld")->getSignal()->connect(boost::bind(&handleUploadBakedTexOldChanged, _2)); + gSavedSettings.getControl("UseOcclusion")->getSignal()->connect(boost::bind(&handleUseOcclusionChanged, _2)); + gSavedSettings.getControl("AudioLevelMaster")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelSFX")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("AudioStreamingMusic")->getSignal()->connect(boost::bind(&handleAudioStreamMusicChanged, _2)); + gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("MuteVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2)); + gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2)); + gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2)); + gSavedSettings.getControl("RenderLightingDetail")->getSignal()->connect(boost::bind(&handleRenderLightingDetailChanged, _2)); + gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2)); + gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("JoystickAxis6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisScale6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("FlycamAxisDeadZone6")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("AvatarAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisScale5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone2")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone3")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone4")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("BuildAxisDeadZone5")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2)); + gSavedSettings.getControl("DebugViews")->getSignal()->connect(boost::bind(&handleDebugViewsChanged, _2)); + gSavedSettings.getControl("UserLogFile")->getSignal()->connect(boost::bind(&handleLogFileChanged, _2)); + gSavedSettings.getControl("RenderHideGroupTitle")->getSignal()->connect(boost::bind(handleHideGroupTitleChanged, _2)); + gSavedSettings.getControl("HighResSnapshot")->getSignal()->connect(boost::bind(handleHighResSnapshotChanged, _2)); + gSavedSettings.getControl("VectorizePerfTest")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _2)); + gSavedSettings.getControl("VectorizeEnable")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _2)); + gSavedSettings.getControl("VectorizeProcessor")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _2)); + gSavedSettings.getControl("VectorizeSkin")->getSignal()->connect(boost::bind(&handleVectorizeChanged, _2)); + gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("PTTCurrentlyEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("PushToTalkButton")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("PushToTalkToggle")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("VoiceEarLocation")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("VoiceInputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("VoiceOutputAudioDevice")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("AudioLevelMic")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceClientPrefsChanged, _2)); + gSavedSettings.getControl("VelocityInterpolate")->getSignal()->connect(boost::bind(&handleVelocityInterpolate, _2)); + gSavedSettings.getControl("QAMode")->getSignal()->connect(boost::bind(&show_debug_menus)); + gSavedSettings.getControl("UseDebugMenus")->getSignal()->connect(boost::bind(&show_debug_menus)); } -template <> eControlType get_control_type(const U32& in, LLSD& out) -{ - out = (LLSD::Integer)in; - return TYPE_U32; -} - -template <> eControlType get_control_type(const S32& in, LLSD& out) -{ - out = in; - return TYPE_S32; -} - -template <> eControlType get_control_type(const F32& in, LLSD& out) -{ - out = in; - return TYPE_F32; -} - -template <> eControlType get_control_type (const bool& in, LLSD& out) -{ - out = in; - return TYPE_BOOLEAN; -} -/* -// Yay BOOL, its really an S32. -template <> eControlType get_control_type (const BOOL& in, LLSD& out) -{ - out = in; - return TYPE_BOOLEAN; -} -*/ -template <> eControlType get_control_type(const std::string& in, LLSD& out) -{ - out = in; - return TYPE_STRING; -} - -template <> eControlType get_control_type(const LLVector3& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_VEC3; -} - -template <> eControlType get_control_type(const LLVector3d& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_VEC3D; -} - -template <> eControlType get_control_type(const LLRect& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_RECT; -} - -template <> eControlType get_control_type(const LLColor4& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_COL4; -} - -template <> eControlType get_control_type(const LLColor3& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_COL3; -} - -template <> eControlType get_control_type(const LLColor4U& in, LLSD& out) -{ - out = in.getValue(); - return TYPE_COL4U; -} - -template <> eControlType get_control_type(const LLSD& in, LLSD& out) -{ - out = in; - return TYPE_LLSD; -} - - #if TEST_CACHED_CONTROL #define DECL_LLCC(T, V) static LLCachedControl mySetting_##T("TestCachedControl"#T, V) diff --git a/indra/newview/llviewercontrol.h b/indra/newview/llviewercontrol.h index c4003111d3..b1f14eca7b 100644 --- a/indra/newview/llviewercontrol.h +++ b/indra/newview/llviewercontrol.h @@ -47,17 +47,13 @@ extern BOOL gHackGodmode; //setting variables are declared in this function void settings_setup_listeners(); -extern std::map gSettings; - // for the graphics settings void create_graphics_group(LLControlGroup& group); // saved at end of session extern LLControlGroup gSavedSettings; extern LLControlGroup gSavedPerAccountSettings; - -// Read-only -extern LLControlGroup gColors; +extern LLControlGroup gWarningSettings; // Saved at end of session extern LLControlGroup gCrashSettings; @@ -66,110 +62,5 @@ extern LLControlGroup gCrashSettings; extern std::string gLastRunVersion; extern std::string gCurrentVersion; -//! Helper function for LLCachedControl -template -eControlType get_control_type(const T& in, LLSD& out) -{ - llerrs << "Usupported control type: " << typeid(T).name() << "." << llendl; - return TYPE_COUNT; -} - -//! Publish/Subscribe object to interact with LLControlGroups. - -//! An LLCachedControl instance to connect to a LLControlVariable -//! without have to manually create and bind a listener to a local -//! object. -template -class LLCachedControl -{ - T mCachedValue; - LLPointer mControl; - boost::signals2::scoped_connection mConnection; - -public: - LLCachedControl(const std::string& name, - const T& default_value, - const std::string& comment = "Declared In Code") - { - mControl = gSavedSettings.getControl(name); - if(mControl.isNull()) - { - declareTypedControl(gSavedSettings, name, default_value, comment); - mControl = gSavedSettings.getControl(name); - if(mControl.isNull()) - { - llerrs << "The control could not be created!!!" << llendl; - } - - mCachedValue = default_value; - } - else - { - mCachedValue = (const T&)mControl->getValue(); - } - - // Add a listener to the controls signal... - mConnection = mControl->getSignal()->connect( - boost::bind(&LLCachedControl::handleValueChange, this, _1) - ); - } - - ~LLCachedControl() - { - } - - LLCachedControl& operator =(const T& newvalue) - { - setTypeValue(*mControl, newvalue); - } - - operator const T&() { return mCachedValue; } - -private: - void declareTypedControl(LLControlGroup& group, - const std::string& name, - const T& default_value, - const std::string& comment) - { - LLSD init_value; - eControlType type = get_control_type(default_value, init_value); - if(type < TYPE_COUNT) - { - group.declareControl(name, type, init_value, comment, FALSE); - } - } - - bool handleValueChange(const LLSD& newvalue) - { - mCachedValue = (const T &)newvalue; - return true; - } - - void setTypeValue(LLControlVariable& c, const T& v) - { - // Implicit conversion from T to LLSD... - c.set(v); - } -}; - -template <> eControlType get_control_type(const U32& in, LLSD& out); -template <> eControlType get_control_type(const S32& in, LLSD& out); -template <> eControlType get_control_type(const F32& in, LLSD& out); -template <> eControlType get_control_type (const bool& in, LLSD& out); -// Yay BOOL, its really an S32. -//template <> eControlType get_control_type (const BOOL& in, LLSD& out) -template <> eControlType get_control_type(const std::string& in, LLSD& out); -template <> eControlType get_control_type(const LLVector3& in, LLSD& out); -template <> eControlType get_control_type(const LLVector3d& in, LLSD& out); -template <> eControlType get_control_type(const LLRect& in, LLSD& out); -template <> eControlType get_control_type(const LLColor4& in, LLSD& out); -template <> eControlType get_control_type(const LLColor3& in, LLSD& out); -template <> eControlType get_control_type(const LLColor4U& in, LLSD& out); -template <> eControlType get_control_type(const LLSD& in, LLSD& out); - -//#define TEST_CACHED_CONTROL 1 -#ifdef TEST_CACHED_CONTROL -void test_cached_control(); -#endif // TEST_CACHED_CONTROL #endif // LL_LLVIEWERCONTROL_H diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 977582ba24..8e65c7e65e 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -46,10 +46,9 @@ #include "lldrawpoolalpha.h" #include "llfeaturemanager.h" #include "llfirstuse.h" -#include "llframestats.h" #include "llhudmanager.h" #include "llimagebmp.h" -#include "llimagegl.h" +#include "llmemory.h" #include "llselectmgr.h" #include "llsky.h" #include "llstartup.h" @@ -58,12 +57,13 @@ #include "lltooldraganddrop.h" #include "lltoolpie.h" #include "lltracker.h" +#include "lltrans.h" #include "llui.h" #include "llviewercamera.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvograss.h" #include "llworld.h" #include "pipeline.h" @@ -73,7 +73,7 @@ #include "llviewershadermgr.h" #include "llfasttimer.h" #include "llfloatertools.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llfocusmgr.h" #include "llcubemap.h" #include "llviewerregion.h" @@ -83,9 +83,9 @@ #include "llwaterparammanager.h" #include "llpostprocess.h" -extern LLPointer gStartImageGL; +extern LLPointer gStartTexture; -LLPointer gDisconnectedImagep = NULL; +LLPointer gDisconnectedImagep = NULL; // used to toggle renderer back on after teleport const F32 TELEPORT_RENDER_DELAY = 20.f; // Max time a teleport is allowed to take before we raise the curtain @@ -135,7 +135,7 @@ void display_startup() if (frame_count++ > 1) // make sure we have rendered a frame first { - LLDynamicTexture::updateAllInstances(); + LLViewerDynamicTexture::updateAllInstances(); } LLGLState::checkStates(); @@ -163,6 +163,7 @@ void display_startup() void display_update_camera() { + LLMemType mt_uc(LLMemType::MTYPE_DISPLAY_UPDATE_CAMERA); llpushcallstacks ; // TODO: cut draw distance down if customizing avatar? // TODO: cut draw distance on per-parcel basis? @@ -199,17 +200,24 @@ void display_stats() F32 mem_log_freq = gSavedSettings.getF32("MemoryLogFrequency"); if (mem_log_freq > 0.f && gRecentMemoryTime.getElapsedTimeF32() >= mem_log_freq) { - gMemoryAllocated = getCurrentRSS(); + gMemoryAllocated = LLMemory::getCurrentRSS(); U32 memory = (U32)(gMemoryAllocated / (1024*1024)); llinfos << llformat("MEMORY: %d MB", memory) << llendl; gRecentMemoryTime.reset(); } } +static LLFastTimer::DeclareTimer FTM_PICK("Picking"); +static LLFastTimer::DeclareTimer FTM_RENDER("Render", true); +static LLFastTimer::DeclareTimer FTM_UPDATE_SKY("Update Sky"); +static LLFastTimer::DeclareTimer FTM_UPDATE_TEXTURES("Update Textures"); +static LLFastTimer::DeclareTimer FTM_IMAGE_UPDATE("Update Images"); + // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { - LLFastTimer t(LLFastTimer::FTM_RENDER); + LLMemType mt_render(LLMemType::MTYPE_RENDER); + LLFastTimer t(FTM_RENDER); if (LLPipeline::sRenderFrameTest) { @@ -226,8 +234,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLGLState::checkStates(); LLGLState::checkTextureChannels(); + stop_glerror(); + gPipeline.disableLights(); + stop_glerror(); + // Don't draw if the window is hidden or minimized. // In fact, must explicitly check the minimized state before drawing. // Attempting to draw into a minimized window causes a GL error. JC @@ -238,18 +250,21 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // Clean up memory the pools may have allocated if (rebuild) { - gFrameStats.start(LLFrameStats::REBUILD); + stop_glerror(); gPipeline.rebuildPools(); + stop_glerror(); } + stop_glerror(); gViewerWindow->returnEmptyPicks(); + stop_glerror(); return; } gViewerWindow->checkSettings(); { - LLFastTimer ftm(LLFastTimer::FTM_PICK); + LLFastTimer ftm(FTM_PICK); LLAppViewer::instance()->pingMainloopTimeout("Display:Pick"); gViewerWindow->performPick(); } @@ -299,13 +314,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // LLAppViewer::instance()->pingMainloopTimeout("Display:TextureStats"); - gFrameStats.start(LLFrameStats::UPDATE_TEX_STATS); stop_glerror(); LLImageGL::updateStats(gFrameTimeSeconds); - LLVOAvatar::sRenderName = gSavedSettings.getS32("RenderName"); - LLVOAvatar::sRenderGroupTitles = !gSavedSettings.getBOOL("RenderHideGroupTitleAll"); + LLVOAvatar::sRenderName = gSavedSettings.getS32("AvatarNameTagMode"); + LLVOAvatar::sRenderGroupTitles = (gSavedSettings.getBOOL("RenderShowGroupTitleAll") && gSavedSettings.getS32("AvatarNameTagMode")); gPipeline.mBackfaceCull = TRUE; gFrameCount++; @@ -369,12 +383,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) case LLAgent::TELEPORT_START_ARRIVAL: // Transition to ARRIVING. Viewer has received avatar update, etc., from destination simulator gTeleportArrivalTimer.reset(); - gViewerWindow->setProgressCancelButtonVisible(FALSE, std::string("Cancel")); //TODO: Translate + gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); gViewerWindow->setProgressPercent(75.f); gAgent.setTeleportState( LLAgent::TELEPORT_ARRIVING ); gAgent.setTeleportMessage( LLAgent::sTeleportProgressMessages["arriving"]); - gImageList.mForceResetTextureStats = TRUE; + gTextureList.mForceResetTextureStats = TRUE; gAgent.resetView(TRUE, TRUE); break; @@ -388,7 +402,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLFirstUse::useTeleport(); gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); } - gViewerWindow->setProgressCancelButtonVisible(FALSE, std::string("Cancel")); //TODO: Translate + gViewerWindow->setProgressCancelButtonVisible(FALSE, LLTrans::getString("Cancel")); gViewerWindow->setProgressPercent( arrival_fraction * 25.f + 75.f); gViewerWindow->setProgressString(message); } @@ -496,19 +510,20 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES)) { LLAppViewer::instance()->pingMainloopTimeout("Display:DynamicTextures"); - LLFastTimer t(LLFastTimer::FTM_UPDATE_TEXTURES); - if (LLDynamicTexture::updateAllInstances()) + LLFastTimer t(FTM_UPDATE_TEXTURES); + if (LLViewerDynamicTexture::updateAllInstances()) { gGL.setColorMask(true, true); glClear(GL_DEPTH_BUFFER_BIT); } } - gViewerWindow->setupViewport(); + gViewerWindow->setup3DViewport(); gPipeline.resetFrameStats(); // Reset per-frame statistics. if (!gDisconnected) { + LLMemType mt_du(LLMemType::MTYPE_DISPLAY_UPDATE); LLAppViewer::instance()->pingMainloopTimeout("Display:Update"); if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD)) { //don't draw hud objects in this frame @@ -528,17 +543,21 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) stop_glerror(); // *TODO: merge these two methods - LLHUDManager::getInstance()->updateEffects(); - LLHUDObject::updateAll(); - stop_glerror(); - - gFrameStats.start(LLFrameStats::UPDATE_GEOM); - const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time - gPipeline.createObjects(max_geom_update_time); - gPipeline.updateGeom(max_geom_update_time); - stop_glerror(); - - gFrameStats.start(LLFrameStats::UPDATE_CULL); + { + LLMemType mt_uh(LLMemType::MTYPE_DISPLAY_UPDATE_HUD); + LLHUDManager::getInstance()->updateEffects(); + LLHUDObject::updateAll(); + stop_glerror(); + } + + { + LLMemType mt_ug(LLMemType::MTYPE_DISPLAY_UPDATE_GEOM); + const F32 max_geom_update_time = 0.005f*10.f*gFrameIntervalSeconds; // 50 ms/second update time + gPipeline.createObjects(max_geom_update_time); + gPipeline.updateGeom(max_geom_update_time); + stop_glerror(); + } + S32 water_clip = 0; if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_ENVIRONMENT) > 1) && gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_WATER)) @@ -552,7 +571,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) water_clip = 1; } } - + LLAppViewer::instance()->pingMainloopTimeout("Display:Cull"); //Increment drawable frame counter @@ -601,8 +620,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:Swap"); { + LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SWAP); { - LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY); + LLFastTimer ftm(FTM_CLIENT_COPY); LLVertexBuffer::clientCopy(0.016); } @@ -643,7 +663,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) glLoadMatrixf(proj.m); glMatrixMode(GL_MODELVIEW); glLoadMatrixf(mod.m); - gViewerWindow->setupViewport(); + gViewerWindow->setup3DViewport(); LLGLState::checkStates(); LLGLState::checkTextureChannels(); @@ -655,6 +675,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!for_snapshot) { + LLMemType mt_gw(LLMemType::MTYPE_DISPLAY_GEN_REFLECTION); LLAppViewer::instance()->pingMainloopTimeout("Display:Imagery"); gPipeline.generateWaterReflection(*LLViewerCamera::getInstance()); } @@ -669,18 +690,18 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:UpdateImages"); LLError::LLCallStacks::clear() ; llpushcallstacks ; - gFrameStats.start(LLFrameStats::IMAGE_UPDATE); { - LLFastTimer t(LLFastTimer::FTM_IMAGE_UPDATE); + LLMemType mt_iu(LLMemType::MTYPE_DISPLAY_IMAGE_UPDATE); + LLFastTimer t(FTM_IMAGE_UPDATE); - LLViewerImage::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), + LLViewerTexture::updateClass(LLViewerCamera::getInstance()->getVelocityStat()->getMean(), LLViewerCamera::getInstance()->getAngularVelocityStat()->getMean()); - gBumpImageList.updateImages(); // must be called before gImageList version so that it's textures are thrown out first. + gBumpImageList.updateImages(); // must be called before gTextureList version so that it's textures are thrown out first. const F32 max_image_decode_time = llmin(0.005f, 0.005f*10.f*gFrameIntervalSeconds); // 50 ms/second decode time (no more than 5ms/frame) - gImageList.updateImages(max_image_decode_time); + gTextureList.updateImages(max_image_decode_time); stop_glerror(); } llpushcallstacks ; @@ -694,7 +715,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // LLAppViewer::instance()->pingMainloopTimeout("Display:StateSort"); { - gFrameStats.start(LLFrameStats::STATE_SORT); + LLMemType mt_ss(LLMemType::MTYPE_DISPLAY_STATE_SORT); gPipeline.stateSort(*LLViewerCamera::getInstance(), result); stop_glerror(); @@ -705,7 +726,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // rebuildPools // // - gFrameStats.start(LLFrameStats::REBUILD); gPipeline.rebuildPools(); stop_glerror(); } @@ -714,8 +734,9 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLPipeline::sUseOcclusion = occlusion; { + LLMemType mt_ds(LLMemType::MTYPE_DISPLAY_SKY); LLAppViewer::instance()->pingMainloopTimeout("Display:Sky"); - LLFastTimer t(LLFastTimer::FTM_UPDATE_SKY); + LLFastTimer t(FTM_UPDATE_SKY); gSky.updateSky(); } @@ -741,7 +762,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) // glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); // glLoadIdentity(); - // LLRect floater_rect = frontmost_floaterp->getScreenRect(); + // LLRect floater_rect = frontmost_floaterp->calcScreenRect(); // // deflate by one pixel so rounding errors don't occlude outside of floater extents // floater_rect.stretch(-1); // LLRectf floater_3d_rect((F32)floater_rect.mLeft / (F32)gViewerWindow->getWindowWidth(), @@ -792,7 +813,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (!(LLAppViewer::instance()->logoutRequestSent() && LLAppViewer::instance()->hasSavedFinalSnapshot()) && !gRestoreGL) { - + LLMemType mt_rg(LLMemType::MTYPE_DISPLAY_RENDER_GEOM); gGL.setColorMask(true, false); if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { @@ -818,6 +839,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) if (to_texture) { + LLMemType mt_rf(LLMemType::MTYPE_DISPLAY_RENDER_FLUSH); if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender) { gPipeline.mDeferredScreen.flush(); @@ -844,16 +866,15 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) LLAppViewer::instance()->pingMainloopTimeout("Display:RenderUI"); if (!for_snapshot) { - gFrameStats.start(LLFrameStats::RENDER_UI); + LLFastTimer t(FTM_RENDER_UI); render_ui(); } LLSpatialGroup::sNoDelete = FALSE; } - + LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats"); - gFrameStats.start(LLFrameStats::MISC_END); stop_glerror(); if (LLPipeline::sRenderFrameTest) @@ -869,6 +890,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) void render_hud_attachments() { + LLMemType mt_ra(LLMemType::MTYPE_DISPLAY_RENDER_ATTACHMENTS); glMatrixMode(GL_PROJECTION); glPushMatrix(); glMatrixMode(GL_MODELVIEW); @@ -1024,9 +1046,11 @@ BOOL setup_hud_matrices(const LLRect& screen_region) } } +static LLFastTimer::DeclareTimer FTM_SWAP("Swap"); void render_ui(F32 zoom_factor, int subfield) { + LLMemType mt_ru(LLMemType::MTYPE_DISPLAY_RENDER_UI); LLGLState::checkStates(); glPushMatrix(); @@ -1058,7 +1082,7 @@ void render_ui(F32 zoom_factor, int subfield) gGL.color4f(1,1,1,1); if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI)) { - LLFastTimer t(LLFastTimer::FTM_RENDER_UI); + LLFastTimer t(FTM_RENDER_UI); if (!gDisconnected) { @@ -1085,7 +1109,7 @@ void render_ui(F32 zoom_factor, int subfield) if (gDisplaySwapBuffers) { - LLFastTimer t(LLFastTimer::FTM_SWAP); + LLFastTimer t(FTM_SWAP); gViewerWindow->mWindow->swapBuffers(); } gDisplaySwapBuffers = TRUE; @@ -1261,8 +1285,7 @@ void render_disconnected_background() //llinfos << "Bitmap load failed" << llendl; return; } - - gDisconnectedImagep = new LLImageGL( FALSE ); + LLPointer raw = new LLImageRaw; if (!image_bmp->decode(raw, 0.0f)) { @@ -1288,8 +1311,8 @@ void render_disconnected_background() raw->expandToPowerOfTwo(); - gDisconnectedImagep->createGLTexture(0, raw); - gStartImageGL = gDisconnectedImagep; + gDisconnectedImagep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE ); + gStartTexture = gDisconnectedImagep; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); } diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp new file mode 100644 index 0000000000..b85dc30e72 --- /dev/null +++ b/indra/newview/llviewerfloaterreg.cpp @@ -0,0 +1,250 @@ +/** + * @file llviewerfloaterreg.cpp + * @brief LLViewerFloaterReg class registers floaters used in the viewer + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#include "llviewerprecompiledheaders.h" + +#include "llfloaterreg.h" + +#include "llviewerfloaterreg.h" + +#include "llcompilequeue.h" +#include "llfloaterabout.h" +#include "llfloateractivespeakers.h" +#include "llfloateranimpreview.h" +#include "llfloaterauction.h" +#include "llfloateravatarpicker.h" +#include "llfloateravatartextures.h" +#include "llfloaterbeacons.h" +#include "llfloaterbuildoptions.h" +#include "llfloaterbuy.h" +#include "llfloaterbuycontents.h" +#include "llfloaterbuycurrency.h" +#include "llfloaterbuyland.h" +#include "llfloaterbulkpermission.h" +#include "llfloaterbump.h" +#include "llfloatercall.h" +#include "llfloatercamera.h" +#include "llfloaterchat.h" +#include "llfloaterchatterbox.h" +#include "llfloaterdaycycle.h" +#include "llfloaterdirectory.h" +#include "llfloaterfirsttimetip.h" +#include "llfloaterenvsettings.h" +#include "llfloaterfonttest.h" +#include "llfloatergesture.h" +#include "llfloatergodtools.h" +#include "llfloatergroups.h" +#include "llfloaterhardwaresettings.h" +#include "llfloaterhtmlcurrency.h" +#include "llfloatermediabrowser.h" +#include "llfloaterhud.h" +#include "llfloaterimagepreview.h" +#include "llimpanel.h" +#include "llfloaterinspect.h" +#include "llfloaterinventory.h" +#include "llfloaterjoystick.h" +#include "llfloaterlagmeter.h" +#include "llfloaterland.h" +#include "llfloaterlandholdings.h" +#include "llfloatermap.h" +#include "llfloatermemleak.h" +#include "llfloatermute.h" +#include "llfloaternamedesc.h" +#include "llfloaternotificationsconsole.h" +#include "llfloateropenobject.h" +#include "llgivemoney.h" +#include "llfloaterparcel.h" +#include "llfloaterperms.h" +#include "llfloaterpostcard.h" +#include "llfloaterpostprocess.h" +#include "llfloaterpreference.h" +#include "llfloaterproperties.h" +#include "llfloaterregioninfo.h" +#include "llfloaterreporter.h" +#include "llfloaterscriptdebug.h" +#include "llfloatersellland.h" +#include "llfloatersettingsdebug.h" +#include "llfloatersnapshot.h" +#include "llfloatertelehub.h" +#include "llfloatertestlistview.h" +#include "llfloatertools.h" +#include "llfloatertos.h" +#include "llfloatertopobjects.h" +#include "llfloateruipreview.h" +#include "llfloaterurldisplay.h" +#include "llfloatervoicedevicesettings.h" +#include "llfloaterwater.h" +#include "llfloaterwindlight.h" +#include "llfloaterworldmap.h" +#include "llinspectavatar.h" +#include "llmediaremotectrl.h" +#include "llmoveview.h" +#include "llnearbychat.h" +#include "llpreviewanim.h" +#include "llpreviewgesture.h" +#include "llpreviewnotecard.h" +#include "llpreviewscript.h" +#include "llpreviewsound.h" +#include "llpreviewtexture.h" +#include "llsyswellwindow.h" +// *NOTE: Please add files in alphabetical order to keep merges easy. + + +void LLViewerFloaterReg::registerFloaters() +{ + // *NOTE: Please keep these alphabetized for easier merges + + LLFloaterReg::add("about_land", "floater_about_land.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("active_speakers", "floater_active_speakers.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("auction", "floater_auction.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar_picker", "floater_avatar_picker.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("avatar_textures", "floater_avatar_textures.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("beacons", "floater_beacons.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("bulk_perms", "floater_bulk_perms.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("buy_currency", "floater_buy_currency.xml", &LLFloaterBuyCurrency::buildFloater); + LLFloaterReg::add("buy_land", "floater_buy_land.xml", &LLFloaterBuyLand::buildFloater); + LLFloaterReg::add("buy_object", "floater_buy_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("buy_object_contents", "floater_buy_contents.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("build", "floater_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("build_options", "floater_build_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("bumps", "floater_bumps.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("camera", "floater_camera.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("chat", "floater_chat_history.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("nearby_chat", "floater_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("communicate", "floater_chatterbox.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("compile_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("contacts", "floater_my_friends.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("first_time_tip", "floater_first_time_tip.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_day_cycle", "floater_day_cycle_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_post_process", "floater_post_process.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_settings", "floater_env_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_water", "floater_water.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("env_windlight", "floater_windlight_options.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("font_test", "floater_font_test.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("gestures", "floater_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("god_tools", "floater_god_tools.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("group_picker", "floater_choose_group.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("html_simple", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inventory", "floater_inventory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inspect", "floater_inspect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("inspect_avatar", "inspect_avatar.xml", + &LLFloaterReg::build); + + LLFloaterReg::add("lagmeter", "floater_lagmeter.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("land_holdings", "floater_land_holdings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("mem_leaking", "floater_mem_leaking.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("media_browser", "floater_media_browser.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("message_critical", "floater_critical.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("message_tos", "floater_tos.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("moveview", "floater_moveview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("mute", "floater_mute.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("mute_object", "floater_mute_object.xml", &LLFloaterMute::buildFloaterMuteObjectUI); + LLFloaterReg::add("mini_map", "floater_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("syswell_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("notifications_console", "floater_notifications_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("nearby_chat", "floater_nearby_chat.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("openobject", "floater_openobject.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("parcel_info", "floater_preview_url.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pay_resident", "floater_pay.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pay_object", "floater_pay_object.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("postcard", "floater_postcard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("prefs_hardware_settings", "floater_hardware_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("perm_prefs", "floater_perm_prefs.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preview_url", "floater_preview_url.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pref_joystick", "floater_joystick.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("pref_voicedevicesettings", "floater_device_settings.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("preview_anim", "floater_preview_animation.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_gesture", "floater_preview_gesture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_notecard", "floater_preview_notecard.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_script", "floater_script_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_scriptedit", "floater_live_lsleditor.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_sound", "floater_preview_sound.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("preview_texture", "floater_preview_texture.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "preview"); + LLFloaterReg::add("properties", "floater_inventory_item_properties.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("telehubs", "floater_telehub.xml",&LLFloaterReg::build); + LLFloaterReg::add("test_list_view", "floater_test_list_view.xml",&LLFloaterReg::build); + LLFloaterReg::add("test_widgets", "floater_test_widgets.xml", &LLFloaterReg::build); + LLFloaterReg::add("top_objects", "floater_top_objects.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("reporter", "floater_report_abuse.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("reset_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("region_info", "floater_region_info.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("script_debug", "floater_script_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("script_debug_output", "floater_script_debug_panel.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("sell_land", "floater_sell_land.xml", &LLFloaterSellLand::buildFloater); + LLFloaterReg::add("settings_debug", "floater_settings_debug.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("stats", "floater_stats.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("start_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("stop_queue", "floater_script_queue.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("sl_about", "floater_about.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("snapshot", "floater_snapshot.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + LLFloaterReg::add("search", "floater_directory.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("ui_preview", "floater_ui_preview.xml", &LLFloaterReg::build); + LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build, "upload"); + + LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + LLFloaterReg::add("world_map", "floater_world_map.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + // *NOTE: Please keep these alphabetized for easier merges + + // debug use only + LLFloaterReg::add("media_remote_ctrl", "floater_media_remote.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); + + // Untested / dangerous - not for release +#if !LL_RELEASE_FOR_DOWNLOAD + LLFloaterReg::add("buy_currency_html", "floater_html_simple.xml", (LLFloaterBuildFunc)&LLFloaterReg::build); +#endif + + LLFloaterReg::registerControlVariables(); // Make sure visibility and rect controls get preserved when saving +} diff --git a/indra/newview/llfloaterevent.h b/indra/newview/llviewerfloaterreg.h similarity index 65% rename from indra/newview/llfloaterevent.h rename to indra/newview/llviewerfloaterreg.h index 8f448b5fa2..08c9589ebb 100644 --- a/indra/newview/llfloaterevent.h +++ b/indra/newview/llviewerfloaterreg.h @@ -1,8 +1,6 @@ /** - * @file llfloaterevent.h - * @brief Event information as shown in a floating window from - * secondlife:// command handler. - * Just a wrapper for LLPanelEvent. + * @file llviewerfloaterreg.h + * @brief The LLViewerFloaterReg class declaration * * $LicenseInfo:firstyear=2007&license=viewergpl$ * @@ -32,29 +30,14 @@ * $/LicenseInfo$ */ -#ifndef LL_LLFLOATEREVENT_H -#define LL_LLFLOATEREVENT_H +#ifndef LL_LLVIEWERFLOATERREG_H +#define LL_LLVIEWERFLOATERREG_H -#include "llfloater.h" - -class LLPanelEvent; - -class LLFloaterEventInfo : public LLFloater +class LLViewerFloaterReg { public: - LLFloaterEventInfo(const std::string& name, const U32 event_id ); - /*virtual*/ ~LLFloaterEventInfo(); - - void displayEventInfo(const U32 event_id); - - static LLFloaterEventInfo* show(const U32 event_id); - - static void* createEventDetail(void* userdata); - -private: - U32 mEventID; // for which event is this window? - LLPanelEvent* mPanelEventp; - + static void registerFloaters(); }; -#endif // LL_LLFLOATEREVENT_H + +#endif // LL_LLVIEWERFLOATERREG_H diff --git a/indra/newview/llviewergesture.cpp b/indra/newview/llviewergesture.cpp index 168f9af1d1..93b126b67d 100644 --- a/indra/newview/llviewergesture.cpp +++ b/indra/newview/llviewergesture.cpp @@ -34,12 +34,11 @@ #include "llviewergesture.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "lldir.h" #include "llviewerinventory.h" #include "sound_ids.h" // for testing -#include "llchatbar.h" #include "llkeyboard.h" // for key shortcuts for testing #include "llinventorymodel.h" #include "llvoavatar.h" @@ -47,6 +46,7 @@ #include "llviewermessage.h" // send_guid_sound_trigger #include "llviewernetwork.h" #include "llagent.h" +#include "llnearbychatbar.h" // Globals LLViewerGestureList gGestureList; @@ -132,11 +132,11 @@ void LLViewerGesture::doTrigger( BOOL send_chat ) } } - if ( send_chat && !mOutputString.empty()) + if (send_chat && !mOutputString.empty()) { // Don't play nodding animation, since that might not blend // with the gesture animation. - gChatBar->sendChatFromViewer(mOutputString, CHAT_TYPE_NORMAL, FALSE); + LLNearbyChatBar::getInstance()->sendChatFromViewer(mOutputString, CHAT_TYPE_NORMAL, FALSE); } } diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index bad2e174c9..95ab40f9bf 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -37,6 +37,7 @@ #include "indra_constants.h" #include "llagent.h" +#include "llfoldertype.h" #include "llviewercontrol.h" #include "llconsole.h" #include "llinventorymodel.h" @@ -44,12 +45,14 @@ #include "llimview.h" #include "llgesturemgr.h" -#include "llinventoryview.h" +#include "llinventorybridge.h" +#include "llfloaterinventory.h" #include "llviewerregion.h" #include "llviewerobjectlist.h" #include "llpreviewgesture.h" #include "llviewerwindow.h" +#include "lltrans.h" ///---------------------------------------------------------------------------- /// Local function declarations, constants, enums, and typedefs @@ -199,10 +202,19 @@ void LLViewerInventoryItem::fetchFromServer(void) const { std::string url; - if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) - url = gAgent.getRegion()->getCapability("FetchLib"); - else - url = gAgent.getRegion()->getCapability("FetchInventory"); + LLViewerRegion* region = gAgent.getRegion(); + // we have to check region. It can be null after region was destroyed. See EXT-245 + if (region) + { + if( ALEXANDRIA_LINDEN_ID.getString() == mPermissions.getOwner().getString()) + url = region->getCapability("FetchLib"); + else + url = region->getCapability("FetchInventory"); + } + else + { + llwarns << "Agent Region is absent" << llendl; + } if (!url.empty()) { @@ -242,8 +254,7 @@ BOOL LLViewerInventoryItem::unpackMessage(LLSD item) } // virtual -BOOL LLViewerInventoryItem::unpackMessage( - LLMessageSystem* msg, const char* block, S32 block_num) +BOOL LLViewerInventoryItem::unpackMessage(LLMessageSystem* msg, const char* block, S32 block_num) { BOOL rv = LLInventoryItem::unpackMessage(msg, block, block_num); mIsComplete = TRUE; @@ -402,7 +413,8 @@ void LLViewerInventoryCategory::updateParentOnServer(BOOL restamp) const void LLViewerInventoryCategory::updateServer(BOOL is_new) const { // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + + if (LLAssetType::lookupIsProtectedCategoryType(mPreferredType)) { LLNotifications::instance().add("CannotModifyProtectedCategories"); return; @@ -426,7 +438,7 @@ void LLViewerInventoryCategory::removeFromServer( void ) llinfos << "Removing inventory category " << mUUID << " from server." << llendl; // communicate that change with the server. - if(LLAssetType::AT_NONE != mPreferredType) + if(LLAssetType::lookupIsProtectedCategoryType(mPreferredType)) { LLNotifications::instance().add("CannotRemoveProtectedCategories"); return; @@ -576,6 +588,76 @@ bool LLViewerInventoryCategory::exportFileLocal(LLFILE* fp) const return true; } +void LLViewerInventoryCategory::determineFolderType() +{ + LLAssetType::EType original_type = getPreferredType(); + if (LLAssetType::lookupIsProtectedCategoryType(original_type)) + return; + + U64 folder_valid = 0; + U64 folder_invalid = 0; + LLInventoryModel::cat_array_t category_array; + LLInventoryModel::item_array_t item_array; + gInventory.collectDescendents(getUUID(),category_array,item_array,FALSE); + + // For ensembles + if (category_array.empty()) + { + for (LLInventoryModel::item_array_t::iterator item_iter = item_array.begin(); + item_iter != item_array.end(); + item_iter++) + { + const LLViewerInventoryItem *item = (*item_iter); + if (item->getIsLinkType()) + return; + if (item->getInventoryType() == LLInventoryType::IT_WEARABLE) + { + const EWearableType wearable_type = EWearableType(item->getFlags() & LLInventoryItem::II_FLAGS_WEARABLES_MASK); + const std::string& wearable_name = LLWearableDictionary::getTypeName(wearable_type); + U64 valid_folder_types = LLFolderType::lookupValidFolderTypes(wearable_name); + folder_valid |= valid_folder_types; + folder_invalid |= ~valid_folder_types; + } + } + for (U8 i = LLAssetType::AT_FOLDER_ENSEMBLE_START; i <= LLAssetType::AT_FOLDER_ENSEMBLE_END; i++) + { + if ((folder_valid & (1LL << i)) && + !(folder_invalid & (1LL << i))) + { + changeType((LLAssetType::EType)i); + return; + } + } + } + if (LLAssetType::lookupIsEnsembleCategoryType(original_type)) + { + changeType(LLAssetType::AT_NONE); + } +} + +void LLViewerInventoryCategory::changeType(LLAssetType::EType new_folder_type) +{ + const LLUUID &folder_id = getUUID(); + const LLUUID &parent_id = getParentUUID(); + const std::string &name = getName(); + + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_UpdateInventoryFolder); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->nextBlockFast(_PREHASH_FolderData); + msg->addUUIDFast(_PREHASH_FolderID, folder_id); + msg->addUUIDFast(_PREHASH_ParentID, parent_id); + msg->addS8Fast(_PREHASH_Type, new_folder_type); + msg->addStringFast(_PREHASH_Name, name); + gAgent.sendReliableMessage(); + + setPreferredType(new_folder_type); + gInventory.addChangedMask(LLInventoryObserver::LABEL, folder_id); + gInventory.updateLinkedObjects(folder_id); +} + ///---------------------------------------------------------------------------- /// Local function definitions ///---------------------------------------------------------------------------- @@ -663,13 +745,12 @@ void RezAttachmentCallback::fire(const LLUUID& inv_item) } } -extern LLGestureManager gGestureManager; void ActivateGestureCallback::fire(const LLUUID& inv_item) { if (inv_item.isNull()) return; - gGestureManager.activateGesture(inv_item); + LLGestureManager::instance().activateGesture(inv_item); } void CreateGestureCallback::fire(const LLUUID& inv_item) @@ -677,19 +758,16 @@ void CreateGestureCallback::fire(const LLUUID& inv_item) if (inv_item.isNull()) return; - gGestureManager.activateGesture(inv_item); + LLGestureManager::instance().activateGesture(inv_item); LLViewerInventoryItem* item = gInventory.getItem(inv_item); if (!item) return; gInventory.updateItem(item); gInventory.notifyObservers(); - if(!LLPreview::show(inv_item,FALSE)) - { - LLPreviewGesture* preview = LLPreviewGesture::show(std::string("Gesture: ") + item->getName(), inv_item, LLUUID::null); - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - } + LLPreviewGesture* preview = LLPreviewGesture::show(inv_item, LLUUID::null); + // Force to be entirely onscreen. + gFloaterView->adjustToFitScreen(preview, FALSE); } LLInventoryCallbackManager gInventoryCallbacks; @@ -721,6 +799,16 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, gAgent.sendReliableMessage(); } +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent /*= LLUUID::null*/, LLPointer cb/*=NULL*/) +{ + std::string item_desc = avatar_id.asString(); + std::string item_name; + gCacheName->getFullName(avatar_id, item_name); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent, LLTransactionID::tnull, item_name, item_desc, LLAssetType::AT_CALLINGCARD, + LLInventoryType::IT_CALLINGCARD, NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb); +} + void copy_inventory_item( const LLUUID& agent_id, const LLUUID& current_owner, @@ -743,6 +831,32 @@ void copy_inventory_item( gAgent.sendReliableMessage(); } +void link_inventory_item( + const LLUUID& agent_id, + const LLUUID& item_id, + const LLUUID& parent_id, + const std::string& new_name, + const LLAssetType::EType asset_type, + LLPointer cb) +{ + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_LinkInventoryItem); + msg->nextBlockFast(_PREHASH_AgentData); + { + msg->addUUIDFast(_PREHASH_AgentID, agent_id); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + } + msg->nextBlockFast(_PREHASH_InventoryData); + { + msg->addU32Fast(_PREHASH_CallbackID, gInventoryCallbacks.registerCB(cb)); + msg->addUUIDFast(_PREHASH_FolderID, parent_id); + msg->addUUIDFast(_PREHASH_OldItemID, item_id); + msg->addStringFast(_PREHASH_Name, new_name); + msg->addU8Fast(_PREHASH_AssetType, asset_type); + } + gAgent.sendReliableMessage(); +} + void move_inventory_item( const LLUUID& agent_id, const LLUUID& session_id, @@ -800,3 +914,311 @@ void copy_inventory_from_notecard(const LLUUID& object_id, const LLUUID& notecar viewer_region->getCapAPI().post(request); } + +void create_new_item(const std::string& name, + const LLUUID& parent_id, + LLAssetType::EType asset_type, + LLInventoryType::EType inv_type, + U32 next_owner_perm) +{ + std::string desc; + LLAssetType::generateDescriptionFor(asset_type, desc); + next_owner_perm = (next_owner_perm) ? next_owner_perm : PERM_MOVE | PERM_TRANSFER; + + + if (inv_type == LLInventoryType::IT_GESTURE) + { + LLPointer cb = new CreateGestureCallback(); + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, + NOT_WEARABLE, next_owner_perm, cb); + } + else + { + LLPointer cb = NULL; + create_inventory_item(gAgent.getID(), gAgent.getSessionID(), + parent_id, LLTransactionID::tnull, name, desc, asset_type, inv_type, + NOT_WEARABLE, next_owner_perm, cb); + } + +} + +const std::string NEW_LSL_NAME = "New Script"; // *TODO:Translate? (probably not) +const std::string NEW_NOTECARD_NAME = "New Note"; // *TODO:Translate? (probably not) +const std::string NEW_GESTURE_NAME = "New Gesture"; // *TODO:Translate? (probably not) + +void menu_create_inventory_item(LLFolderView* folder, LLFolderBridge *bridge, const LLSD& userdata) +{ + std::string type = userdata.asString(); + + if (("category" == type) || ("current" == type) || ("outfit" == type) || ("my_otfts" == type) ) + { + LLAssetType::EType a_type = LLAssetType::AT_NONE; + if ("current" == type) + a_type = LLAssetType::AT_CURRENT_OUTFIT; + if ("outfit" == type) + a_type = LLAssetType::AT_OUTFIT; + if ("my_otfts" == type) + a_type = LLAssetType::AT_MY_OUTFITS; + LLUUID category; + if (bridge) + { + category = gInventory.createNewCategory(bridge->getUUID(), a_type, LLStringUtil::null); + } + else + { + category = gInventory.createNewCategory(gInventory.getRootFolderID(), a_type, LLStringUtil::null); + } + gInventory.notifyObservers(); + folder->setSelectionByID(category, TRUE); + } + else if ("lsl" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_LSL_TEXT); + create_new_item(NEW_LSL_NAME, + parent_id, + LLAssetType::AT_LSL_TEXT, + LLInventoryType::IT_LSL, + PERM_MOVE | PERM_TRANSFER); + } + else if ("notecard" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_NOTECARD); + create_new_item(NEW_NOTECARD_NAME, + parent_id, + LLAssetType::AT_NOTECARD, + LLInventoryType::IT_NOTECARD, + PERM_ALL); + } + else if ("gesture" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_GESTURE); + create_new_item(NEW_GESTURE_NAME, + parent_id, + LLAssetType::AT_GESTURE, + LLInventoryType::IT_GESTURE, + PERM_ALL); + } + else if ("shirt" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_SHIRT); + } + else if ("pants" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_PANTS); + } + else if ("shoes" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_SHOES); + } + else if ("socks" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_SOCKS); + } + else if ("jacket" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_JACKET); + } + else if ("skirt" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_SKIRT); + } + else if ("gloves" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_GLOVES); + } + else if ("undershirt" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_UNDERSHIRT); + } + else if ("underpants" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_CLOTHING); + LLFolderBridge::createWearable(parent_id, WT_UNDERPANTS); + } + else if ("shape" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); + LLFolderBridge::createWearable(parent_id, WT_SHAPE); + } + else if ("skin" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); + LLFolderBridge::createWearable(parent_id, WT_SKIN); + } + else if ("hair" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); + LLFolderBridge::createWearable(parent_id, WT_HAIR); + } + else if ("eyes" == type) + { + LLUUID parent_id = bridge ? bridge->getUUID() : gInventory.findCategoryUUIDForType(LLAssetType::AT_BODYPART); + LLFolderBridge::createWearable(parent_id, WT_EYES); + } + + folder->setNeedsAutoRename(TRUE); +} + +LLAssetType::EType LLViewerInventoryItem::getType() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getType(); + } + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getType(); + } + return LLInventoryItem::getType(); +} + +const LLUUID& LLViewerInventoryItem::getAssetUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getAssetUUID(); + } + + return LLInventoryItem::getAssetUUID(); +} + +const std::string& LLViewerInventoryItem::getName() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getName(); + } + if (const LLViewerInventoryCategory *linked_category = getLinkedCategory()) + { + return linked_category->getName(); + } + + return LLInventoryItem::getName(); +} + +const LLPermissions& LLViewerInventoryItem::getPermissions() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getPermissions(); + } + + // Use the actual permissions of the symlink, not its parent. + return LLInventoryItem::getPermissions(); +} + +const LLUUID& LLViewerInventoryItem::getCreatorUUID() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getCreatorUUID(); + } + + return LLInventoryItem::getCreatorUUID(); +} + +const std::string& LLViewerInventoryItem::getDescription() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getDescription(); + } + + return LLInventoryItem::getDescription(); +} + +const LLSaleInfo& LLViewerInventoryItem::getSaleInfo() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getSaleInfo(); + } + + return LLInventoryItem::getSaleInfo(); +} + +LLInventoryType::EType LLViewerInventoryItem::getInventoryType() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getInventoryType(); + } + + // Categories don't have types. If this item is an AT_FOLDER_LINK, + // treat it as a category. + if (getLinkedCategory()) + { + return LLInventoryType::IT_CATEGORY; + } + + return LLInventoryItem::getInventoryType(); +} + +U32 LLViewerInventoryItem::getFlags() const +{ + if (const LLViewerInventoryItem *linked_item = getLinkedItem()) + { + return linked_item->getFlags(); + } + return LLInventoryItem::getFlags(); +} + +time_t LLViewerInventoryItem::getCreationDate() const +{ + return LLInventoryItem::getCreationDate(); +} + +U32 LLViewerInventoryItem::getCRC32() const +{ + return LLInventoryItem::getCRC32(); +} + +// This returns true if the item that this item points to +// doesn't exist in memory (i.e. LLInventoryModel). The baseitem +// might still be in the database but just not loaded yet. +bool LLViewerInventoryItem::getIsBrokenLink() const +{ + // If the item's type resolves to be a link, that means either: + // A. It wasn't able to perform indirection, i.e. the baseobj doesn't exist in memory. + // B. It's pointing to another link, which is illegal. + return LLAssetType::lookupIsLinkType(getType()); +} + +const LLViewerInventoryItem *LLViewerInventoryItem::getLinkedItem() const +{ + if (mType == LLAssetType::AT_LINK) + { + const LLViewerInventoryItem *linked_item = gInventory.getItem(mAssetUUID); + return linked_item; + } + return NULL; +} + +const LLViewerInventoryCategory *LLViewerInventoryItem::getLinkedCategory() const +{ + if (mType == LLAssetType::AT_LINK_FOLDER) + { + const LLViewerInventoryCategory *linked_category = gInventory.getCategory(mAssetUUID); + return linked_category; + } + return NULL; +} + +//---------- + +void LLViewerInventoryItem::onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name) +{ + rename(first_name + " " + last_name); + gInventory.addChangedMask(LLInventoryObserver::LABEL, getUUID()); + gInventory.notifyObservers(); +} + diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h index 1ddf8a58f9..0bfb37f7e8 100644 --- a/indra/newview/llviewerinventory.h +++ b/indra/newview/llviewerinventory.h @@ -37,6 +37,10 @@ #include "llframetimer.h" #include "llwearable.h" +class LLFolderView; +class LLFolderBridge; +class LLViewerInventoryCategory; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLViewerInventoryItem // @@ -44,7 +48,7 @@ // their inventory. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -class LLViewerInventoryItem : public LLInventoryItem +class LLViewerInventoryItem : public LLInventoryItem, public boost::signals2::trackable { public: typedef LLDynamicArray > item_array_t; @@ -53,6 +57,18 @@ protected: ~LLViewerInventoryItem( void ); // ref counted public: + virtual LLAssetType::EType getType() const; + virtual const LLUUID& getAssetUUID() const; + virtual const std::string& getName() const; + virtual const LLPermissions& getPermissions() const; + virtual const LLUUID& getCreatorUUID() const; + virtual const std::string& getDescription() const; + virtual const LLSaleInfo& getSaleInfo() const; + virtual LLInventoryType::EType getInventoryType() const; + virtual U32 getFlags() const; + virtual time_t getCreationDate() const; + virtual U32 getCRC32() const; // really more of a checksum. + // construct a complete viewer inventory item LLViewerInventoryItem(const LLUUID& uuid, const LLUUID& parent_uuid, const LLPermissions& permissions, @@ -125,7 +141,14 @@ public: }; LLTransactionID getTransactionID() const { return mTransactionID; } -protected: + bool getIsBrokenLink() const; // true if the baseitem this points to doesn't exist in memory. + const LLViewerInventoryItem *getLinkedItem() const; + const LLViewerInventoryCategory *getLinkedCategory() const; + + // callback + void onCallingCardNameLookup(const LLUUID& id, const std::string& first_name, const std::string& last_name); + +public: BOOL mIsComplete; LLTransactionID mTransactionID; }; @@ -184,7 +207,8 @@ public: // other than cacheing. bool exportFileLocal(LLFILE* fp) const; bool importFileLocal(LLFILE* fp); - + void determineFolderType(); + void changeType(LLAssetType::EType new_folder_type); protected: LLUUID mOwnerID; S32 mVersion; @@ -253,6 +277,7 @@ extern LLInventoryCallbackManager gInventoryCallbacks; #define NOT_WEARABLE (EWearableType)0 +// *TODO: Find a home for these void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, const LLUUID& parent, const LLTransactionID& transaction_id, const std::string& name, @@ -261,6 +286,8 @@ void create_inventory_item(const LLUUID& agent_id, const LLUUID& session_id, U32 next_owner_perm, LLPointer cb); +void create_inventory_callingcard(const LLUUID& avatar_id, const LLUUID& parent = LLUUID::null, LLPointer cb=NULL); + /** * @brief Securely create a new inventory item by copying from another. */ @@ -272,6 +299,14 @@ void copy_inventory_item( const std::string& new_name, LLPointer cb); +void link_inventory_item( + const LLUUID& agent_id, + const LLUUID& item_id, + const LLUUID& parent_id, + const std::string& new_name, + const LLAssetType::EType asset_type, + LLPointer cb); + void move_inventory_item( const LLUUID& agent_id, const LLUUID& session_id, @@ -286,4 +321,8 @@ void copy_inventory_from_notecard(const LLUUID& object_id, U32 callback_id = 0); +void menu_create_inventory_item(LLFolderView* folder, + LLFolderBridge* bridge, + const LLSD& userdata); + #endif // LL_LLVIEWERINVENTORY_H diff --git a/indra/newview/llviewerjointattachment.h b/indra/newview/llviewerjointattachment.h index 4847ac7a72..c003579684 100644 --- a/indra/newview/llviewerjointattachment.h +++ b/indra/newview/llviewerjointattachment.h @@ -71,20 +71,20 @@ public: void setPieSlice(S32 pie_slice) { mPieSlice = pie_slice; } void setVisibleInFirstPerson(BOOL visibility) { mVisibleInFirst = visibility; } - BOOL getVisibleInFirstPerson() { return mVisibleInFirst; } + BOOL getVisibleInFirstPerson() const { return mVisibleInFirst; } void setGroup(S32 group) { mGroup = group; } void setOriginalPosition(LLVector3 &position); void setAttachmentVisibility(BOOL visible); void setIsHUDAttachment(BOOL is_hud) { mIsHUDAttachment = is_hud; } - BOOL getIsHUDAttachment() { return mIsHUDAttachment; } + BOOL getIsHUDAttachment() const { return mIsHUDAttachment; } - BOOL isAnimatable() { return FALSE; } + BOOL isAnimatable() const { return FALSE; } - S32 getGroup() { return mGroup; } - S32 getPieSlice() { return mPieSlice; } - LLViewerObject *getObject() { return mAttachedObject; } - S32 getNumObjects() { return (mAttachedObject ? 1 : 0); } - const LLUUID& getItemID() { return mItemID; } + S32 getGroup() const { return mGroup; } + S32 getPieSlice() const { return mPieSlice; } + LLViewerObject *getObject() const { return mAttachedObject; } + S32 getNumObjects() const { return (mAttachedObject ? 1 : 0); } + const LLUUID& getItemID() const { return mItemID; } // // unique methods diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index b6f0dafae6..28f883312a 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -39,7 +39,6 @@ #include "llfasttimer.h" #include "llrender.h" -#include "llagent.h" #include "llapr.h" #include "llbox.h" #include "lldrawable.h" @@ -52,7 +51,7 @@ #include "lltexlayer.h" #include "llviewercamera.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerjointmesh.h" #include "llvoavatar.h" #include "llsky.h" @@ -230,7 +229,7 @@ void LLViewerJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha ) //-------------------------------------------------------------------- // LLViewerJointMesh::getTexture() //-------------------------------------------------------------------- -//LLViewerImage *LLViewerJointMesh::getTexture() +//LLViewerTexture *LLViewerJointMesh::getTexture() //{ // return mTexture; //} @@ -238,7 +237,7 @@ void LLViewerJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha ) //-------------------------------------------------------------------- // LLViewerJointMesh::setTexture() //-------------------------------------------------------------------- -void LLViewerJointMesh::setTexture( LLViewerImage *texture ) +void LLViewerJointMesh::setTexture( LLViewerTexture *texture ) { mTexture = texture; @@ -557,7 +556,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { if( mLayerSet->hasComposite() ) { - gGL.getTexUnit(0)->bind(mLayerSet->getComposite()->getTexture()); + gGL.getTexUnit(0)->bind(mLayerSet->getComposite()); } else { @@ -567,19 +566,22 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) { llwarns << "Layerset without composite" << llendl; } - gGL.getTexUnit(0)->bind(gImageList.getImage(IMG_DEFAULT)); + gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT)); } } else if ( !is_dummy && mTexture.notNull() ) { - old_mode = mTexture->getAddressMode(); - gGL.getTexUnit(0)->bind(mTexture.get()); + if(mTexture->hasGLTexture()) + { + old_mode = mTexture->getAddressMode(); + } + gGL.getTexUnit(0)->bind(mTexture); gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); } else { - gGL.getTexUnit(0)->bind(gImageList.getImage(IMG_DEFAULT_AVATAR)); + gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR)); } if (gRenderForSelect) @@ -633,7 +635,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy) if (mTexture.notNull() && !is_dummy) { - gGL.getTexUnit(0)->bind(mTexture.get()); + gGL.getTexUnit(0)->bind(mTexture); gGL.getTexUnit(0)->setTextureAddressMode(old_mode); } diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h index 0cae48df93..543679c44b 100644 --- a/indra/newview/llviewerjointmesh.h +++ b/indra/newview/llviewerjointmesh.h @@ -34,7 +34,7 @@ #define LL_LLVIEWERJOINTMESH_H #include "llviewerjoint.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llpolymesh.h" #include "v4color.h" #include "llapr.h" @@ -72,7 +72,7 @@ protected: LLColor4 mColor; // color value // LLColor4 mSpecular; // specular color (always white for now) F32 mShiny; // shiny value - LLPointer mTexture; // ptr to a global texture + LLPointer mTexture; // ptr to a global texture LLTexLayerSet* mLayerSet; // ptr to a layer set owned by the avatar U32 mTestImageName; // handle to a temporary texture for previewing uploads LLPolyMesh* mMesh; // ptr to a global polymesh @@ -110,7 +110,7 @@ public: void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; }; // Sets the shape texture - void setTexture( LLViewerImage *texture ); + void setTexture( LLViewerTexture *texture ); void setTestTexture( U32 name ) { mTestImageName = name; } @@ -148,7 +148,7 @@ public: void setIsTransparent(BOOL is_transparent) { mIsTransparent = is_transparent; } - /*virtual*/ BOOL isAnimatable() { return FALSE; } + /*virtual*/ BOOL isAnimatable() const { return FALSE; } static void updateVectorize(); // Update globals when settings variables change diff --git a/indra/newview/llviewerkeyboard.cpp b/indra/newview/llviewerkeyboard.cpp index 15c814829c..fc2f00a2ea 100644 --- a/indra/newview/llviewerkeyboard.cpp +++ b/indra/newview/llviewerkeyboard.cpp @@ -36,14 +36,15 @@ #include "llviewerkeyboard.h" #include "llmath.h" #include "llagent.h" -#include "llchatbar.h" +#include "llnearbychatbar.h" #include "llviewercontrol.h" #include "llfocusmgr.h" #include "llmorphview.h" #include "llmoveview.h" #include "lltoolfocus.h" #include "llviewerwindow.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llfloatercamera.h" // // Constants @@ -135,14 +136,29 @@ static void agent_push_forwardbackward( EKeystate s, S32 direction, LLAgent::EDo } } +void camera_move_forward( EKeystate s ); + void agent_push_forward( EKeystate s ) { + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_forward(s); + return; + } agent_push_forwardbackward(s, 1, LLAgent::DOUBLETAP_FORWARD); } +void camera_move_backward( EKeystate s ); void agent_push_backward( EKeystate s ) { + //in free camera control mode we need to intercept keyboard events for avatar movements + if (LLFloaterCamera::inFreeCameraMode()) + { + camera_move_backward(s); + return; + } agent_push_forwardbackward(s, -1, LLAgent::DOUBLETAP_BACKWARD); } @@ -175,8 +191,17 @@ void agent_slide_right( EKeystate s ) 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 (LLToolCamera::getInstance()->mouseSteerMode()) { agent_slide_left(s); @@ -189,9 +214,17 @@ void agent_turn_left( EKeystate s ) } } +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 (LLToolCamera::getInstance()->mouseSteerMode()) { agent_slide_right(s); @@ -224,7 +257,7 @@ void agent_toggle_fly( EKeystate s ) // Only catch the edge if (KEYSTATE_DOWN == s ) { - gAgent.toggleFlying(); + LLAgent::toggleFlying(); } } @@ -500,24 +533,24 @@ void stop_moving( EKeystate s ) void start_chat( EKeystate s ) { // start chat - gChatBar->startChat(NULL); + LLNearbyChatBar::startChat(NULL); } void start_gesture( EKeystate s ) { if (KEYSTATE_UP == s && - !(gFocusMgr.getKeyboardFocus() && gFocusMgr.getKeyboardFocus()->acceptsTextInput())) + !(gFocusMgr.getKeyboardFocus() && dynamic_cast(gFocusMgr.getKeyboardFocus())->acceptsTextInput())) { - if (gChatBar->getCurrentChat().empty()) - { - // No existing chat in chat editor, insert '/' - gChatBar->startChat("/"); - } - else - { - // Don't overwrite existing text in chat editor - gChatBar->startChat(NULL); - } + if (LLNearbyChatBar::getInstance()->getCurrentChat().empty()) + { + // No existing chat in chat editor, insert '/' + LLNearbyChatBar::startChat("/"); + } + else + { + // Don't overwrite existing text in chat editor + LLNearbyChatBar::startChat(NULL); + } } } @@ -842,7 +875,7 @@ EKeyboardMode LLViewerKeyboard::getMode() { return MODE_EDIT_AVATAR; } - else if (gAgent.getAvatarObject() && gAgent.getAvatarObject()->mIsSitting) + else if (gAgent.getAvatarObject() && gAgent.getAvatarObject()->isSitting()) { return MODE_SITTING; } diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp index 82f8359732..a06d913fd6 100644 --- a/indra/newview/llviewermedia.cpp +++ b/indra/newview/llviewermedia.cpp @@ -33,399 +33,212 @@ #include "llviewerprecompiledheaders.h" #include "llviewermedia.h" - +#include "llviewermediafocus.h" +#include "llhoverview.h" #include "llmimetypes.h" #include "llviewercontrol.h" -#include "llviewerimage.h" +#include "llviewertexture.h" +#include "llviewerparcelmedia.h" +#include "llviewerparcelmgr.h" #include "llviewerwindow.h" #include "llversionviewer.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" +#include "llpluginclassmedia.h" #include "llevent.h" // LLSimpleListener -#include "llmediamanager.h" #include "lluuid.h" #include // for SkinFolder listener #include +// Move this to its own file. -// Implementation functions not exported into header file -class LLViewerMediaImpl - : public LLMediaObserver +LLViewerMediaEventEmitter::~LLViewerMediaEventEmitter() { - public: - LLViewerMediaImpl() - : mMediaSource( NULL ), - mMovieImageID(), - mMovieImageHasMips(false) - { } + observerListType::iterator iter = mObservers.begin(); - void destroyMediaSource(); - - void play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop); - - void stop(); - void pause(); - void start(); - void seek(F32 time); - void setVolume(F32 volume); - LLMediaBase::EStatus getStatus(); - - /*virtual*/ void onMediaSizeChange(const EventType& event_in); - /*virtual*/ void onMediaContentsChange(const EventType& event_in); - - void updateMovieImage(const LLUUID& image_id, BOOL active); - void updateImagesMediaStreams(); - LLUUID getMediaTextureID(); - - // Internally set our desired browser user agent string, including - // the Second Life version and skin name. Used because we can - // switch skins without restarting the app. - static void updateBrowserUserAgent(); - - // Callback for when the SkinCurrent control is changed to - // switch the user agent string to indicate the new skin. - static bool handleSkinCurrentChanged(const LLSD& newvalue); - - public: - - // a single media url with some data and an impl. - LLMediaBase* mMediaSource; - LLUUID mMovieImageID; - bool mMovieImageHasMips; - std::string mMediaURL; - std::string mMimeType; - private: - void initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source); -}; - -static LLViewerMediaImpl sViewerMediaImpl; - -////////////////////////////////////////////////////////////////////////////////////////// - -void LLViewerMediaImpl::destroyMediaSource() -{ - LLMediaManager* mgr = LLMediaManager::getInstance(); - if ( mMediaSource ) + while( iter != mObservers.end() ) { - bool was_playing = LLViewerMedia::isMediaPlaying(); - mMediaSource->remObserver(this); - mgr->destroySource( mMediaSource ); - - // Restore the texture - updateMovieImage(LLUUID::null, was_playing); - + LLViewerMediaObserver *self = *iter; + iter++; + remObserver(self); } - mMediaSource = NULL; } -void LLViewerMediaImpl::play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop) +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::addObserver( LLViewerMediaObserver* observer ) { - // first stop any previously playing media - stop(); + if ( ! observer ) + return false; - // Save this first, as init/load below may fire events - mMovieImageID = placeholder_texture_id; + if ( std::find( mObservers.begin(), mObservers.end(), observer ) != mObservers.end() ) + return false; - // If the mime_type passed in is different than the cached one, and - // Auto-discovery is turned OFF, replace the cached mime_type with the new one. - if(mime_type != mMimeType && - ! gSavedSettings.getBOOL("AutoMimeDiscovery")) + mObservers.push_back( observer ); + observer->mEmitters.push_back( this ); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +bool LLViewerMediaEventEmitter::remObserver( LLViewerMediaObserver* observer ) +{ + if ( ! observer ) + return false; + + mObservers.remove( observer ); + observer->mEmitters.remove(this); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////// +// +void LLViewerMediaEventEmitter::emitEvent( LLPluginClassMedia* media, LLPluginClassMediaOwner::EMediaEvent event ) +{ + observerListType::iterator iter = mObservers.begin(); + + while( iter != mObservers.end() ) { - mMimeType = mime_type; + LLViewerMediaObserver *self = *iter; + ++iter; + self->handleMediaEvent( media, event ); } - LLURI url(media_url); - std::string scheme = url.scheme() != "" ? url.scheme() : "http"; +} - LLMediaManager* mgr = LLMediaManager::getInstance(); - mMediaSource = mgr->createSourceFromMimeType(scheme, mMimeType ); - if ( !mMediaSource ) +// Move this to its own file. +LLViewerMediaObserver::~LLViewerMediaObserver() +{ + std::list::iterator iter = mEmitters.begin(); + + while( iter != mEmitters.end() ) { - if (mMimeType != "none/none") + LLViewerMediaEventEmitter *self = *iter; + iter++; + self->remObserver( this ); + } +} + + +// Move this to its own file. +// helper class that tries to download a URL from a web site and calls a method +// on the Panel Land Media and to discover the MIME type +class LLMimeDiscoveryResponder : public LLHTTPClient::Responder +{ +LOG_CLASS(LLMimeDiscoveryResponder); +public: + LLMimeDiscoveryResponder( viewer_media_t media_impl) + : mMediaImpl(media_impl), + mInitialized(false) + {} + + + + virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) + { + std::string media_type = content["content-type"].asString(); + std::string::size_type idx1 = media_type.find_first_of(";"); + std::string mime_type = media_type.substr(0, idx1); + completeAny(status, mime_type); + } + + virtual void error( U32 status, const std::string& reason ) + { + // completeAny(status, "none/none"); + } + + void completeAny(U32 status, const std::string& mime_type) + { + if(!mInitialized && ! mime_type.empty()) { - llwarns << "media source create failed " << media_url - << " type " << mMimeType - << llendl; - } - return; - } - - // Store the URL and Mime Type - mMediaURL = media_url; - - if ((media_width != 0) && (media_height != 0)) - { - mMediaSource->setRequestedMediaSize(media_width, media_height); - } - - mMediaSource->setLooping(media_loop); - mMediaSource->setAutoScaled(media_auto_scale); - mMediaSource->addObserver( this ); - mMediaSource->navigateTo( media_url ); - mMediaSource->addCommand(LLMediaBase::COMMAND_START); -} - -void LLViewerMediaImpl::stop() -{ - destroyMediaSource(); -} - -void LLViewerMediaImpl::pause() -{ - if(mMediaSource) - { - mMediaSource->addCommand(LLMediaBase::COMMAND_PAUSE); - } -} - -void LLViewerMediaImpl::start() -{ - if(mMediaSource) - { - mMediaSource->addCommand(LLMediaBase::COMMAND_START); - } -} - -void LLViewerMediaImpl::seek(F32 time) -{ - if(mMediaSource) - { - mMediaSource->seek(time); - } -} - -void LLViewerMediaImpl::setVolume(F32 volume) -{ - if(mMediaSource) - { - mMediaSource->setVolume( volume); - } -} - -LLMediaBase::EStatus LLViewerMediaImpl::getStatus() -{ - if (mMediaSource) - { - return mMediaSource->getStatus(); - } - else - { - return LLMediaBase::STATUS_UNKNOWN; - } -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) -{ - // IF the media image hasn't changed, do nothing - if (mMovieImageID == uuid) - { - return; - } - // If we have changed media uuid, restore the old one - if (!mMovieImageID.isNull()) - { - LLViewerImage* oldImage = LLViewerImage::getImage( mMovieImageID ); - if (oldImage) - { - oldImage->reinit(mMovieImageHasMips); - oldImage->mIsMediaTexture = FALSE; - } - mMovieImageID.setNull(); - } - // If the movie is playing, set the new media image - if (active && !uuid.isNull()) - { - LLViewerImage* viewerImage = LLViewerImage::getImage( uuid ); - if( viewerImage ) - { - mMovieImageID = uuid; - // Can't use mipmaps for movies because they don't update the full image - mMovieImageHasMips = viewerImage->getUseMipMaps(); - viewerImage->reinit(FALSE); - viewerImage->mIsMediaTexture = TRUE; - } - } -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMediaImpl::updateImagesMediaStreams() -{ - LLMediaManager::updateClass(); -} - -void LLViewerMediaImpl::initializePlaceholderImage(LLViewerImage *placeholder_image, LLMediaBase *media_source) -{ - int media_width = media_source->getMediaWidth(); - int media_height = media_source->getMediaHeight(); - //int media_rowspan = media_source->getMediaRowSpan(); - - // if width & height are invalid, don't bother doing anything - if ( media_width < 1 || media_height < 1 ) - return; - - llinfos << "initializing media placeholder" << llendl; - llinfos << "movie image id " << mMovieImageID << llendl; - - int texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); - int texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height ); - int texture_depth = media_source->getMediaDepth(); - - // MEDIAOPT: check to see if size actually changed before doing work - placeholder_image->destroyGLTexture(); - // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? - placeholder_image->reinit(FALSE); // probably not needed - - // MEDIAOPT: seems insane that we actually have to make an imageraw then - // immediately discard it - LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); - raw->clear(0x0f, 0x0f, 0x0f, 0xff); - int discard_level = 0; - - // ask media source for correct GL image format constants - placeholder_image->setExplicitFormat(media_source->getTextureFormatInternal(), - media_source->getTextureFormatPrimary(), - media_source->getTextureFormatType()); - - placeholder_image->createGLTexture(discard_level, raw); - - // placeholder_image->setExplicitFormat() - placeholder_image->setUseMipMaps(FALSE); - - // MEDIAOPT: set this dynamically on play/stop - placeholder_image->mIsMediaTexture = true; -} - - - -// virtual -void LLViewerMediaImpl::onMediaContentsChange(const EventType& event_in) -{ - LLMediaBase* media_source = event_in.getSubject(); - LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID ); - if ((placeholder_image) && (placeholder_image->getHasGLTexture())) - { - if (placeholder_image->getUseMipMaps()) - { - // bad image! NO MIPMAPS! - initializePlaceholderImage(placeholder_image, media_source); - } - - U8* data = media_source->getMediaData(); - S32 x_pos = 0; - S32 y_pos = 0; - S32 width = media_source->getMediaWidth(); - S32 height = media_source->getMediaHeight(); - S32 data_width = media_source->getMediaDataWidth(); - S32 data_height = media_source->getMediaDataHeight(); - placeholder_image->setSubImage(data, data_width, data_height, - x_pos, y_pos, width, height); - } -} - - -// virtual -void LLViewerMediaImpl::onMediaSizeChange(const EventType& event_in) -{ - LLMediaBase* media_source = event_in.getSubject(); - LLViewerImage* placeholder_image = gImageList.getImage( mMovieImageID ); - if (placeholder_image) - { - initializePlaceholderImage(placeholder_image, media_source); - } - else - { - llinfos << "no placeholder image" << llendl; - } -} - - - // Get the image we're using - - /* - // update media stream if required - LLMediaEngine* media_engine = LLMediaEngine::getInstance(); - if (media_engine) - { - if ( media_engine->update() ) - { - LLUUID media_uuid = media_engine->getImageUUID(); - updateMovieImage(media_uuid, TRUE); - if (!media_uuid.isNull()) + if (mMediaImpl->initializeMedia(mime_type)) { - LLViewerImage* viewerImage = getImage( media_uuid ); - if( viewerImage ) - { - LLMediaBase* renderer = media_engine->getMediaRenderer(); - if ((renderer->getTextureWidth() != viewerImage->getWidth()) || - (renderer->getTextureHeight() != viewerImage->getHeight()) || - (renderer->getTextureDepth() != viewerImage->getComponents()) || - (viewerImage->getHasGLTexture() == FALSE)) - { - // destroy existing GL image - viewerImage->destroyGLTexture(); - - // set new size - viewerImage->setSize( renderer->getTextureWidth(), - renderer->getTextureHeight(), - renderer->getTextureDepth() ); - - LLPointer raw = new LLImageRaw(renderer->getTextureWidth(), - renderer->getTextureHeight(), - renderer->getTextureDepth()); - raw->clear(0x7f,0x7f,0x7f,0xff); - viewerImage->createGLTexture(0, raw); - } - - // Set the explicit format the instance wants - viewerImage->setExplicitFormat(renderer->getTextureFormatInternal(), - renderer->getTextureFormatPrimary(), - renderer->getTextureFormatType(), - renderer->getTextureFormatSwapBytes()); - // This should be redundant, but just in case: - viewerImage->setUseMipMaps(FALSE); - - LLImageRaw* rawImage = media_engine->getImageRaw(); - if ( rawImage ) - { - viewerImage->setSubImage(rawImage, 0, 0, - renderer->getMediaWidth(), - renderer->getMediaHeight()); - } - } - else - { - llwarns << "MediaEngine update unable to get viewer image for GL texture" << llendl; - } + mInitialized = true; + mMediaImpl->play(); } } - else - { - LLUUID media_uuid = media_engine->getImageUUID(); - updateMovieImage(media_uuid, FALSE); - } } - */ + public: + viewer_media_t mMediaImpl; + bool mInitialized; +}; +typedef std::vector impl_list; +static impl_list sViewerMediaImplList; -LLUUID LLViewerMediaImpl::getMediaTextureID() +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMedia + +////////////////////////////////////////////////////////////////////////////////////////// +// static +viewer_media_t LLViewerMedia::newMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, S32 media_height, U8 media_auto_scale, + U8 media_loop, + std::string mime_type) { - return mMovieImageID; + LLViewerMediaImpl* media_impl = getMediaImplFromTextureID(texture_id); + if(media_impl == NULL || texture_id.isNull()) + { + // Create the media impl + media_impl = new LLViewerMediaImpl(media_url, texture_id, media_width, media_height, media_auto_scale, media_loop, mime_type); + sViewerMediaImplList.push_back(media_impl); + } + else + { + media_impl->stop(); + media_impl->mTextureId = texture_id; + media_impl->mMediaURL = media_url; + media_impl->mMediaWidth = media_width; + media_impl->mMediaHeight = media_height; + media_impl->mMediaAutoScale = media_auto_scale; + media_impl->mMediaLoop = media_loop; + if(! media_url.empty()) + media_impl->navigateTo(media_url, mime_type, true); + } + return media_impl; } +////////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMediaImpl::updateBrowserUserAgent() +void LLViewerMedia::removeMedia(LLViewerMediaImpl* media) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + if(media == *iter) + { + sViewerMediaImplList.erase(iter); + return; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +LLViewerMediaImpl* LLViewerMedia::getMediaImplFromTextureID(const LLUUID& texture_id) +{ + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* media_impl = *iter; + if(media_impl->getMediaTextureID() == texture_id) + { + return media_impl; + } + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +std::string LLViewerMedia::getCurrentUserAgent() { // Don't use user-visible string to avoid // punctuation and strange characters. @@ -446,11 +259,33 @@ void LLViewerMediaImpl::updateBrowserUserAgent() codec << LL_VERSION_MAJOR << "." << LL_VERSION_MINOR << "." << LL_VERSION_PATCH << "." << LL_VERSION_BUILD; codec << " (" << channel << "; " << skin_name << " skin)"; llinfos << codec.str() << llendl; - LLMediaManager::setBrowserUserAgent( codec.str() ); + + return codec.str(); } +////////////////////////////////////////////////////////////////////////////////////////// // static -bool LLViewerMediaImpl::handleSkinCurrentChanged(const LLSD& /*newvalue*/) +void LLViewerMedia::updateBrowserUserAgent() +{ + std::string user_agent = getCurrentUserAgent(); + + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->mMediaSource && pimpl->mMediaSource->pluginSupportsMediaBrowser()) + { + pimpl->mMediaSource->setBrowserUserAgent(user_agent); + } + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +// static +bool LLViewerMedia::handleSkinCurrentChanged(const LLSD& /*newvalue*/) { // gSavedSettings is already updated when this function is called. updateBrowserUserAgent(); @@ -458,249 +293,921 @@ bool LLViewerMediaImpl::handleSkinCurrentChanged(const LLSD& /*newvalue*/) } ////////////////////////////////////////////////////////////////////////////////////////// -// Wrapper class -////////////////////////////////////////////////////////////////////////////////////////// - - -////////////////////////////////////////////////////////////////////////////////////////// -// The viewer takes a long time to load the start screen. Part of the problem -// is media initialization -- in particular, QuickTime loads many DLLs and -// hits the disk heavily. So we initialize only the browser component before -// the login screen, then do the rest later when we have a progress bar. JC // static -void LLViewerMedia::initBrowser() +bool LLViewerMedia::textureHasMedia(const LLUUID& texture_id) { - LLMediaManagerData* init_data = new LLMediaManagerData; - buildMediaManagerData( init_data ); - LLMediaManager::initBrowser( init_data ); - delete init_data; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); - // We use a custom user agent with viewer version and skin name. - LLViewerMediaImpl::updateBrowserUserAgent(); + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + if(pimpl->getMediaTextureID() == texture_id) + { + return true; + } + } + return false; } ////////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMedia::initClass() +void LLViewerMedia::setVolume(F32 volume) { - // *TODO: This looks like a memory leak to me. JC - LLMediaManagerData* init_data = new LLMediaManagerData; - buildMediaManagerData( init_data ); - LLMediaManager::initClass( init_data ); - delete init_data; + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); - LLMediaManager* mm = LLMediaManager::getInstance(); - LLMIMETypes::mime_info_map_t::const_iterator it; - for (it = LLMIMETypes::sMap.begin(); it != LLMIMETypes::sMap.end(); ++it) + for(; iter != end; iter++) { - const std::string& mime_type = it->first; - const LLMIMETypes::LLMIMEInfo& info = it->second; - mm->addMimeTypeImplNameMap( mime_type, info.mImpl ); + LLViewerMediaImpl* pimpl = *iter; + pimpl->setVolume(volume); } } ////////////////////////////////////////////////////////////////////////////////////////// // static -void LLViewerMedia::buildMediaManagerData( LLMediaManagerData* init_data ) +void LLViewerMedia::updateMedia() { -// std::string executable_dir = std::string( arg0 ).substr( 0, std::string( arg0 ).find_last_of("\\/") ); -// std::string component_dir = std::string( executable_dir ).substr( 0, std::string( executable_dir ).find_last_of("\\/") ); -// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); -// component_dir = std::string( component_dir ).substr( 0, std::string( component_dir ).find_last_of("\\/") ); -// component_dir += "\\newview\\app_settings\\mozilla"; - - -#if LL_DARWIN - // For Mac OS, we store both the shared libraries and the runtime files (chrome/, plugins/, etc) in - // Second Life.app/Contents/MacOS/. This matches the way Firefox is distributed on the Mac. - std::string component_dir(gDirUtilp->getExecutableDir()); -#elif LL_WINDOWS - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - #ifdef LL_DEBUG - component_dir += "mozilla_debug"; - #else // LL_DEBUG - component_dir += "mozilla"; - #endif // LL_DEBUG -#elif LL_LINUX - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - component_dir += "mozilla-runtime-linux-i686"; -#elif LL_SOLARIS - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - #ifdef __sparc - component_dir += "mozilla-solaris-sparc"; - #else - component_dir += "mozilla-solaris-i686"; - #endif -#else - std::string component_dir( gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "" ) ); - component_dir += gDirUtilp->getDirDelimiter(); - component_dir += "mozilla"; -#endif - - std::string application_dir = gDirUtilp->getExecutableDir(); - - init_data->setBrowserApplicationDir( application_dir ); - std::string profile_dir = gDirUtilp->getExpandedFilename( LL_PATH_MOZILLA_PROFILE, "" ); - init_data->setBrowserProfileDir( profile_dir ); - init_data->setBrowserComponentDir( component_dir ); - std::string profile_name("Second Life"); - init_data->setBrowserProfileName( profile_name ); - init_data->setBrowserParentWindow( gViewerWindow->getMediaWindow() ); - - // Users can change skins while client is running, so make sure - // we pick up on changes. - gSavedSettings.getControl("SkinCurrent")->getSignal()->connect( - boost::bind( LLViewerMediaImpl::handleSkinCurrentChanged, _1 ) ); + impl_list::iterator iter = sViewerMediaImplList.begin(); + impl_list::iterator end = sViewerMediaImplList.end(); + for(; iter != end; iter++) + { + LLViewerMediaImpl* pimpl = *iter; + pimpl->update(); + } } ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerMedia::cleanupClass() { - stop() ; - LLMediaManager::cleanupClass(); -} - -// static -void LLViewerMedia::play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop) -{ - sViewerMediaImpl.play(media_url, mime_type, placeholder_texture_id, - media_width, media_height, media_auto_scale, media_loop); -} - -// static -void LLViewerMedia::stop() -{ - sViewerMediaImpl.stop(); -} - -// static -void LLViewerMedia::pause() -{ - sViewerMediaImpl.pause(); -} - -// static -void LLViewerMedia::start() -{ - sViewerMediaImpl.start(); -} - -// static -void LLViewerMedia::seek(F32 time) -{ - sViewerMediaImpl.seek(time); -} - -// static -void LLViewerMedia::setVolume(F32 volume) -{ - sViewerMediaImpl.setVolume(volume); -} - -// static -LLMediaBase::EStatus LLViewerMedia::getStatus() -{ - return sViewerMediaImpl.getStatus(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -LLUUID LLViewerMedia::getMediaTextureID() -{ - return sViewerMediaImpl.getMediaTextureID(); -} - -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getMediaSize(S32 *media_width, S32 *media_height) -{ - // make sure we're valid - - if ( sViewerMediaImpl.mMediaSource != NULL ) + // This is no longer necessary, since the list is no longer smart pointers. +#if 0 + while(!sViewerMediaImplList.empty()) { - *media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); - *media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); + sViewerMediaImplList.pop_back(); + } +#endif +} + +////////////////////////////////////////////////////////////////////////////////////////// +// LLViewerMediaImpl +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::LLViewerMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + const std::string& mime_type) +: + mMediaSource( NULL ), + mMovieImageHasMips(false), + mTextureId(texture_id), + mMediaWidth(media_width), + mMediaHeight(media_height), + mMediaAutoScale(media_auto_scale), + mMediaLoop(media_loop), + mMediaURL(media_url), + mMimeType(mime_type), + mNeedsNewTexture(true), + mSuspendUpdates(false), + mVisible(true) +{ + createMediaSource(); +} + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaImpl::~LLViewerMediaImpl() +{ + if( gEditMenuHandler == this ) + { + gEditMenuHandler = NULL; + } + + destroyMediaSource(); + LLViewerMedia::removeMedia(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializeMedia(const std::string& mime_type) +{ + if((mMediaSource == NULL) || (mMimeType != mime_type)) + { + if(! initializePlugin(mime_type)) + { + LL_WARNS("Plugin") << "plugin intialization failed for mime type: " << mime_type << LL_ENDL; + LLSD args; + args["MIME_TYPE"] = mime_type; + LLNotifications::instance().add("NoPlugin", args); + + return false; + } + } + + // play(); + return (mMediaSource != NULL); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::createMediaSource() +{ + if(! mMediaURL.empty()) + { + navigateTo(mMediaURL, mMimeType, true); + } + else if(! mMimeType.empty()) + { + initializeMedia(mMimeType); + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::destroyMediaSource() +{ + mNeedsNewTexture = true; + if(! mMediaSource) + { + return; + } + // Restore the texture + updateMovieImage(LLUUID::null, false); + delete mMediaSource; + mMediaSource = NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setMediaType(const std::string& media_type) +{ + mMimeType = media_type; +} + +////////////////////////////////////////////////////////////////////////////////////////// +/*static*/ +LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height) +{ + std::string plugin_basename = LLMIMETypes::implType(media_type); + + if(plugin_basename.empty()) + { + LL_WARNS("Media") << "Couldn't find plugin for media type " << media_type << LL_ENDL; + } + else + { + std::string plugins_path = gDirUtilp->getLLPluginDir(); + plugins_path += gDirUtilp->getDirDelimiter(); + + std::string launcher_name = gDirUtilp->getLLPluginLauncher(); + std::string plugin_name = gDirUtilp->getLLPluginFilename(plugin_basename); + + // See if the plugin executable exists + llstat s; + if(LLFile::stat(launcher_name, &s)) + { + LL_WARNS("Media") << "Couldn't find launcher at " << launcher_name << LL_ENDL; + } + else if(LLFile::stat(plugin_name, &s)) + { + LL_WARNS("Media") << "Couldn't find plugin at " << plugin_name << LL_ENDL; + } + else + { + LLPluginClassMedia* media_source = new LLPluginClassMedia(owner); + media_source->setSize(default_width, default_height); + if (media_source->init(launcher_name, plugin_name)) + { + return media_source; + } + else + { + LL_WARNS("Media") << "Failed to init plugin. Destroying." << LL_ENDL; + delete media_source; + } + } + } + + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::initializePlugin(const std::string& media_type) +{ + if(mMediaSource) + { + // Save the previous media source's last set size before destroying it. + mMediaWidth = mMediaSource->getSetWidth(); + mMediaHeight = mMediaSource->getSetHeight(); + } + + // Always delete the old media impl first. + destroyMediaSource(); + + // and unconditionally set the mime type + mMimeType = media_type; + + LLPluginClassMedia* media_source = newSourceFromMediaType(media_type, this, mMediaWidth, mMediaHeight); + + if (media_source) + { + media_source->setDisableTimeout(gSavedSettings.getBOOL("DebugPluginDisableTimeout")); + media_source->setLoop(mMediaLoop); + media_source->setAutoScale(mMediaAutoScale); + media_source->setBrowserUserAgent(LLViewerMedia::getCurrentUserAgent()); + + mMediaSource = media_source; return true; } + return false; } -////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::getTextureSize(S32 *texture_width, S32 *texture_height) +void LLViewerMediaImpl::setSize(int width, int height) { - if ( sViewerMediaImpl.mMediaSource != NULL ) + mMediaWidth = width; + mMediaHeight = height; + if(mMediaSource) { - S32 media_width = sViewerMediaImpl.mMediaSource->getMediaWidth(); - S32 media_height = sViewerMediaImpl.mMediaSource->getMediaHeight(); - *texture_width = LLMediaManager::textureWidthFromMediaWidth( media_width ); - *texture_height = LLMediaManager::textureHeightFromMediaHeight( media_height ); - return true; + mMediaSource->setSize(width, height); } - return false; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::play() +{ + // first stop any previously playing media + // stop(); + + // mMediaSource->addObserver( this ); + if(mMediaSource == NULL) + { + if(!initializePlugin(mMimeType)) + { + // Plugin failed initialization... should assert or something + return; + } + } + + // updateMovieImage(mTextureId, true); + + mMediaSource->loadURI( mMediaURL ); + if(/*mMediaSource->pluginSupportsMediaTime()*/ true) + { + start(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::stop() +{ + if(mMediaSource) + { + mMediaSource->stop(); + // destroyMediaSource(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::pause() +{ + if(mMediaSource) + { + mMediaSource->pause(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::start() +{ + if(mMediaSource) + { + mMediaSource->start(); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::seek(F32 time) +{ + if(mMediaSource) + { + mMediaSource->seek(time); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVolume(F32 volume) +{ + if(mMediaSource) + { + mMediaSource->setVolume(volume); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::focus(bool focus) +{ + if (mMediaSource) + { + // call focus just for the hell of it, even though this apopears to be a nop + mMediaSource->focus(focus); + if (focus) + { + // spoof a mouse click to *actually* pass focus + // Don't do this anymore -- it actually clicks through now. +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, 1, 1, 0); +// mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, 1, 1, 0); + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseDown(S32 x, S32 y) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOWN, x, y, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseUp(S32 x, S32 y) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, x, y, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseMove(S32 x, S32 y) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_MOVE, x, y, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseLeftDoubleClick(S32 x, S32 y) +{ + scaleMouse(&x, &y); + mLastMouseX = x; + mLastMouseY = y; + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_DOUBLE_CLICK, x, y, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::onMouseCaptureLost() +{ + if (mMediaSource) + { + mMediaSource->mouseEvent(LLPluginClassMedia::MOUSE_EVENT_UP, mLastMouseX, mLastMouseY, 0); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +BOOL LLViewerMediaImpl::handleMouseUp(S32 x, S32 y, MASK mask) +{ + // NOTE: this is called when the mouse is released when we have capture. + // Due to the way mouse coordinates are mapped to the object, we can't use the x and y coordinates that come in with the event. + + if(hasMouseCapture()) + { + // Release the mouse -- this will also send a mouseup to the media + gFocusMgr.setMouseCapture( FALSE ); + } + + return TRUE; +} +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateHome() +{ + if(mMediaSource) + { + mMediaSource->loadURI( mHomeURL ); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateTo(const std::string& url, const std::string& mime_type, bool rediscover_type) +{ + if(rediscover_type) + { + + LLURI uri(url); + std::string scheme = uri.scheme(); + + if(scheme.empty() || "http" == scheme || "https" == scheme) + { + LLHTTPClient::getHeaderOnly( url, new LLMimeDiscoveryResponder(this)); + } + else if("data" == scheme || "file" == scheme || "about" == scheme) + { + // FIXME: figure out how to really discover the type for these schemes + // We use "data" internally for a text/html url for loading the login screen + if(initializeMedia("text/html")) + { + mMediaSource->loadURI( url ); + } + } + else + { + // This catches 'rtsp://' urls + if(initializeMedia(scheme)) + { + mMediaSource->loadURI( url ); + } + } + } + else if (mMediaSource) + { + mMediaSource->loadURI( url ); + } + else if(initializeMedia(mime_type) && mMediaSource) + { + mMediaSource->loadURI( url ); + } + else + { + LL_WARNS("Media") << "Couldn't navigate to: " << url << " as there is no media type for: " << mime_type << LL_ENDL; + return; + } + mMediaURL = url; + +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::navigateStop() +{ + if(mMediaSource) + { + mMediaSource->browse_stop(); + } + +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleKeyHere(KEY key, MASK mask) +{ + bool result = false; + + if (mMediaSource) + { + result = mMediaSource->keyEvent(LLPluginClassMedia::KEY_EVENT_DOWN ,key, mask); + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::handleUnicodeCharHere(llwchar uni_char) +{ + bool result = false; + + if (mMediaSource) + { + mMediaSource->textInput(wstring_to_utf8str(LLWString(1, uni_char))); + } + + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateForward() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryForwardAvailable(); + } + return result; +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::canNavigateBack() +{ + BOOL result = FALSE; + if (mMediaSource) + { + result = mMediaSource->getHistoryBackAvailable(); + } + return result; } ////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::updateImagesMediaStreams() +void LLViewerMediaImpl::updateMovieImage(const LLUUID& uuid, BOOL active) { - sViewerMediaImpl.updateImagesMediaStreams(); + // IF the media image hasn't changed, do nothing + if (mTextureId == uuid) + { + return; + } + // If we have changed media uuid, restore the old one + if (!mTextureId.isNull()) + { + LLViewerMediaTexture* old_image = LLViewerTextureManager::findMediaTexture( mTextureId ); + if (old_image) + { + old_image->setPlaying(FALSE); + LLViewerTexture* original_texture = old_image->getOldTexture(); + if(original_texture) + { + old_image->switchToTexture(original_texture); + } + } + } + // If the movie is playing, set the new media image + if (active && !uuid.isNull()) + { + LLViewerMediaTexture* viewerImage = LLViewerTextureManager::findMediaTexture( uuid ); + if( viewerImage ) + { + mTextureId = uuid; + + // Can't use mipmaps for movies because they don't update the full image + mMovieImageHasMips = viewerImage->getUseMipMaps(); + viewerImage->reinit(FALSE); + // FIXME +// viewerImage->mIsMediaTexture = TRUE; + } + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::update() +{ + if(mMediaSource == NULL) + { + return; + } + + mMediaSource->idle(); + + if(mMediaSource->isPluginExited()) + { + destroyMediaSource(); + return; + } + + if(!mMediaSource->textureValid()) + { + return; + } + + if(mSuspendUpdates || !mVisible) + { + return; + } + + LLViewerMediaTexture* placeholder_image = updatePlaceholderImage(); + + if(placeholder_image) + { + LLRect dirty_rect; + if(mMediaSource->getDirty(&dirty_rect)) + { + // Constrain the dirty rect to be inside the texture + S32 x_pos = llmax(dirty_rect.mLeft, 0); + S32 y_pos = llmax(dirty_rect.mBottom, 0); + S32 width = llmin(dirty_rect.mRight, placeholder_image->getWidth()) - x_pos; + S32 height = llmin(dirty_rect.mTop, placeholder_image->getHeight()) - y_pos; + + if(width > 0 && height > 0) + { + + U8* data = mMediaSource->getBitsData(); + + // Offset the pixels pointer to match x_pos and y_pos + data += ( x_pos * mMediaSource->getTextureDepth() * mMediaSource->getBitsWidth() ); + data += ( y_pos * mMediaSource->getTextureDepth() ); + + placeholder_image->setSubImage( + data, + mMediaSource->getBitsWidth(), + mMediaSource->getBitsHeight(), + x_pos, + y_pos, + width, + height); + + } + + mMediaSource->resetDirty(); + } + } +} + + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::updateImagesMediaStreams() +{ +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLViewerMediaTexture* LLViewerMediaImpl::updatePlaceholderImage() +{ + if(mTextureId.isNull()) + { + // The code that created this instance will read from the plugin's bits. + return NULL; + } + + LLViewerMediaTexture* placeholder_image = LLViewerTextureManager::getMediaTexture( mTextureId ); + + if (mNeedsNewTexture + || placeholder_image->getUseMipMaps() +// || ! placeholder_image->getType() == LLViewerTexture::MEDIA_TEXTURE + || placeholder_image->getWidth() != mMediaSource->getTextureWidth() + || placeholder_image->getHeight() != mMediaSource->getTextureHeight()) + { + llinfos << "initializing media placeholder" << llendl; + llinfos << "movie image id " << mTextureId << llendl; + + int texture_width = mMediaSource->getTextureWidth(); + int texture_height = mMediaSource->getTextureHeight(); + int texture_depth = mMediaSource->getTextureDepth(); + + // MEDIAOPT: check to see if size actually changed before doing work + placeholder_image->destroyGLTexture(); + // MEDIAOPT: apparently just calling setUseMipMaps(FALSE) doesn't work? + placeholder_image->reinit(FALSE); // probably not needed + + // MEDIAOPT: seems insane that we actually have to make an imageraw then + // immediately discard it + LLPointer raw = new LLImageRaw(texture_width, texture_height, texture_depth); + raw->clear(0x0f, 0x0f, 0x0f, 0xff); + int discard_level = 0; + + // ask media source for correct GL image format constants + placeholder_image->setExplicitFormat(mMediaSource->getTextureFormatInternal(), + mMediaSource->getTextureFormatPrimary(), + mMediaSource->getTextureFormatType(), + mMediaSource->getTextureFormatSwapBytes()); + + placeholder_image->createGLTexture(discard_level, raw); + + // placeholder_image->setExplicitFormat() + placeholder_image->setUseMipMaps(FALSE); + + // MEDIAOPT: set this dynamically on play/stop + // FIXME +// placeholder_image->mIsMediaTexture = true; + mNeedsNewTexture = false; + } + + return placeholder_image; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +LLUUID LLViewerMediaImpl::getMediaTextureID() +{ + return mTextureId; +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::setVisible(bool visible) +{ + mVisible = visible; + + if(mVisible) + { + if(mMediaSource && mMediaSource->isPluginExited()) + { + destroyMediaSource(); + } + + if(!mMediaSource) + { + createMediaSource(); + } + } + + if(mMediaSource) + { + mMediaSource->setPriority(mVisible?LLPluginClassMedia::PRIORITY_NORMAL:LLPluginClassMedia::PRIORITY_HIDDEN); + } +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::mouseCapture() +{ + gFocusMgr.setMouseCapture(this); +} + +////////////////////////////////////////////////////////////////////////////////////////// +void LLViewerMediaImpl::scaleMouse(S32 *mouse_x, S32 *mouse_y) +{ +#if 0 + S32 media_width, media_height; + S32 texture_width, texture_height; + getMediaSize( &media_width, &media_height ); + getTextureSize( &texture_width, &texture_height ); + S32 y_delta = texture_height - media_height; + + *mouse_y -= y_delta; +#endif +} + +////////////////////////////////////////////////////////////////////////////////////////// +bool LLViewerMediaImpl::isMediaPlaying() +{ + bool result = false; + + if(mMediaSource) + { + EMediaStatus status = mMediaSource->getStatus(); + if(status == MEDIA_PLAYING || status == MEDIA_LOADING) + result = true; + } + + return result; } ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isMediaPlaying() +bool LLViewerMediaImpl::isMediaPaused() { - LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); - return (status == LLMediaBase::STATUS_STARTED ); + bool result = false; + + if(mMediaSource) + { + if(mMediaSource->getStatus() == MEDIA_PAUSED) + result = true; + } + + return result; } + ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::isMediaPaused() +// +bool LLViewerMediaImpl::hasMedia() { - LLMediaBase::EStatus status = sViewerMediaImpl.getStatus(); - return (status == LLMediaBase::STATUS_PAUSED); + return mMediaSource != NULL; } + ////////////////////////////////////////////////////////////////////////////////////////// -// static -bool LLViewerMedia::hasMedia() +void LLViewerMediaImpl::handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event) { - return sViewerMediaImpl.mMediaSource != NULL; + switch(event) + { + case MEDIA_EVENT_PLUGIN_FAILED: + { + LLSD args; + args["PLUGIN"] = LLMIMETypes::implType(mMimeType); + LLNotifications::instance().add("MediaPluginFailed", args); + } + break; + default: + break; + } + // Just chain the event to observers. + emitEvent(self, event); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::cut() +{ + if (mMediaSource) + mMediaSource->cut(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCut() const +{ + if (mMediaSource) + return mMediaSource->canCut(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::copy() +{ + if (mMediaSource) + mMediaSource->copy(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canCopy() const +{ + if (mMediaSource) + return mMediaSource->canCopy(); + else + return FALSE; +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +void +LLViewerMediaImpl::paste() +{ + if (mMediaSource) + mMediaSource->paste(); +} + +//////////////////////////////////////////////////////////////////////////////// +// virtual +BOOL +LLViewerMediaImpl::canPaste() const +{ + if (mMediaSource) + return mMediaSource->canPaste(); + else + return FALSE; +} + + +////////////////////////////////////////////////////////////////////////////////////////// +//static +void LLViewerMedia::toggleMusicPlay(void*) +{ +// FIXME: This probably doesn't belong here +#if 0 + if (mMusicState != PLAYING) + { + mMusicState = PLAYING; // desired state + if (gAudiop) + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if ( parcel ) + { + gAudiop->startInternetStream(parcel->getMusicURL()); + } + } + } + else + { + mMusicState = STOPPED; // desired state + if (gAudiop) + { + gAudiop->stopInternetStream(); + } + } +#endif } ////////////////////////////////////////////////////////////////////////////////////////// //static -bool LLViewerMedia::isActiveMediaTexture(const LLUUID& id) +void LLViewerMedia::toggleMediaPlay(void*) { - return (id.notNull() - && id == getMediaTextureID() - && isMediaPlaying()); +// FIXME: This probably doesn't belong here +#if 0 + if (LLViewerMedia::isMediaPaused()) + { + LLViewerParcelMedia::start(); + } + else if(LLViewerMedia::isMediaPlaying()) + { + LLViewerParcelMedia::pause(); + } + else + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + LLViewerParcelMedia::play(parcel); + } + } +#endif } ////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getMediaURL() +//static +void LLViewerMedia::mediaStop(void*) { - return sViewerMediaImpl.mMediaURL; +// FIXME: This probably doesn't belong here +#if 0 + LLViewerParcelMedia::stop(); +#endif } + ////////////////////////////////////////////////////////////////////////////////////////// -// static -std::string LLViewerMedia::getMimeType() -{ - return sViewerMediaImpl.mMimeType; -} -////////////////////////////////////////////////////////////////////////////////////////// -// static -void LLViewerMedia::setMimeType(std::string mime_type) -{ - sViewerMediaImpl.mMimeType = mime_type; +//static +bool LLViewerMedia::isMusicPlaying() +{ +// FIXME: This probably doesn't belong here +// FIXME: make this work + return false; } diff --git a/indra/newview/llviewermedia.h b/indra/newview/llviewermedia.h index 600d7409e2..68a49662e7 100644 --- a/indra/newview/llviewermedia.h +++ b/indra/newview/llviewermedia.h @@ -33,50 +33,196 @@ #ifndef LLVIEWERMEDIA_H #define LLVIEWERMEDIA_H -#include "llmediabase.h" // for status codes +#include "llfocusmgr.h" +#include "lleditmenuhandler.h" -class LLMediaManagerData; +#include "llpanel.h" +#include "llpluginclassmediaowner.h" + +#include "llviewermediaobserver.h" + +class LLViewerMediaImpl; class LLUUID; +class LLViewerMediaTexture; + +typedef LLPointer viewer_media_t; +/////////////////////////////////////////////////////////////////////////////// +// +class LLViewerMediaEventEmitter +{ +public: + virtual ~LLViewerMediaEventEmitter(); + + bool addObserver( LLViewerMediaObserver* subject ); + bool remObserver( LLViewerMediaObserver* subject ); + void emitEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent event); + +private: + typedef std::list< LLViewerMediaObserver* > observerListType; + observerListType mObservers; +}; class LLViewerMedia { + LOG_CLASS(LLViewerMedia); public: // Special case early init for just web browser component // so we can show login screen. See .cpp file for details. JC - static void initBrowser(); - static void initClass(); + static viewer_media_t newMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + std::string mime_type = "none/none"); + + static void removeMedia(LLViewerMediaImpl* media); + static LLViewerMediaImpl* getMediaImplFromTextureID(const LLUUID& texture_id); + static std::string getCurrentUserAgent(); + static void updateBrowserUserAgent(); + static bool handleSkinCurrentChanged(const LLSD& /*newvalue*/); + static bool textureHasMedia(const LLUUID& texture_id); + static void setVolume(F32 volume); + + static void updateMedia(); + static bool isMusicPlaying(); + static void cleanupClass(); - static void play(const std::string& media_url, - const std::string& mime_type, - const LLUUID& placeholder_texture_id, - S32 media_width, S32 media_height, U8 media_auto_scale, - U8 media_loop); - static void stop(); - static void pause(); - static void start(); - static void seek(F32 time); - static void setVolume(F32 volume); - static LLMediaBase::EStatus getStatus(); + static void toggleMusicPlay(void*); + static void toggleMediaPlay(void*); + static void mediaStop(void*); +}; - static LLUUID getMediaTextureID(); - static bool getMediaSize(S32 *media_width, S32 *media_height); - static bool getTextureSize(S32 *texture_width, S32 *texture_height); - static bool isMediaPlaying(); - static bool isMediaPaused(); - static bool hasMedia(); - static bool isActiveMediaTexture(const LLUUID& id); +// Implementation functions not exported into header file +class LLViewerMediaImpl + : public LLMouseHandler, public LLRefCount, public LLPluginClassMediaOwner, public LLViewerMediaEventEmitter, public LLEditMenuHandler +{ + LOG_CLASS(LLViewerMediaImpl); +public: - static std::string getMediaURL(); - static std::string getMimeType(); - static void setMimeType(std::string mime_type); + LLViewerMediaImpl(const std::string& media_url, + const LLUUID& texture_id, + S32 media_width, + S32 media_height, + U8 media_auto_scale, + U8 media_loop, + const std::string& mime_type); - static void updateImagesMediaStreams(); + ~LLViewerMediaImpl(); + void createMediaSource(); + void destroyMediaSource(); + void setMediaType(const std::string& media_type); + bool initializeMedia(const std::string& mime_type); + bool initializePlugin(const std::string& media_type); + LLPluginClassMedia* getMediaPlugin() { return mMediaSource; } + void setSize(int width, int height); - private: - // Fill in initialization data for LLMediaManager::initClass() - static void buildMediaManagerData( LLMediaManagerData* init_data ); + void play(); + void stop(); + void pause(); + void start(); + void seek(F32 time); + void setVolume(F32 volume); + void focus(bool focus); + void mouseDown(S32 x, S32 y); + void mouseUp(S32 x, S32 y); + void mouseMove(S32 x, S32 y); + void mouseLeftDoubleClick(S32 x,S32 y ); + void mouseCapture(); + + void navigateHome(); + void navigateTo(const std::string& url, const std::string& mime_type = "", bool rediscover_type = false); + void navigateStop(); + bool handleKeyHere(KEY key, MASK mask); + bool handleUnicodeCharHere(llwchar uni_char); + bool canNavigateForward(); + bool canNavigateBack(); + std::string getMediaURL() { return mMediaURL; } + std::string getMediaHomeURL() { return mHomeURL; } + std::string getMimeType() { return mMimeType; } + void scaleMouse(S32 *mouse_x, S32 *mouse_y); + + void update(); + void updateMovieImage(const LLUUID& image_id, BOOL active); + void updateImagesMediaStreams(); + LLUUID getMediaTextureID(); + + void suspendUpdates(bool suspend) { mSuspendUpdates = suspend; }; + void setVisible(bool visible); + + bool isMediaPlaying(); + bool isMediaPaused(); + bool hasMedia(); + + // utility function to create a ready-to-use media instance from a desired media type. + static LLPluginClassMedia* newSourceFromMediaType(std::string media_type, LLPluginClassMediaOwner *owner /* may be NULL */, S32 default_width, S32 default_height); + + // Internally set our desired browser user agent string, including + // the Second Life version and skin name. Used because we can + // switch skins without restarting the app. + static void updateBrowserUserAgent(); + + // Callback for when the SkinCurrent control is changed to + // switch the user agent string to indicate the new skin. + static bool handleSkinCurrentChanged(const LLSD& newvalue); + + // need these to handle mouseup... + /*virtual*/ void onMouseCaptureLost(); + /*virtual*/ BOOL handleMouseUp(S32 x, S32 y, MASK mask); + + // Grr... the only thing I want as an LLMouseHandler are the onMouseCaptureLost and handleMouseUp calls. + // Sadly, these are all pure virtual, so I have to supply implementations here: + /*virtual*/ BOOL handleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleScrollWheel(S32 x, S32 y, S32 clicks) { return FALSE; }; + /*virtual*/ BOOL handleDoubleClick(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleRightMouseUp(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleToolTip(S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen) { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseDown(S32 x, S32 y, MASK mask) { return FALSE; }; + /*virtual*/ BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask) {return FALSE; }; + /*virtual*/ const std::string& getName() const { return LLStringUtil::null; }; + /*virtual*/ BOOL isView() const { return FALSE; }; + /*virtual*/ void screenPointToLocal(S32 screen_x, S32 screen_y, S32* local_x, S32* local_y) const {}; + /*virtual*/ void localPointToScreen(S32 local_x, S32 local_y, S32* screen_x, S32* screen_y) const {}; + /*virtual*/ BOOL hasMouseCapture() { return gFocusMgr.getMouseCapture() == this; }; + + // Inherited from LLPluginClassMediaOwner + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, LLPluginClassMediaOwner::EMediaEvent); + + // LLEditMenuHandler overrides + /*virtual*/ void cut(); + /*virtual*/ BOOL canCut() const; + + /*virtual*/ void copy(); + /*virtual*/ BOOL canCopy() const; + + /*virtual*/ void paste(); + /*virtual*/ BOOL canPaste() const; + +public: + // a single media url with some data and an impl. + LLPluginClassMedia* mMediaSource; + LLUUID mTextureId; + bool mMovieImageHasMips; + std::string mMediaURL; + std::string mHomeURL; + std::string mMimeType; + S32 mLastMouseX; // save the last mouse coord we get, so when we lose capture we can simulate a mouseup at that point. + S32 mLastMouseY; + S32 mMediaWidth; + S32 mMediaHeight; + bool mMediaAutoScale; + bool mMediaLoop; + bool mNeedsNewTexture; + bool mSuspendUpdates; + bool mVisible; + + +private: + LLViewerMediaTexture *updatePlaceholderImage(); }; #endif // LLVIEWERMEDIA_H diff --git a/indra/newview/llviewermedia_streamingaudio.cpp b/indra/newview/llviewermedia_streamingaudio.cpp new file mode 100644 index 0000000000..90cfb85821 --- /dev/null +++ b/indra/newview/llviewermedia_streamingaudio.cpp @@ -0,0 +1,167 @@ +/** + * @file llviewermedia_streamingaudio.h + * @author Tofu Linden, Sam Kolb + * @brief LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugins API. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#include "llviewerprecompiledheaders.h" +#include "linden_common.h" +#include "llpluginclassmedia.h" +#include "llviewermedia.h" + +#include "llviewermedia_streamingaudio.h" + +#include "llmimetypes.h" +#include "llvfs.h" +#include "lldir.h" + + +LLStreamingAudio_MediaPlugins::LLStreamingAudio_MediaPlugins() : + mMediaPlugin(NULL), + mGain(1.0) +{ + // nothing interesting to do? + // we will lazily create a media plugin at play-time, if none exists. +} + +LLStreamingAudio_MediaPlugins::~LLStreamingAudio_MediaPlugins() +{ + delete mMediaPlugin; + mMediaPlugin = NULL; +} + +void LLStreamingAudio_MediaPlugins::start(const std::string& url) +{ + if (!mMediaPlugin) // lazy-init the underlying media plugin + { + mMediaPlugin = initializeMedia("audio/mpeg"); // assumes that whatever media implementation supports mp3 also supports vorbis. + llinfos << "mMediaPlugin is now " << mMediaPlugin << llendl; + } + + if(!mMediaPlugin) + return; + + if (!url.empty()) { + llinfos << "Starting internet stream: " << url << llendl; + mURL = url; + mMediaPlugin->loadURI ( url ); + mMediaPlugin->start(); + llinfos << "Playing....." << llendl; + } else { + llinfos << "setting stream to NULL"<< llendl; + mURL.clear(); + mMediaPlugin->stop(); + } +} + +void LLStreamingAudio_MediaPlugins::stop() +{ + if(mMediaPlugin) + { + mMediaPlugin->stop(); + } + + mURL.clear(); +} + +void LLStreamingAudio_MediaPlugins::pause(int pause) +{ + if(!mMediaPlugin) + return; + + if(pause) + { + mMediaPlugin->pause(); + } + else + { + mMediaPlugin->start(); + } +} + +void LLStreamingAudio_MediaPlugins::update() +{ + if (mMediaPlugin) + mMediaPlugin->idle(); +} + +int LLStreamingAudio_MediaPlugins::isPlaying() +{ + if (!mMediaPlugin) + return 0; + + // *TODO: can probably do better than this + if (mMediaPlugin->isPluginRunning()) + { + return 1; // Active and playing + } + + if (mMediaPlugin->isPluginExited()) + { + return 0; // stopped + } + + return 2; // paused +} + +void LLStreamingAudio_MediaPlugins::setGain(F32 vol) +{ + mGain = vol; + + if(!mMediaPlugin) + return; + + vol = llclamp(vol, 0.f, 1.f); + mMediaPlugin->setVolume(vol); +} + +F32 LLStreamingAudio_MediaPlugins::getGain() +{ + return mGain; +} + +std::string LLStreamingAudio_MediaPlugins::getURL() +{ + return mURL; +} + +LLPluginClassMedia* LLStreamingAudio_MediaPlugins::initializeMedia(const std::string& media_type) +{ + LLPluginClassMediaOwner* owner = NULL; + S32 default_size = 1; // audio-only - be minimal, doesn't matter + LLPluginClassMedia* media_source = LLViewerMediaImpl::newSourceFromMediaType(media_type, owner, default_size, default_size); + + if (media_source) + { + media_source->setLoop(false); // audio streams are not expected to loop + } + + return media_source; +} + diff --git a/indra/newview/llviewermedia_streamingaudio.h b/indra/newview/llviewermedia_streamingaudio.h new file mode 100644 index 0000000000..270bab7625 --- /dev/null +++ b/indra/newview/llviewermedia_streamingaudio.h @@ -0,0 +1,69 @@ +/** + * @file llviewermedia_streamingaudio.h + * @author Tofu Linden + * @brief Definition of LLStreamingAudio_MediaPlugins implementation - an implementation of the streaming audio interface which is implemented as a client of the media plugins API. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * + * Copyright (c) 2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWERMEDIA_STREAMINGAUDIO_H +#define LL_VIEWERMEDIA_STREAMINGAUDIO_H + + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" + +class LLPluginClassMedia; + +class LLStreamingAudio_MediaPlugins : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_MediaPlugins(); + /*virtual*/ ~LLStreamingAudio_MediaPlugins(); + + /*virtual*/ void start(const std::string& url); + /*virtual*/ void stop(); + /*virtual*/ void pause(int pause); + /*virtual*/ void update(); + /*virtual*/ int isPlaying(); + /*virtual*/ void setGain(F32 vol); + /*virtual*/ F32 getGain(); + /*virtual*/ std::string getURL(); + +private: + LLPluginClassMedia* initializeMedia(const std::string& media_type); + + LLPluginClassMedia *mMediaPlugin; + + std::string mURL; + F32 mGain; +}; + + +#endif //LL_VIEWERMEDIA_STREAMINGAUDIO_H diff --git a/indra/newview/llviewermediafocus.cpp b/indra/newview/llviewermediafocus.cpp new file mode 100644 index 0000000000..60eabd730f --- /dev/null +++ b/indra/newview/llviewermediafocus.cpp @@ -0,0 +1,355 @@ +/** + * @file llviewermediafocus.cpp + * @brief Governs focus on Media prims + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewermediafocus.h" + +//LLViewerMediaFocus +#include "llviewerobjectlist.h" +#include "llpanelmediahud.h" +#include "llpluginclassmedia.h" +#include "llagent.h" +#include "lltoolpie.h" +#include "llviewercamera.h" +#include "llviewermedia.h" +#include "llhudview.h" +#include "lluictrlfactory.h" +#include "lldrawable.h" +#include "llparcel.h" +#include "llviewerparcelmgr.h" +#include "llweb.h" +// +// LLViewerMediaFocus +// + +LLViewerMediaFocus::LLViewerMediaFocus() +: mMouseOverFlag(false) +{ +} + +LLViewerMediaFocus::~LLViewerMediaFocus() +{ + // The destructor for LLSingletons happens at atexit() time, which is too late to do much. + // Clean up in cleanupClass() instead. +} + +void LLViewerMediaFocus::cleanupClass() +{ + LLViewerMediaFocus *self = LLViewerMediaFocus::getInstance(); + + if(self) + { + // mMediaHUD will have been deleted by this point -- don't try to delete it. + + /* Richard says: + all widgets are supposed to be destroyed at the same time + you shouldn't hold on to pointer to them outside of ui code + you can use the LLHandle approach + if you want to be type safe, you'll need to add a LLRootHandle to whatever derived class you are pointing to + look at llview::gethandle + its our version of a weak pointer + */ + if(self->mMediaHUD.get()) + { + self->mMediaHUD.get()->setMediaImpl(NULL); + } + self->mMediaImpl = NULL; + } + +} + + +void LLViewerMediaFocus::setFocusFace( BOOL b, LLPointer objectp, S32 face, viewer_media_t media_impl ) +{ + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (b && media_impl.notNull()) + { + mMediaImpl = media_impl; + LLSelectMgr::getInstance()->deselectAll(); + LLSelectMgr::getInstance()->selectObjectOnly(objectp, face); + + mFocus = LLSelectMgr::getInstance()->getSelection(); + if(mMediaHUD.get() && ! parcel->getMediaPreventCameraZoom()) + { + mMediaHUD.get()->resetZoomLevel(); + mMediaHUD.get()->nextZoomLevel(); + } + if (!mFocus->isEmpty()) + { + gFocusMgr.setKeyboardFocus(this); + } + mObjectID = objectp->getID(); + // LLViewerMedia::addObserver(this, mObjectID); + + + } + else + { + gFocusMgr.setKeyboardFocus(NULL); + mFocus = NULL; + if(! parcel->getMediaPreventCameraZoom()) + { + gAgent.setFocusOnAvatar(TRUE, ANIMATE); + } + // LLViewerMedia::remObserver(this, mObjectID); + + // Null out the media hud media pointer + if(mMediaHUD.get()) + { + mMediaHUD.get()->setMediaImpl(NULL); + } + + // and null out the media impl + mMediaImpl = NULL; + } + if(mMediaHUD.get()) + { + mMediaHUD.get()->setMediaFocus(b); + } +} +bool LLViewerMediaFocus::getFocus() +{ + if (gFocusMgr.getKeyboardFocus() == this) + { + return true; + } + return false; +} + +// This function selects an ideal viewing distance given a selection bounding box, normal, and padding value +void LLViewerMediaFocus::setCameraZoom(F32 padding_factor) +{ + LLPickInfo& pick = LLToolPie::getInstance()->getPick(); + + if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + pick = mPickInfo; + setFocusFace(true, pick.getObject(), pick.mObjectFace, mMediaImpl); + } + + if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) + { + gAgent.setFocusOnAvatar(FALSE, ANIMATE); + + LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection(); + F32 height; + F32 width; + F32 depth; + F32 angle_of_view; + F32 distance; + + // We need the aspect ratio, and the 3 components of the bbox as height, width, and depth. + F32 aspect_ratio = getBBoxAspectRatio(selection_bbox, pick.mNormal, &height, &width, &depth); + F32 camera_aspect = LLViewerCamera::getInstance()->getAspect(); + + // We will normally use the side of the volume aligned with the short side of the screen (i.e. the height for + // a screen in a landscape aspect ratio), however there is an edge case where the aspect ratio of the object is + // more extreme than the screen. In this case we invert the logic, using the longer component of both the object + // and the screen. + bool invert = (camera_aspect > 1.0f && aspect_ratio > camera_aspect) || + (camera_aspect < 1.0f && aspect_ratio < camera_aspect); + + // To calculate the optimum viewing distance we will need the angle of the shorter side of the view rectangle. + // In portrait mode this is the width, and in landscape it is the height. + // We then calculate the distance based on the corresponding side of the object bbox (width for portrait, height for landscape) + // We will add half the depth of the bounding box, as the distance projection uses the center point of the bbox. + if(camera_aspect < 1.0f || invert) + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect()); + distance = width * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); + } + else + { + angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getView()); + distance = height * 0.5 * padding_factor / tan(angle_of_view * 0.5f ); + } + + distance += depth * 0.5; + + // Finally animate the camera to this new position and focal point + gAgent.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(pick.mNormal * distance), + LLSelectMgr::getInstance()->getSelectionCenterGlobal(), LLSelectMgr::getInstance()->getSelection()->getFirstObject()->mID ); + } +} +void LLViewerMediaFocus::onFocusReceived() +{ + if(mMediaImpl.notNull()) + mMediaImpl->focus(true); + + LLFocusableElement::onFocusReceived(); +} + +void LLViewerMediaFocus::onFocusLost() +{ + if(mMediaImpl.notNull()) + mMediaImpl->focus(false); + gViewerWindow->focusClient(); + mFocus = NULL; + LLFocusableElement::onFocusLost(); +} +void LLViewerMediaFocus::setMouseOverFlag(bool b, viewer_media_t media_impl) +{ + if (b && media_impl.notNull()) + { + if(! mMediaHUD.get()) + { + LLPanelMediaHUD* media_hud = new LLPanelMediaHUD(mMediaImpl); + mMediaHUD = media_hud->getHandle(); + gHUDView->addChild(media_hud); + } + mMediaHUD.get()->setMediaImpl(media_impl); + mMediaImpl = media_impl; + } + mMouseOverFlag = b; +} +LLUUID LLViewerMediaFocus::getSelectedUUID() +{ + LLViewerObject* object = mFocus->getFirstObject(); + return object ? object->getID() : LLUUID::null; +} +#if 0 // Must re-implement when the new media api event system is ready +void LLViewerMediaFocus::onNavigateComplete( const EventType& event_in ) +{ + if (hasFocus() && mLastURL != event_in.getStringValue()) + { + LLViewerMedia::focus(true, mObjectID); + // spoof mouse event to reassert focus + LLViewerMedia::mouseDown(1,1, mObjectID); + LLViewerMedia::mouseUp(1,1, mObjectID); + } + mLastURL = event_in.getStringValue(); +} +#endif +BOOL LLViewerMediaFocus::handleKey(KEY key, MASK mask, BOOL called_from_parent) +{ + if(mMediaImpl.notNull()) + mMediaImpl->handleKeyHere(key, mask); + return true; +} + +BOOL LLViewerMediaFocus::handleUnicodeChar(llwchar uni_char, BOOL called_from_parent) +{ + if(mMediaImpl.notNull()) + mMediaImpl->handleUnicodeCharHere(uni_char); + return true; +} +BOOL LLViewerMediaFocus::handleScrollWheel(S32 x, S32 y, S32 clicks) +{ + BOOL retval = FALSE; + if(mFocus.notNull() && mMediaImpl.notNull() && mMediaImpl->hasMedia()) + { + mMediaImpl->getMediaPlugin()->scrollEvent(x, y, clicks); + retval = TRUE; + } + return retval; +} + +void LLViewerMediaFocus::update() +{ + if (mMediaHUD.get()) + { + if(mFocus.notNull() || mMouseOverFlag || mMediaHUD.get()->isMouseOver()) + { + // mMediaHUD.get()->setVisible(true); + mMediaHUD.get()->updateShape(); + } + else + { + mMediaHUD.get()->setVisible(false); + } + } +} +// This function calculates the aspect ratio and the world aligned components of a selection bounding box. +F32 LLViewerMediaFocus::getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth) +{ + // Convert the selection normal and an up vector to local coordinate space of the bbox + LLVector3 local_normal = bbox.agentToLocalBasis(normal); + LLVector3 z_vec = bbox.agentToLocalBasis(LLVector3(0.0f, 0.0f, 1.0f)); + + LLVector3 comp1(0.f,0.f,0.f); + LLVector3 comp2(0.f,0.f,0.f); + LLVector3 bbox_max = bbox.getExtentLocal(); + F32 dot1 = 0.f; + F32 dot2 = 0.f; + + // The largest component of the localized normal vector is the depth component + // meaning that the other two are the legs of the rectangle. + local_normal.abs(); + if(local_normal.mV[VX] > local_normal.mV[VY]) + { + if(local_normal.mV[VX] > local_normal.mV[VZ]) + { + // Use the y and z comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VX]; + } + else + { + // Use the x and y comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VZ]; + } + } + else if(local_normal.mV[VY] > local_normal.mV[VZ]) + { + // Use the x and z comps + comp1.mV[VX] = bbox_max.mV[VX]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VY]; + } + else + { + // Use the x and y comps + comp1.mV[VY] = bbox_max.mV[VY]; + comp2.mV[VZ] = bbox_max.mV[VZ]; + *depth = bbox_max.mV[VX]; + } + + // The height is the vector closest to vertical in the bbox coordinate space (highest dot product value) + dot1 = comp1 * z_vec; + dot2 = comp2 * z_vec; + if(fabs(dot1) > fabs(dot2)) + { + *height = comp1.length(); + *width = comp2.length(); + } + else + { + *height = comp2.length(); + *width = comp1.length(); + } + + // Return the aspect ratio. + return *width / *height; +} diff --git a/indra/newview/llviewermediafocus.h b/indra/newview/llviewermediafocus.h new file mode 100644 index 0000000000..a078d24b6a --- /dev/null +++ b/indra/newview/llviewermediafocus.h @@ -0,0 +1,90 @@ +/** + * @file llpanelmsgs.h + * @brief Message popup preferences panel + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2007, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlife.com/developers/opensource/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at http://secondlife.com/developers/opensource/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_VIEWERMEDIAFOCUS_H +#define LL_VIEWERMEDIAFOCUS_H + +// includes for LLViewerMediaFocus +#include "llfocusmgr.h" +#include "llviewermedia.h" +#include "llviewerobject.h" +#include "llviewerwindow.h" +#include "llselectmgr.h" + +class LLViewerMediaImpl; +class LLPanelMediaHUD; + +class LLViewerMediaFocus : + public LLFocusableElement, + public LLSingleton +{ +public: + LLViewerMediaFocus(); + ~LLViewerMediaFocus(); + + static void cleanupClass(); + + void setFocusFace(BOOL b, LLPointer objectp, S32 face, viewer_media_t media_impl); + void clearFocus() { setFocusFace(false, NULL, 0, NULL); } + /*virtual*/ bool getFocus(); + /*virtual*/ // void onNavigateComplete( const EventType& event_in ); + + /*virtual*/ BOOL handleKey(KEY key, MASK mask, BOOL called_from_parent); + /*virtual*/ BOOL handleUnicodeChar(llwchar uni_char, BOOL called_from_parent); + BOOL handleScrollWheel(S32 x, S32 y, S32 clicks); + + LLUUID getSelectedUUID(); + LLObjectSelectionHandle getSelection() { return mFocus; } + + void update(); + + void setCameraZoom(F32 padding_factor); + void setMouseOverFlag(bool b, viewer_media_t media_impl = NULL); + bool getMouseOverFlag() { return mMouseOverFlag; } + void setPickInfo(LLPickInfo pick_info) { mPickInfo = pick_info; } + F32 getBBoxAspectRatio(const LLBBox& bbox, const LLVector3& normal, F32* height, F32* width, F32* depth); + +protected: + /*virtual*/ void onFocusReceived(); + /*virtual*/ void onFocusLost(); + +private: + LLObjectSelectionHandle mFocus; + std::string mLastURL; + bool mMouseOverFlag; + LLPickInfo mPickInfo; + LLHandle mMediaHUD; + LLUUID mObjectID; + viewer_media_t mMediaImpl; +}; + + +#endif // LL_VIEWERMEDIAFOCUS_H diff --git a/indra/newview/llviewermediaobserver.h b/indra/newview/llviewermediaobserver.h new file mode 100644 index 0000000000..6667f982b6 --- /dev/null +++ b/indra/newview/llviewermediaobserver.h @@ -0,0 +1,71 @@ +/** + * @file llviewermediaobserver.h + * @brief Methods to override to catch events from LLViewerMedia class + * + * $LicenseInfo:firstyear=2007&license=viewergpl$ + * + * Copyright (c) 2007-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLVIEWERMEDIAOBSERVER_H +#define LLVIEWERMEDIAOBSERVER_H + +#include "llpluginclassmediaowner.h" + +class LLViewerMediaEventEmitter; + +class LLViewerMediaObserver : public LLPluginClassMediaOwner +{ +public: + virtual ~LLViewerMediaObserver(); + +private: + // Emitters will manage this list in addObserver/remObserver. + friend class LLViewerMediaEventEmitter; + std::list mEmitters; +}; + + +#if 0 + // Classes that inherit from LLViewerMediaObserver should add this to their class declaration: + + // inherited from LLViewerMediaObserver + /*virtual*/ void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); + + /* and will probably need to add this to their cpp file: + + #include "llpluginclassmedia.h" + + */ + + // The list of events is in llpluginclassmediaowner.h + + +#endif + + +#endif // LLVIEWERMEDIAOBSERVER_H + diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index ac36cf7bb6..8a5928f4e9 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -40,10 +40,12 @@ #include // linden library includes -#include "audioengine.h" +#include "llaudioengine.h" +#include "llfloaterreg.h" #include "indra_constants.h" #include "llassetstorage.h" #include "llchat.h" +#include "llcombobox.h" #include "llfeaturemanager.h" #include "llfocusmgr.h" #include "llfontgl.h" @@ -64,7 +66,7 @@ // newview includes #include "llagent.h" - +#include "llagentwearables.h" #include "llagentpilot.h" #include "llbox.h" #include "llcallingcard.h" @@ -79,37 +81,31 @@ #include "lldrawpooltree.h" #include "llface.h" #include "llfirstuse.h" +#include "llfirsttimetipmanager.h" #include "llfloater.h" #include "llfloaterabout.h" #include "llfloaterbuycurrency.h" #include "llfloateractivespeakers.h" #include "llfloateranimpreview.h" -#include "llfloateravatarinfo.h" #include "llfloateravatartextures.h" -#include "llfloaterbeacons.h" #include "llfloaterbuildoptions.h" #include "llfloaterbump.h" #include "llfloaterbuy.h" #include "llfloaterbuycontents.h" #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" -#include "llfloatercamera.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterdaycycle.h" #include "llfloaterdirectory.h" -#include "llfloatereditui.h" #include "llfloaterchatterbox.h" -#include "llfloaterfriends.h" #include "llfloaterfonttest.h" #include "llfloatergesture.h" #include "llfloatergodtools.h" -#include "llfloatergroupinfo.h" #include "llfloatergroupinvite.h" #include "llfloatergroups.h" -#include "llfloaterhtml.h" #include "llfloaterhtmlcurrency.h" -#include "llfloaterhtmlhelp.h" // gViewerHtmlHelp +#include "llfloatermediabrowser.h" // gViewerHtmlHelp #include "llfloaterhtmlsimple.h" #include "llfloaterhud.h" #include "llfloaterinspect.h" @@ -119,25 +115,23 @@ #include "llfloatermap.h" #include "llfloatermute.h" #include "llfloateropenobject.h" -#include "llfloaterpermissionsmgr.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" +#include "llfloaterreg.h" #include "llfloaterregioninfo.h" #include "llfloaterreporter.h" #include "llfloaterscriptdebug.h" #include "llfloatersettingsdebug.h" #include "llfloaterenvsettings.h" -#include "llfloaterstats.h" -#include "llfloatertest.h" #include "llfloatertools.h" #include "llfloaterwater.h" #include "llfloaterwindlight.h" #include "llfloaterworldmap.h" #include "llfloatermemleak.h" -#include "llframestats.h" -#include "llframestatview.h" #include "llfasttimerview.h" +#include "llavataractions.h" +#include "lllandmarkactions.h" #include "llmemoryview.h" #include "llgivemoney.h" #include "llgroupmgr.h" @@ -148,12 +142,14 @@ #include "llimagebmp.h" #include "llimagej2c.h" #include "llimagetga.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llkeyboard.h" #include "llpanellogin.h" #include "llmenucommands.h" #include "llmenugl.h" +#include "llmimetypes.h" #include "llmorphview.h" #include "llmoveview.h" #include "llmutelist.h" @@ -162,7 +158,9 @@ #include "llparcel.h" #include "llprimitive.h" #include "llresmgr.h" +#include "llrootview.h" #include "llselectmgr.h" +#include "llsidetray.h" #include "llsky.h" #include "llstatusbar.h" #include "llstatview.h" @@ -177,17 +175,16 @@ #include "lltoolgrab.h" #include "lltoolmgr.h" #include "lltoolpie.h" -#include "lltoolplacer.h" #include "lltoolselectland.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "lluploaddialog.h" #include "lluserauth.h" #include "lluuid.h" -#include "llvelocitybar.h" #include "llviewercamera.h" #include "llviewergenericmessage.h" #include "llviewergesture.h" -#include "llviewerimagelist.h" // gImageList +#include "llviewertexturelist.h" // gTextureList #include "llviewerinventory.h" #include "llviewermenufile.h" // init_menu_file() #include "llviewermessage.h" @@ -199,6 +196,7 @@ #include "llviewerstats.h" #include "llviewerwindow.h" #include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvolume.h" #include "llweb.h" #include "llworld.h" @@ -216,17 +214,6 @@ #include "lltexlayer.h" using namespace LLVOAvatarDefines; -using namespace LLOldEvents; - -void init_client_menu(LLMenuGL* menu); -void init_server_menu(LLMenuGL* menu); - -void init_debug_world_menu(LLMenuGL* menu); -void init_debug_rendering_menu(LLMenuGL* menu); -void init_debug_ui_menu(LLMenuGL* menu); -void init_debug_xui_menu(LLMenuGL* menu); -void init_debug_avatar_menu(LLMenuGL* menu); -void init_debug_baked_texture_menu(LLMenuGL* menu); BOOL enable_land_build(void*); BOOL enable_object_build(void*); @@ -238,13 +225,14 @@ void handle_test_load_url(void*); // // Evil hackish imported globals -// -extern BOOL gRenderLightGlows; -extern BOOL gRenderAvatar; -extern BOOL gHideSelectedObjects; -extern BOOL gShowOverlayTitle; -extern BOOL gOcclusionCull; -extern BOOL gAllowSelectAvatar; + +//extern BOOL gHideSelectedObjects; +//extern BOOL gAllowSelectAvatar; +//extern BOOL gDebugAvatarRotation; +extern BOOL gDebugClicks; +extern BOOL gDebugWindowProc; +//extern BOOL gDebugTextEditorTips; +//extern BOOL gDebugSelectMgr; // // Globals @@ -256,15 +244,11 @@ LLMenuGL *gPopupMenuView = NULL; LLMenuBarGL *gLoginMenuBarView = NULL; // Pie menus -LLPieMenu *gPieSelf = NULL; -LLPieMenu *gPieAvatar = NULL; -LLPieMenu *gPieObject = NULL; -LLPieMenu *gPieAttachment = NULL; -LLPieMenu *gPieLand = NULL; - -// local constants -const std::string CLIENT_MENU_NAME("Advanced"); -const std::string SERVER_MENU_NAME("Admin"); +LLContextMenu *gPieSelf = NULL; +LLContextMenu *gPieAvatar = NULL; +LLContextMenu *gPieObject = NULL; +LLContextMenu *gPieAttachment = NULL; +LLContextMenu *gPieLand = NULL; const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory"); const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents"); @@ -272,27 +256,24 @@ const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents" LLMenuGL* gAttachSubMenu = NULL; LLMenuGL* gDetachSubMenu = NULL; LLMenuGL* gTakeOffClothes = NULL; -LLPieMenu* gPieRate = NULL; -LLPieMenu* gAttachScreenPieMenu = NULL; -LLPieMenu* gAttachPieMenu = NULL; -LLPieMenu* gAttachBodyPartPieMenus[8]; -LLPieMenu* gDetachPieMenu = NULL; -LLPieMenu* gDetachScreenPieMenu = NULL; -LLPieMenu* gDetachBodyPartPieMenus[8]; +LLContextMenu* gPieRate = NULL; +LLContextMenu* gAttachScreenPieMenu = NULL; +LLContextMenu* gAttachPieMenu = NULL; +LLContextMenu* gAttachBodyPartPieMenus[8]; +LLContextMenu* gDetachPieMenu = NULL; +LLContextMenu* gDetachScreenPieMenu = NULL; +LLContextMenu* gDetachBodyPartPieMenus[8]; LLMenuItemCallGL* gAFKMenu = NULL; LLMenuItemCallGL* gBusyMenu = NULL; -typedef LLMemberListener view_listener_t; - // // Local prototypes -// -void handle_leave_group(void *); // File Menu +const char* upload_pick(void* data); void handle_compress_image(void*); -BOOL enable_save_as(void *); + // Edit menu void handle_dump_group_info(void *); @@ -300,7 +281,6 @@ void handle_dump_capabilities_info(void *); void handle_dump_focus(void*); // Advanced->Consoles menu -void handle_show_notifications_console(void*); void handle_region_dump_settings(void*); void handle_region_dump_temp_asset_data(void*); void handle_region_clear_temp_asset_data(void*); @@ -309,7 +289,7 @@ void handle_region_clear_temp_asset_data(void*); BOOL sitting_on_selection(); void near_sit_object(); -void label_sit_or_stand(std::string& label, void*); +//void label_sit_or_stand(std::string& label, void*); // buy and take alias into the same UI positions, so these // declarations handle this mess. BOOL is_selection_buy_not_take(); @@ -321,51 +301,31 @@ BOOL enable_buy(void*); void handle_buy(void *); void handle_buy_object(LLSaleInfo sale_info); void handle_buy_contents(LLSaleInfo sale_info); -void label_touch(std::string& label, void*); // Land pie menu void near_sit_down_point(BOOL success, void *); // Avatar pie menu -void handle_follow(void *userdata); -void handle_talk_to(void *userdata); // Debug menu -void show_permissions_control(void*); -void toggle_build_options(void* user_data); -void reload_ui(void*); -void handle_agent_stop_moving(void*); -void print_packets_lost(void*); -void drop_packet(void*); -void velocity_interpolate( void* data ); -void toggle_wind_audio(void); -void toggle_water_audio(void); + + +void velocity_interpolate( void* ); + void handle_rebake_textures(void*); BOOL check_admin_override(void*); void handle_admin_override_toggle(void*); #ifdef TOGGLE_HACKED_GODLIKE_VIEWER void handle_toggle_hacked_godmode(void*); BOOL check_toggle_hacked_godmode(void*); +bool enable_toggle_hacked_godmode(void*); #endif -void toggle_glow(void *); -BOOL check_glow(void *); - -void toggle_vertex_shaders(void *); -BOOL check_vertex_shaders(void *); - -void toggle_cull_small(void *); - void toggle_show_xui_names(void *); BOOL check_show_xui_names(void *); -void run_vectorize_perf_test(void *) -{ - gSavedSettings.setBOOL("VectorizePerfTest", TRUE); -} - // Debug UI -void handle_web_search_demo(void*); + void handle_web_browser_test(void*); void handle_buy_currency_test(void*); void handle_save_to_xml(void*); @@ -376,16 +336,12 @@ void handle_god_mode(void*); // God menu void handle_leave_god_mode(void*); -BOOL is_inventory_visible( void* user_data ); + void handle_reset_view(); -void disabled_duplicate(void*); void handle_duplicate_in_place(void*); -void handle_repeat_duplicate(void*); -void handle_export(void*); -// void handle_deed_object_to_group(void*); -// BOOL enable_deed_object_to_group(void*); + void handle_object_owner_self(void*); void handle_object_owner_permissive(void*); void handle_object_lock(void*); @@ -400,11 +356,8 @@ void handle_force_parcel_owner_to_me(void*); void handle_force_parcel_to_content(void*); void handle_claim_public_land(void*); -void handle_god_request_havok(void *); void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry -void reload_personal_settings_overrides(void *); void reload_vertex_shader(void *); -void slow_mo_animations(void *); void handle_disconnect_viewer(void *); void force_error_breakpoint(void *); @@ -414,25 +367,13 @@ void force_error_infinite_loop(void *); void force_error_software_exception(void *); void force_error_driver_crash(void *); -void handle_stopall(void*); -//void handle_hinge(void*); -//void handle_ptop(void*); -//void handle_lptop(void*); -//void handle_wheel(void*); -//void handle_dehinge(void*); -BOOL enable_dehinge(void*); void handle_force_delete(void*); void print_object_info(void*); void print_agent_nvpairs(void*); void toggle_debug_menus(void*); -void export_info_callback(LLAssetInfo *info, void **user_data, S32 result); -void export_data_callback(LLVFS *vfs, const LLUUID& uuid, LLAssetType::EType type, void **user_data, S32 result); void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status); -BOOL menu_check_build_tool( void* user_data ); -void handle_reload_settings(void*); -void focus_here(void*); void dump_select_mgr(void*); -void dump_volume_mgr(void*); + void dump_inventory(void*); void edit_ui(void*); void toggle_visibility(void*); @@ -442,52 +383,30 @@ BOOL get_visibility(void*); void request_friendship(const LLUUID& agent_id); // Tools menu -void handle_force_unlock(void*); void handle_selected_texture_info(void*); -void handle_dump_image_list(void*); -void handle_crash(void*); void handle_dump_followcam(void*); void handle_viewer_enable_message_log(void*); void handle_viewer_disable_message_log(void*); -void handle_send_postcard(void*); -void handle_gestures_old(void*); -void handle_focus(void *); + BOOL enable_buy_land(void*); -void handle_move(void*); -void handle_show_inventory(void*); -void handle_activate(void*); -BOOL enable_activate(void*); // Help menu -void handle_buy_currency(void*); void handle_test_male(void *); void handle_test_female(void *); void handle_toggle_pg(void*); void handle_dump_attachments(void *); -void handle_show_overlay_title(void*); void handle_dump_avatar_local_textures(void*); void handle_debug_avatar_textures(void*); void handle_grab_texture(void*); BOOL enable_grab_texture(void*); void handle_dump_region_object_cache(void*); -BOOL menu_ui_enabled(void *user_data); -BOOL menu_check_control( void* user_data); -void menu_toggle_variable( void* user_data ); -BOOL menu_check_variable( void* user_data); -BOOL enable_land_selected( void* ); -BOOL enable_more_than_one_selected(void* ); -BOOL enable_selection_you_own_all(void*); -BOOL enable_selection_you_own_one(void*); BOOL enable_save_into_inventory(void*); BOOL enable_save_into_task_inventory(void*); -BOOL enable_not_thirdperson(void*); -// BOOL enable_export_selected(void *); -BOOL enable_have_card(void*); -BOOL enable_detach(void*); -BOOL enable_region_owner(void*); + +BOOL enable_detach(const LLSD& = LLSD()); void menu_toggle_attached_lights(void* user_data); void menu_toggle_attached_particles(void* user_data); @@ -521,27 +440,6 @@ void LLMenuParcelObserver::changed() } -//----------------------------------------------------------------------------- -// Menu Construction -//----------------------------------------------------------------------------- - -// code required to calculate anything about the menus -void pre_init_menus() -{ - // static information - LLColor4 color; - color = gColors.getColor( "MenuDefaultBgColor" ); - LLMenuGL::setDefaultBackgroundColor( color ); - color = gColors.getColor( "MenuItemEnabledColor" ); - LLMenuItemGL::setEnabledColor( color ); - color = gColors.getColor( "MenuItemDisabledColor" ); - LLMenuItemGL::setDisabledColor( color ); - color = gColors.getColor( "MenuItemHighlightBgColor" ); - LLMenuItemGL::setHighlightBGColor( color ); - color = gColors.getColor( "MenuItemHighlightFgColor" ); - LLMenuItemGL::setHighlightFGColor( color ); -} - void initialize_menus(); //----------------------------------------------------------------------------- @@ -560,13 +458,13 @@ void set_underclothes_menu_options() { if (gMenuHolder && gAgent.isTeen()) { - gMenuHolder->getChild("Self Underpants", TRUE)->setVisible(FALSE); - gMenuHolder->getChild("Self Undershirt", TRUE)->setVisible(FALSE); + gMenuHolder->getChild("Self Underpants")->setVisible(FALSE); + gMenuHolder->getChild("Self Undershirt")->setVisible(FALSE); } if (gMenuBarView && gAgent.isTeen()) { - gMenuBarView->getChild("Menu Underpants", TRUE)->setVisible(FALSE); - gMenuBarView->getChild("Menu Undershirt", TRUE)->setVisible(FALSE); + gMenuBarView->getChild("Menu Underpants")->setVisible(FALSE); + gMenuBarView->getChild("Menu Undershirt")->setVisible(FALSE); } } @@ -593,62 +491,63 @@ void init_menus() /// The popup menu is now populated by the show_context_menu() /// method. - gPopupMenuView = new LLMenuGL( "Popup" ); - gPopupMenuView->setVisible( FALSE ); + LLMenuGL::Params menu_params; + menu_params.name = "Popup"; + menu_params.visible = false; + gPopupMenuView = LLUICtrlFactory::create(menu_params); gMenuHolder->addChild( gPopupMenuView ); /// /// Pie menus /// - gPieSelf = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_self.xml", gMenuHolder); + gPieSelf = LLUICtrlFactory::getInstance()->createFromFile("menu_pie_self.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); // TomY TODO: what shall we do about these? - gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); - gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); + gDetachScreenPieMenu = gMenuHolder->getChild("Object Detach HUD", true); + gDetachPieMenu = gMenuHolder->getChild("Object Detach", true); - gPieAvatar = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_avatar.xml", gMenuHolder); + gPieAvatar = LLUICtrlFactory::getInstance()->createFromFile("menu_pie_avatar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gPieObject = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_object.xml", gMenuHolder); + gPieObject = LLUICtrlFactory::getInstance()->createFromFile("menu_pie_object.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); - gAttachPieMenu = gMenuHolder->getChild("Object Attach"); - gPieRate = gMenuHolder->getChild("Rate Menu"); + gAttachScreenPieMenu = gMenuHolder->getChild("Object Attach HUD"); + gAttachPieMenu = gMenuHolder->getChild("Object Attach"); + gPieRate = gMenuHolder->getChild("Rate Menu"); - gPieAttachment = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_attachment.xml", gMenuHolder); + gPieAttachment = LLUICtrlFactory::getInstance()->createFromFile("menu_pie_attachment.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); - gPieLand = LLUICtrlFactory::getInstance()->buildPieMenu("menu_pie_land.xml", gMenuHolder); + gPieLand = LLUICtrlFactory::getInstance()->createFromFile("menu_pie_land.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); /// /// set up the colors /// LLColor4 color; - LLColor4 pie_color = gColors.getColor("PieMenuBgColor"); - gPieSelf->setBackgroundColor( pie_color ); - gPieAvatar->setBackgroundColor( pie_color ); - gPieObject->setBackgroundColor( pie_color ); - gPieAttachment->setBackgroundColor( pie_color ); - gPieLand->setBackgroundColor( pie_color ); + LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor"); + + gPieSelf->setBackgroundColor( context_menu_color ); + gPieAvatar->setBackgroundColor( context_menu_color ); + gPieObject->setBackgroundColor( context_menu_color ); + gPieAttachment->setBackgroundColor( context_menu_color ); - color = gColors.getColor( "MenuPopupBgColor" ); + gPieLand->setBackgroundColor( context_menu_color ); + + color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" ); gPopupMenuView->setBackgroundColor( color ); // If we are not in production, use a different color to make it apparent. if (LLViewerLogin::getInstance()->isInProductionGrid()) { - color = gColors.getColor( "MenuBarBgColor" ); + color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); } else { - color = gColors.getColor( "MenuNonProductionBgColor" ); + color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); } - gMenuBarView = (LLMenuBarGL*)LLUICtrlFactory::getInstance()->buildMenu("menu_viewer.xml", gMenuHolder); + gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT)); gMenuBarView->setBackgroundColor( color ); - // gMenuBarView->setItemVisible("Tools", FALSE); - gMenuBarView->arrange(); - gMenuHolder->addChild(gMenuBarView); // menu holder appears on top of menu bar so you can see the menu title @@ -659,6 +558,7 @@ void init_menus() LLViewerLogin::getInstance()->isInProductionGrid()); // Assume L$10 for now, the server will tell us the real cost at login + // *TODO:Also fix cost in llfolderview.cpp for Inventory menus const std::string upload_cost("10"); gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost); gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost); @@ -667,820 +567,1828 @@ void init_menus() gAFKMenu = gMenuBarView->getChild("Set Away", TRUE); gBusyMenu = gMenuBarView->getChild("Set Busy", TRUE); - gAttachSubMenu = gMenuBarView->getChildMenuByName("Attach Object", TRUE); - gDetachSubMenu = gMenuBarView->getChildMenuByName("Detach Object", TRUE); - - // TomY TODO convert these two - LLMenuGL*menu; - - menu = new LLMenuGL(CLIENT_MENU_NAME); - init_client_menu(menu); - gMenuBarView->appendMenu( menu ); - menu->updateParent(LLMenuGL::sMenuContainer); - - menu = new LLMenuGL(SERVER_MENU_NAME); - init_server_menu(menu); - gMenuBarView->appendMenu( menu ); - menu->updateParent(LLMenuGL::sMenuContainer); + gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE); + gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE); gMenuBarView->createJumpKeys(); // Let land based option enable when parcel changes gMenuParcelObserver = new LLMenuParcelObserver(); - // - // Debug menu visiblity - // - show_debug_menus(); - - gLoginMenuBarView = (LLMenuBarGL*)LLUICtrlFactory::getInstance()->buildMenu("menu_login.xml", gMenuHolder); + gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance()); + gLoginMenuBarView->arrangeAndClear(); LLRect menuBarRect = gLoginMenuBarView->getRect(); gLoginMenuBarView->setRect(LLRect(menuBarRect.mLeft, menuBarRect.mTop, gViewerWindow->getRootView()->getRect().getWidth() - menuBarRect.mLeft, menuBarRect.mBottom)); - gLoginMenuBarView->setBackgroundColor( color ); - gMenuHolder->addChild(gLoginMenuBarView); } +/////////////////// +// SHOW CONSOLES // +/////////////////// -void init_client_menu(LLMenuGL* menu) +class LLAdvancedToggleConsole : public view_listener_t { - LLMenuGL* sub_menu = NULL; - - //menu->append(new LLMenuItemCallGL("Permissions Control", &show_permissions_control)); - // this is now in the view menu so we don't need it here! - + bool handleEvent(const LLSD& userdata) { - // *TODO: Translate - LLMenuGL* sub = new LLMenuGL("Consoles"); - menu->appendMenu(sub); - sub->append(new LLMenuItemCheckGL("Frame Console", - &toggle_visibility, - NULL, - &get_visibility, - (void*)gDebugView->mFrameStatView, - '2', MASK_CONTROL|MASK_SHIFT ) ); - sub->append(new LLMenuItemCheckGL("Texture Console", - &toggle_visibility, - NULL, - &get_visibility, - (void*)gTextureView, - '3', MASK_CONTROL|MASK_SHIFT ) ); - LLView* debugview = gDebugView->mDebugConsolep; - sub->append(new LLMenuItemCheckGL("Debug Console", - &toggle_visibility, - NULL, - &get_visibility, - debugview, - '4', MASK_CONTROL|MASK_SHIFT ) ); - - sub->append(new LLMenuItemCheckGL("Fast Timers", - &toggle_visibility, - NULL, - &get_visibility, - (void*)gDebugView->mFastTimerView, - '9', MASK_CONTROL|MASK_SHIFT ) ); + std::string console_type = userdata.asString(); + if ("texture" == console_type) + { + toggle_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + toggle_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); + } + else if ("fast timers" == console_type) + { + toggle_visibility( (void*)gDebugView->mFastTimerView ); + } #if MEM_TRACK_MEM - sub->append(new LLMenuItemCheckGL("Memory", - &toggle_visibility, - NULL, - &get_visibility, - (void*)gDebugView->mMemoryView, - '0', MASK_CONTROL|MASK_SHIFT ) ); + else if ("memory view" == console_type) + { + toggle_visibility( (void*)gDebugView->mMemoryView ); + } #endif - - sub->appendSeparator(); - - // Debugging view for unified notifications - sub->append(new LLMenuItemCallGL("Notifications Console...", - &handle_show_notifications_console, NULL, NULL, '5', MASK_CONTROL|MASK_SHIFT )); - - - sub->appendSeparator(); - - sub->append(new LLMenuItemCallGL("Region Info to Debug Console", - &handle_region_dump_settings, NULL)); - sub->append(new LLMenuItemCallGL("Group Info to Debug Console", - &handle_dump_group_info, NULL, NULL)); - sub->append(new LLMenuItemCallGL("Capabilities Info to Debug Console", - &handle_dump_capabilities_info, NULL, NULL)); - sub->createJumpKeys(); + return true; } - - // neither of these works particularly well at the moment - /*menu->append(new LLMenuItemCallGL( "Reload UI XML", &reload_ui, - NULL, NULL) );*/ - /*menu->append(new LLMenuItemCallGL("Reload settings/colors", - &handle_reload_settings, NULL, NULL));*/ - menu->append(new LLMenuItemCallGL("Reload personal setting overrides", - &reload_personal_settings_overrides, NULL, NULL, KEY_F12, MASK_CONTROL|MASK_SHIFT)); - - sub_menu = new LLMenuGL("HUD Info"); +}; +class LLAdvancedCheckConsole : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) { - sub_menu->append(new LLMenuItemCheckGL("Velocity", - &toggle_visibility, - NULL, - &get_visibility, - (void*)gVelocityBar)); + std::string console_type = userdata.asString(); + bool new_value = false; + if ("texture" == console_type) + { + new_value = get_visibility( (void*)gTextureView ); + } + else if ("debug" == console_type) + { + new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) ); + } + else if ("fast timers" == console_type) + { + new_value = get_visibility( (void*)gDebugView->mFastTimerView ); + } +#if MEM_TRACK_MEM + else if ("memory view" == console_type) + { + new_value = get_visibility( (void*)gDebugView->mMemoryView ); + } +#endif - sub_menu->append(new LLMenuItemToggleGL("Camera", &gDisplayCameraPos ) ); - sub_menu->append(new LLMenuItemToggleGL("Wind", &gDisplayWindInfo) ); - sub_menu->append(new LLMenuItemToggleGL("FOV", &gDisplayFOV ) ); - sub_menu->createJumpKeys(); + return new_value; } - menu->appendMenu(sub_menu); +}; - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL( "High-res Snapshot", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"HighResSnapshot")); +////////////////////////// +// DUMP INFO TO CONSOLE // +////////////////////////// + + +class LLAdvancedDumpInfoToConsole : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + if ("region" == info_type) + { + handle_region_dump_settings(NULL); + } + else if ("group" == info_type) + { + handle_dump_group_info(NULL); + } + else if ("capabilities" == info_type) + { + handle_dump_capabilities_info(NULL); + } + return true; + } +}; + + +////////////// +// HUD INFO // +////////////// + + +class LLAdvancedToggleHUDInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + + if ("camera" == info_type) + { + gDisplayCameraPos = !(gDisplayCameraPos); + } + else if ("wind" == info_type) + { + gDisplayWindInfo = !(gDisplayWindInfo); + } + else if ("fov" == info_type) + { + gDisplayFOV = !(gDisplayFOV); + } + return true; + } +}; + +class LLAdvancedCheckHUDInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string info_type = userdata.asString(); + bool new_value = false; + if ("camera" == info_type) + { + new_value = gDisplayCameraPos; + } + else if ("wind" == info_type) + { + new_value = gDisplayWindInfo; + } + else if ("fov" == info_type) + { + new_value = gDisplayFOV; + } + return new_value; + } +}; + +/////////////////////// +// CLEAR GROUP CACHE // +/////////////////////// + +class LLAdvancedClearGroupCache : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLGroupMgr::debugClearAllGroups(NULL); + return true; + } +}; + + + + +///////////////// +// RENDER TYPE // +///////////////// +U32 render_type_from_string(std::string render_type) +{ + if ("simple" == render_type) + { + return LLPipeline::RENDER_TYPE_SIMPLE; + } + else if ("alpha" == render_type) + { + return LLPipeline::RENDER_TYPE_ALPHA; + } + else if ("tree" == render_type) + { + return LLPipeline::RENDER_TYPE_TREE; + } + else if ("character" == render_type) + { + return LLPipeline::RENDER_TYPE_AVATAR; + } + else if ("surfacePath" == render_type) + { + return LLPipeline::RENDER_TYPE_TERRAIN; + } + else if ("sky" == render_type) + { + return LLPipeline::RENDER_TYPE_SKY; + } + else if ("water" == render_type) + { + return LLPipeline::RENDER_TYPE_WATER; + } + else if ("ground" == render_type) + { + return LLPipeline::RENDER_TYPE_GROUND; + } + else if ("volume" == render_type) + { + return LLPipeline::RENDER_TYPE_VOLUME; + } + else if ("grass" == render_type) + { + return LLPipeline::RENDER_TYPE_GRASS; + } + else if ("clouds" == render_type) + { + return LLPipeline::RENDER_TYPE_CLOUDS; + } + else if ("particles" == render_type) + { + return LLPipeline::RENDER_TYPE_PARTICLES; + } + else if ("bump" == render_type) + { + return LLPipeline::RENDER_TYPE_BUMP; + } + else + { + return 0; + } +} + + +class LLAdvancedToggleRenderType : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + if ( render_type != 0 ) + { + LLPipeline::toggleRenderTypeControl( (void*)render_type ); + } + return true; + } +}; + + +class LLAdvancedCheckRenderType : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U32 render_type = render_type_from_string( userdata.asString() ); + bool new_value = false; + + if ( render_type != 0 ) + { + new_value = LLPipeline::hasRenderTypeControl( (void*)render_type ); + } + + return new_value; + } +}; + + +///////////// +// FEATURE // +///////////// +U32 feature_from_string(std::string feature) +{ + if ("ui" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_UI; + } + else if ("selected" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED; + } + else if ("highlighted" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED; + } + else if ("dynamic textures" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES; + } + else if ("foot shadows" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS; + } + else if ("fog" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FOG; + } + else if ("fr info" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO; + } + else if ("flexible" == feature) + { + return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE; + } + else + { + return 0; + } +}; + + +class LLAdvancedToggleFeature : public view_listener_t{ + bool handleEvent(const LLSD& userdata) + { + U32 feature = feature_from_string( userdata.asString() ); + if ( feature != 0 ) + { + LLPipeline::toggleRenderDebugFeature( (void*)feature ); + } + return true; + } +}; + +class LLAdvancedCheckFeature : public view_listener_t +{bool handleEvent(const LLSD& userdata) +{ + U32 feature = feature_from_string( userdata.asString() ); + bool new_value = false; + + if ( feature != 0 ) + { + new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature ); + } + + return new_value; +} +}; + + +////////////////// +// INFO DISPLAY // +////////////////// +U32 info_display_from_string(std::string info_display) +{ + if ("verify" == info_display) + { + return LLPipeline::RENDER_DEBUG_VERIFY; + } + else if ("bboxes" == info_display) + { + return LLPipeline::RENDER_DEBUG_BBOXES; + } + else if ("points" == info_display) + { + return LLPipeline::RENDER_DEBUG_POINTS; + } + else if ("octree" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCTREE; + } + else if ("shadow frusta" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA; + } + else if ("occlusion" == info_display) + { + return LLPipeline::RENDER_DEBUG_OCCLUSION; + } + else if ("render batches" == info_display) + { + return LLPipeline::RENDER_DEBUG_BATCH_SIZE; + } + else if ("texture anim" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM; + } + else if ("texture priority" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY; + } + else if ("shame" == info_display) + { + return LLPipeline::RENDER_DEBUG_SHAME; + } + else if ("texture area" == info_display) + { + return LLPipeline::RENDER_DEBUG_TEXTURE_AREA; + } + else if ("face area" == info_display) + { + return LLPipeline::RENDER_DEBUG_FACE_AREA; + } + else if ("lights" == info_display) + { + return LLPipeline::RENDER_DEBUG_LIGHTS; + } + else if ("particles" == info_display) + { + return LLPipeline::RENDER_DEBUG_PARTICLES; + } + else if ("composition" == info_display) + { + return LLPipeline::RENDER_DEBUG_COMPOSITION; + } + else if ("glow" == info_display) + { + return LLPipeline::RENDER_DEBUG_GLOW; + } + else if ("collision skeleton" == info_display) + { + return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME; + } + else if ("agent target" == info_display) + { + return LLPipeline::RENDER_DEBUG_AGENT_TARGET; + } + else + { + return 0; + } +}; + +class LLAdvancedToggleInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U32 info_display = info_display_from_string( userdata.asString() ); + + if ( info_display != 0 ) + { + LLPipeline::toggleRenderDebug( (void*)info_display ); + } + + return true; + } +}; + + +class LLAdvancedCheckInfoDisplay : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + U32 info_display = info_display_from_string( userdata.asString() ); + bool new_value = false; + + if ( info_display != 0 ) + { + new_value = LLPipeline::toggleRenderDebugControl( (void*)info_display ); + } + + return new_value; + } +}; + + +/////////////////////////// +//// RANDOMIZE FRAMERATE // +/////////////////////////// + + +class LLAdvancedToggleRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gRandomizeFramerate = !(gRandomizeFramerate); + return true; + } +}; + +class LLAdvancedCheckRandomizeFramerate : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gRandomizeFramerate; + return new_value; + } +}; + +void run_vectorize_perf_test(void *) +{ + gSavedSettings.setBOOL("VectorizePerfTest", TRUE); +} + + +//////////////////////////////// +// RUN Vectorized Perform Test// +//////////////////////////////// + + +class LLAdvancedVectorizePerfTest : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + run_vectorize_perf_test(NULL); + return true; + } +}; + +/////////////////////////// +//// PERIODIC SLOW FRAME // +/////////////////////////// + + +class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gPeriodicSlowFrame = !(gPeriodicSlowFrame); + return true; + } +}; + +class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gPeriodicSlowFrame; + return new_value; + } +}; + + + +//////////////// +// FRAME TEST // +//////////////// + + +class LLAdvancedToggleFrameTest : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLPipeline::sRenderFrameTest = !(LLPipeline::sRenderFrameTest); + return true; + } +}; + +class LLAdvancedCheckFrameTest : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLPipeline::sRenderFrameTest; + return new_value; + } +}; + + +/////////////////////////// +// SELECTED TEXTURE INFO // +/////////////////////////// + + +class LLAdvancedSelectedTextureInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_selected_texture_info(NULL); + return true; + } +}; + +////////////////////// +// TOGGLE WIREFRAME // +////////////////////// + +class LLAdvancedToggleWireframe : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gUseWireframe = !(gUseWireframe); + return true; + } +}; + +class LLAdvancedCheckWireframe : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gUseWireframe; + return new_value; + } +}; - menu->append(new LLMenuItemCheckGL( "Quiet Snapshots to Disk", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"QuietSnapshotsToDisk")); +////////////////////// +// DISABLE TEXTURES // +////////////////////// - menu->append(new LLMenuItemCheckGL("Show Mouselook Crosshairs", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"ShowCrosshairs")); +class LLAdvancedToggleDisableTextures : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerTexture::sDontLoadVolumeTextures = !LLViewerTexture::sDontLoadVolumeTextures; + return true; + } +}; - menu->append(new LLMenuItemCheckGL("Debug Permissions", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"DebugPermissions")); +class LLAdvancedCheckDisableTextures : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerTexture::sDontLoadVolumeTextures; // <-- make this using LLCacheControl + return new_value; + } +}; + +////////////////////////// +// DUMP SCRIPTED CAMERA // +////////////////////////// +class LLAdvancedDumpScriptedCamera : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_dump_followcam(NULL); + return true; +} +}; + + + +////////////////////////////// +// DUMP REGION OBJECT CACHE // +////////////////////////////// + + +class LLAdvancedDumpRegionObjectCache : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) +{ + handle_dump_region_object_cache(NULL); + return true; + } +}; + +class LLAdvancedWebBrowserTest : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_web_browser_test(NULL); + return true; + } +}; + +class LLAdvancedBuyCurrencyTest : public view_listener_t + { + bool handleEvent(const LLSD& userdata) + { + handle_buy_currency_test(NULL); + return true; + } +}; + + +//////////////////////// +// TOGGLE EDITABLE UI // +//////////////////////// + + +class LLAdvancedToggleEditableUI : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + edit_ui(NULL); + return true; + } +}; + + +///////////////////// +// DUMP SELECT MGR // +///////////////////// + + +class LLAdvancedDumpSelectMgr : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + dump_select_mgr(NULL); + return true; + } +}; + + + +//////////////////// +// DUMP INVENTORY // +//////////////////// + + +class LLAdvancedDumpInventory : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + dump_inventory(NULL); + return true; + } +}; + + + +/////////////////////// +// DUMP FOCUS HOLDER // +/////////////////////// + + +class LLAdvancedDumpFocusHolder : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_dump_focus(NULL); + return true; + } +}; + + + +//////////////////////////////// +// PRINT SELECTED OBJECT INFO // +//////////////////////////////// + + +class LLAdvancedPrintSelectedObjectInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + print_object_info(NULL); + return true; + } +}; + + + +////////////////////// +// PRINT AGENT INFO // +////////////////////// + + +class LLAdvancedPrintAgentInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + print_agent_nvpairs(NULL); + return true; + } +}; + + + +//////////////////////////////// +// PRINT TEXTURE MEMORY STATS // +//////////////////////////////// + + +class LLAdvancedPrintTextureMemoryStats : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + output_statistics(NULL); + return true; + } +}; + +////////////////// +// DEBUG CLICKS // +////////////////// + + +class LLAdvancedToggleDebugClicks : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gDebugClicks = !(gDebugClicks); + return true; + } +}; + +class LLAdvancedCheckDebugClicks : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugClicks; + return new_value; + } +}; + + + +///////////////// +// DEBUG VIEWS // +///////////////// + + +class LLAdvancedToggleDebugViews : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugRects = !(LLView::sDebugRects); + return true; + } +}; + +class LLAdvancedCheckDebugViews : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugRects; + return new_value; + } +}; + + + +/////////////////////// +// XUI NAME TOOLTIPS // +/////////////////////// + + +class LLAdvancedToggleXUINameTooltips : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } +}; + +class LLAdvancedCheckXUINameTooltips : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } +}; + + + +//////////////////////// +// DEBUG MOUSE EVENTS // +//////////////////////// + + +class LLAdvancedToggleDebugMouseEvents : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling); + return true; + } +}; + +class LLAdvancedCheckDebugMouseEvents : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugMouseHandling; + return new_value; + } +}; + + + +//////////////// +// DEBUG KEYS // +//////////////// + + +class LLAdvancedToggleDebugKeys : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLView::sDebugKeys = !(LLView::sDebugKeys); + return true; + } +}; + +class LLAdvancedCheckDebugKeys : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLView::sDebugKeys; + return new_value; + } +}; + + + +/////////////////////// +// DEBUG WINDOW PROC // +/////////////////////// + + +class LLAdvancedToggleDebugWindowProc : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gDebugWindowProc = !(gDebugWindowProc); + return true; + } +}; + +class LLAdvancedCheckDebugWindowProc : public view_listener_t + { + bool handleEvent(const LLSD& userdata) + { + bool new_value = gDebugWindowProc; + return new_value; + } +}; + +// ------------------------------XUI MENU --------------------------- + +////////////////////// +// LOAD UI FROM XML // +////////////////////// + + +class LLAdvancedLoadUIFromXML : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_load_from_xml(NULL); + return true; +} +}; + + + +//////////////////// +// SAVE UI TO XML // +//////////////////// + + +class LLAdvancedSaveUIToXML : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_save_to_xml(NULL); + return true; +} +}; + + +class LLAdvancedSendTestIms : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLIMModel::instance().testMessages(); + return true; +} +}; + +class LLAdvancedAvatarInspector : public view_listener_t +{ + bool handleEvent(const LLSD& avatar_id) + { + LLFloaterReg::showInstance("inspect_avatar", avatar_id); + return true; + } +}; + +/////////////// +// XUI NAMES // +/////////////// + + +class LLAdvancedToggleXUINames : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + toggle_show_xui_names(NULL); + return true; + } +}; + +class LLAdvancedCheckXUINames : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_show_xui_names(NULL); + return new_value; + } +}; + + +//////////////////////// +// GRAB BAKED TEXTURE // +//////////////////////// + + +class LLAdvancedGrabBakedTexture : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string texture_type = userdata.asString(); + if ("iris" == texture_type) + { + handle_grab_texture( (void*)TEX_EYES_BAKED ); + } + else if ("head" == texture_type) + { + handle_grab_texture( (void*)TEX_HEAD_BAKED ); + } + else if ("upper" == texture_type) + { + handle_grab_texture( (void*)TEX_UPPER_BAKED ); + } + else if ("lower" == texture_type) + { + handle_grab_texture( (void*)TEX_SKIRT_BAKED ); + } + else if ("skirt" == texture_type) + { + handle_grab_texture( (void*)TEX_SKIRT_BAKED ); + } + else if ("hair" == texture_type) + { + handle_grab_texture( (void*)TEX_HAIR_BAKED ); +} + + return true; + } +}; + +class LLAdvancedEnableGrabBakedTexture : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) +{ + std::string texture_type = userdata.asString(); + bool new_value = false; + + if ("iris" == texture_type) + { + new_value = enable_grab_texture( (void*)TEX_EYES_BAKED ); + } + else if ("head" == texture_type) + { + new_value = enable_grab_texture( (void*)TEX_HEAD_BAKED ); + } + else if ("upper" == texture_type) + { + new_value = enable_grab_texture( (void*)TEX_UPPER_BAKED ); + } + else if ("lower" == texture_type) + { + new_value = enable_grab_texture( (void*)TEX_LOWER_BAKED ); + } + else if ("skirt" == texture_type) + { + new_value = enable_grab_texture( (void*)TEX_SKIRT_BAKED ); + } + + return new_value; +} +}; + +/////////////////////// +// APPEARANCE TO XML // +/////////////////////// + + +class LLAdvancedAppearanceToXML : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::dumpArchetypeXML(NULL); + return true; + } +}; + + + +/////////////////////////////// +// TOGGLE CHARACTER GEOMETRY // +/////////////////////////////// + + +class LLAdvancedToggleCharacterGeometry : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_god_request_avatar_geometry(NULL); + return true; +} +}; + +class LLEnableGodCustomerService : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) +{ + bool new_value = enable_god_customer_service(NULL); + return new_value; + } +}; + + + + ///////////////////////////// +// TEST MALE / TEST FEMALE // +///////////////////////////// + +class LLAdvancedTestMale : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_test_male(NULL); + return true; + } +}; + + +class LLAdvancedTestFemale : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_test_female(NULL); + return true; + } +}; + + + +/////////////// +// TOGGLE PG // +/////////////// + + +class LLAdvancedTogglePG : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_toggle_pg(NULL); + return true; + } +}; + + + +//////////////////////////// +// ALLOW TAP-TAP-HOLD RUN // +//////////////////////////// + + +class LLAdvancedToggleAllowTapTapHoldRun : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gAllowTapTapHoldRun = !(gAllowTapTapHoldRun); + return true; + } +}; + +class LLAdvancedCheckAllowTapTapHoldRun : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gAllowTapTapHoldRun; + return new_value; + } +}; + + + + + +class LLAdvancedForceParamsToDefault : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLAgent::clearVisualParams(NULL); + return true; + } +}; + + + +////////////////////////// +// RELOAD VERTEX SHADER // +////////////////////////// + + +class LLAdvancedReloadVertexShader : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + reload_vertex_shader(NULL); + return true; + } +}; + + + +//////////////////// +// ANIMATION INFO // +//////////////////// + + +class LLAdvancedToggleAnimationInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug); + return true; + } +}; + +class LLAdvancedCheckAnimationInfo : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sShowAnimationDebug; + return new_value; + } +}; + + +////////////////// +// SHOW LOOK AT // +////////////////// + + +class LLAdvancedToggleShowLookAt : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt); + return true; + } +}; + +class LLAdvancedCheckShowLookAt : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectLookAt::sDebugLookAt; + return new_value; + } +}; + + + +/////////////////// +// SHOW POINT AT // +/////////////////// + + +class LLAdvancedToggleShowPointAt : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt); + return true; + } +}; + +class LLAdvancedCheckShowPointAt : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLHUDEffectPointAt::sDebugPointAt; + return new_value; + } +}; + + + +///////////////////////// +// DEBUG JOINT UPDATES // +///////////////////////// + + +class LLAdvancedToggleDebugJointUpdates : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug); + return true; + } +}; + +class LLAdvancedCheckDebugJointUpdates : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sJointDebug; + return new_value; + } +}; + + + +///////////////// +// DISABLE LOD // +///////////////// + + +class LLAdvancedToggleDisableLOD : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD); + return true; + } +}; + +class LLAdvancedCheckDisableLOD : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoint::sDisableLOD; + return new_value; + } +}; + + + +///////////////////////// +// DEBUG CHARACTER VIS // +///////////////////////// + + +class LLAdvancedToggleDebugCharacterVis : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible); + return true; + } +}; + +class LLAdvancedCheckDebugCharacterVis : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLVOAvatar::sDebugInvisible; + return new_value; + } +}; + + +////////////////////// +// DUMP ATTACHMENTS // +////////////////////// + + +class LLAdvancedDumpAttachments : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_dump_attachments(NULL); + return true; + } +}; + + + +///////////////////// +// REBAKE TEXTURES // +///////////////////// + + +class LLAdvancedRebakeTextures : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_rebake_textures(NULL); + return true; + } +}; + + +#ifndef LL_RELEASE_FOR_DOWNLOAD +/////////////////////////// +// DEBUG AVATAR TEXTURES // +/////////////////////////// + + +class LLAdvancedDebugAvatarTextures : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_debug_avatar_textures(NULL); + return true; + } +}; + +//////////////////////////////// +// DUMP AVATAR LOCAL TEXTURES // +//////////////////////////////// + + +class LLAdvancedDumpAvatarLocalTextures : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_dump_avatar_local_textures(NULL); + return true; + } +}; + +#endif + +///////////////// +// MESSAGE LOG // +///////////////// + + +class LLAdvancedEnableMessageLog : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_viewer_enable_message_log(NULL); + return true; + } +}; + +class LLAdvancedDisableMessageLog : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_viewer_disable_message_log(NULL); + return true; + } +}; + +///////////////// +// DROP PACKET // +///////////////// + + +class LLAdvancedDropPacket : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gMessageSystem->mPacketRing.dropPackets(1); + return true; + } +}; + + + +///////////////// +// AGENT PILOT // +///////////////// + + +class LLAdvancedAgentPilot : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string command = userdata.asString(); + if ("start playback" == command) + { + LLAgentPilot::startPlayback(NULL); + } + else if ("stop playback" == command) + { + LLAgentPilot::stopPlayback(NULL); + } + else if ("start record" == command) + { + LLAgentPilot::startRecord(NULL); + } + else if ("stop record" == command) + { + LLAgentPilot::saveRecord(NULL); + } + + return true; + } +}; + + + +////////////////////// +// AGENT PILOT LOOP // +////////////////////// + + +class LLAdvancedToggleAgentPilotLoop : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLAgentPilot::sLoop = !(LLAgentPilot::sLoop); + return true; + } +}; + +class LLAdvancedCheckAgentPilotLoop : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLAgentPilot::sLoop; + return new_value; + } +}; + + +///////////////////////// +// SHOW OBJECT UPDATES // +///////////////////////// + + +class LLAdvancedToggleShowObjectUpdates : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + gShowObjectUpdates = !(gShowObjectUpdates); + return true; + } +}; + +class LLAdvancedCheckShowObjectUpdates : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = gShowObjectUpdates; + return new_value; + } +}; + + + +//////////////////// +// COMPRESS IMAGE // +//////////////////// + + +class LLAdvancedCompressImage : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_compress_image(NULL); + return true; + } +}; + + + +///////////////////////// +// SHOW DEBUG SETTINGS // +///////////////////////// + + +class LLAdvancedShowDebugSettings : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFloaterReg::showInstance("settings_debug",userdata); + return true; + } +}; + + + +//////////////////////// +// VIEW ADMIN OPTIONS // +//////////////////////// + + +class LLAdvancedToggleViewAdminOptions : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_admin_override_toggle(NULL); + return true; + } +}; + +class LLAdvancedCheckViewAdminOptions : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = check_admin_override(NULL); + return new_value; + } +}; + +///////////////////////////////////// +// Enable Object Object Occlusion /// +///////////////////////////////////// +class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + + bool new_value = gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString()); + return new_value; +} +}; + + + +////////////////// +// ADMIN STATUS // +////////////////// + + +class LLAdvancedRequestAdminStatus : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_god_mode(NULL); + return true; + } +}; + +class LLAdvancedLeaveAdminStatus : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_leave_god_mode(NULL); + return true; + } +}; + +////////////////////////// +// Advanced > Debugging // +////////////////////////// + + +class LLAdvancedForceErrorBreakpoint : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_breakpoint(NULL); + return true; + } +}; + +class LLAdvancedForceErrorLlerror : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_llerror(NULL); + return true; + } +}; +class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_bad_memory_access(NULL); + return true; + } +}; + +class LLAdvancedForceErrorInfiniteLoop : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_infinite_loop(NULL); + return true; + } +}; + +class LLAdvancedForceErrorSoftwareException : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_software_exception(NULL); + return true; + } +}; + +class LLAdvancedForceErrorDriverCrash : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + force_error_driver_crash(NULL); + return true; + } +}; + +class LLAdvancedForceErrorDisconnectViewer : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_disconnect_viewer(NULL); + return true; +} +}; #ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (!LLViewerLogin::getInstance()->isInProductionGrid()) + +class LLAdvancedHandleToggleHackedGodmode : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) { - menu->append(new LLMenuItemCheckGL("Hacked Godmode", - &handle_toggle_hacked_godmode, - NULL, - &check_toggle_hacked_godmode, - (void*)"HackedGodmode")); + handle_toggle_hacked_godmode(NULL); + return true; } +}; + +class LLAdvancedCheckToggleHackedGodmode : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + check_toggle_hacked_godmode(NULL); + return true; + } +}; + +class LLAdvancedEnableToggleHackedGodmode : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_toggle_hacked_godmode(NULL); + return new_value; + } +}; #endif - menu->append(new LLMenuItemCallGL("Clear Group Cache", - LLGroupMgr::debugClearAllGroups)); - menu->appendSeparator(); - sub_menu = new LLMenuGL("Rendering"); - init_debug_rendering_menu(sub_menu); - menu->appendMenu(sub_menu); +// +////------------------------------------------------------------------- +//// Advanced menu +////------------------------------------------------------------------- - sub_menu = new LLMenuGL("World"); - init_debug_world_menu(sub_menu); - menu->appendMenu(sub_menu); - - sub_menu = new LLMenuGL("UI"); - init_debug_ui_menu(sub_menu); - menu->appendMenu(sub_menu); - - sub_menu = new LLMenuGL("XUI"); - init_debug_xui_menu(sub_menu); - menu->appendMenu(sub_menu); - - sub_menu = new LLMenuGL("Character"); - init_debug_avatar_menu(sub_menu); - menu->appendMenu(sub_menu); +////////////////// +// ADMIN MENU // +////////////////// +// Admin > Object +class LLAdminForceTakeCopy : public view_listener_t { - LLMenuGL* sub = NULL; - sub = new LLMenuGL("Network"); - - sub->append(new LLMenuItemCallGL("Enable Message Log", - &handle_viewer_enable_message_log, NULL)); - sub->append(new LLMenuItemCallGL("Disable Message Log", - &handle_viewer_disable_message_log, NULL)); - - sub->appendSeparator(); - - sub->append(new LLMenuItemCheckGL("Velocity Interpolate Objects", - &velocity_interpolate, - NULL, - &menu_check_control, - (void*)"VelocityInterpolate")); - sub->append(new LLMenuItemCheckGL("Ping Interpolate Object Positions", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"PingInterpolate")); - - sub->appendSeparator(); - - sub->append(new LLMenuItemCallGL("Drop a Packet", - &drop_packet, NULL, NULL, - 'L', MASK_ALT | MASK_CONTROL)); - - menu->appendMenu( sub ); - sub->createJumpKeys(); - } + bool handleEvent(const LLSD& userdata) { - LLMenuGL* sub = NULL; - sub = new LLMenuGL("Recorder"); - - sub->append(new LLMenuItemCheckGL("Full Session Logging", &menu_toggle_control, NULL, &menu_check_control, (void*)"StatsSessionTrackFrameStats")); - - sub->append(new LLMenuItemCallGL("Start Logging", &LLFrameStats::startLogging, NULL)); - sub->append(new LLMenuItemCallGL("Stop Logging", &LLFrameStats::stopLogging, NULL)); - sub->append(new LLMenuItemCallGL("Log 10 Seconds", &LLFrameStats::timedLogging10, NULL)); - sub->append(new LLMenuItemCallGL("Log 30 Seconds", &LLFrameStats::timedLogging30, NULL)); - sub->append(new LLMenuItemCallGL("Log 60 Seconds", &LLFrameStats::timedLogging60, NULL)); - sub->appendSeparator(); - sub->append(new LLMenuItemCallGL("Start Playback", &LLAgentPilot::startPlayback, NULL)); - sub->append(new LLMenuItemCallGL("Stop Playback", &LLAgentPilot::stopPlayback, NULL)); - sub->append(new LLMenuItemToggleGL("Loop Playback", &LLAgentPilot::sLoop) ); - sub->append(new LLMenuItemCallGL("Start Record", &LLAgentPilot::startRecord, NULL)); - sub->append(new LLMenuItemCallGL("Stop Record", &LLAgentPilot::saveRecord, NULL)); - - menu->appendMenu( sub ); - sub->createJumpKeys(); + force_take_copy(NULL); + return true; } +}; - menu->appendSeparator(); - - menu->append(new LLMenuItemToggleGL("Show Updates", - &gShowObjectUpdates)); - - menu->appendSeparator(); - - menu->append(new LLMenuItemCallGL("Compress Images...", - &handle_compress_image, NULL, NULL)); - - menu->append(new LLMenuItemCheckGL("Limit Select Distance", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"LimitSelectDistance")); - - menu->append(new LLMenuItemCheckGL("Disable Camera Constraints", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"DisableCameraConstraints")); - - menu->append(new LLMenuItemCheckGL("Mouse Smoothing", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*) "MouseSmooth")); - menu->appendSeparator(); - - menu->append(new LLMenuItemCheckGL( "Console Window", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"ShowConsoleWindow")); - - if(gSavedSettings.getBOOL("QAMode")) +class LLAdminHandleObjectOwnerSelf : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) { - LLMenuGL* sub = NULL; - sub = new LLMenuGL("Debugging"); -#if LL_WINDOWS - sub->append(new LLMenuItemCallGL("Force Breakpoint", &force_error_breakpoint, NULL, NULL, 'B', MASK_CONTROL | MASK_ALT)); -#endif - sub->append(new LLMenuItemCallGL("Force LLError And Crash", &force_error_llerror)); - sub->append(new LLMenuItemCallGL("Force Bad Memory Access", &force_error_bad_memory_access)); - sub->append(new LLMenuItemCallGL("Force Infinite Loop", &force_error_infinite_loop)); - sub->append(new LLMenuItemCallGL("Force Driver Crash", &force_error_driver_crash)); - sub->append(new LLMenuItemCallGL("Force Disconnect Viewer", &handle_disconnect_viewer)); - // *NOTE:Mani this isn't handled yet... sub->append(new LLMenuItemCallGL("Force Software Exception", &force_error_unhandled_exception)); - sub->createJumpKeys(); - menu->appendMenu(sub); + handle_object_owner_self(NULL); + return true; } - - menu->append(new LLMenuItemCheckGL( "Output Debug Minidump", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"SaveMinidump")); - - menu->append(new LLMenuItemCallGL("Debug Settings...", LLFloaterSettingsDebug::show, NULL, NULL)); - menu->append(new LLMenuItemCheckGL("View Admin Options", &handle_admin_override_toggle, NULL, &check_admin_override, NULL, 'V', MASK_CONTROL | MASK_ALT)); - - menu->append(new LLMenuItemCallGL("Request Admin Status", - &handle_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_CONTROL)); - - menu->append(new LLMenuItemCallGL("Leave Admin Status", - &handle_leave_god_mode, NULL, NULL, 'G', MASK_ALT | MASK_SHIFT | MASK_CONTROL)); - - menu->createJumpKeys(); -} - -void init_debug_world_menu(LLMenuGL* menu) +}; +class LLAdminHandleObjectOwnerPermissive : public view_listener_t { -/* REMOVE mouse move sun from menu options - menu->append(new LLMenuItemCheckGL("Mouse Moves Sun", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"MouseSun", - 'M', MASK_CONTROL|MASK_ALT)); -*/ - menu->append(new LLMenuItemCheckGL("Sim Sun Override", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"SkyOverrideSimSunPosition")); - menu->append(new LLMenuItemCallGL("Dump Scripted Camera", - &handle_dump_followcam, NULL, NULL)); - menu->append(new LLMenuItemCheckGL("Fixed Weather", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"FixedWeather")); - menu->append(new LLMenuItemCallGL("Dump Region Object Cache", - &handle_dump_region_object_cache, NULL, NULL)); - menu->createJumpKeys(); -} - - -void handle_export_menus_to_xml(void*) -{ - - LLFilePicker& picker = LLFilePicker::instance(); - if(!picker.getSaveFile(LLFilePicker::FFSAVE_XML)) + bool handleEvent(const LLSD& userdata) { - llwarns << "No file" << llendl; - return; + handle_object_owner_permissive(NULL); + return true; } - std::string filename = picker.getFirstFile(); +}; - llofstream out(filename); - LLXMLNodePtr node = gMenuBarView->getXML(); - node->writeToOstream(out); - out.close(); -} - -extern BOOL gDebugClicks; -extern BOOL gDebugWindowProc; -extern BOOL gDebugTextEditorTips; -extern BOOL gDebugSelectMgr; - -void init_debug_ui_menu(LLMenuGL* menu) +class LLAdminHandleForceDelete : public view_listener_t { - menu->append(new LLMenuItemCheckGL("Rotate Mini-Map", menu_toggle_control, NULL, menu_check_control, (void*)"MiniMapRotate")); - menu->append(new LLMenuItemCheckGL("Use default system color picker", menu_toggle_control, NULL, menu_check_control, (void*)"UseDefaultColorPicker")); - menu->append(new LLMenuItemCheckGL("Show search panel in overlay bar", menu_toggle_control, NULL, menu_check_control, (void*)"ShowSearchBar")); - menu->appendSeparator(); - - menu->append(new LLMenuItemCallGL("Web Browser Test", &handle_web_browser_test)); - // commented out until work is complete: DEV-32268 - // menu->append(new LLMenuItemCallGL("Buy Currency Test", &handle_buy_currency_test)); - menu->append(new LLMenuItemCallGL("Editable UI", &edit_ui)); - menu->append(new LLMenuItemCallGL( "Dump SelectMgr", &dump_select_mgr)); - menu->append(new LLMenuItemCallGL( "Dump Inventory", &dump_inventory)); - menu->append(new LLMenuItemCallGL( "Dump Focus Holder", &handle_dump_focus, NULL, NULL, 'F', MASK_ALT | MASK_CONTROL)); - menu->append(new LLMenuItemCallGL( "Print Selected Object Info", &print_object_info, NULL, NULL, 'P', MASK_CONTROL|MASK_SHIFT )); - menu->append(new LLMenuItemCallGL( "Print Agent Info", &print_agent_nvpairs, NULL, NULL, 'P', MASK_SHIFT )); - menu->append(new LLMenuItemCallGL( "Memory Stats", &output_statistics, NULL, NULL, 'M', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - menu->append(new LLMenuItemCheckGL("Double-Click Auto-Pilot", - menu_toggle_control, NULL, menu_check_control, - (void*)"DoubleClickAutoPilot")); - menu->appendSeparator(); -// menu->append(new LLMenuItemCallGL( "Print Packets Lost", &print_packets_lost, NULL, NULL, 'L', MASK_SHIFT )); - menu->append(new LLMenuItemToggleGL("Debug SelectMgr", &gDebugSelectMgr)); - menu->append(new LLMenuItemToggleGL("Debug Clicks", &gDebugClicks)); - menu->append(new LLMenuItemToggleGL("Debug Views", &LLView::sDebugRects)); - menu->append(new LLMenuItemCheckGL("Show Name Tooltips", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); - menu->append(new LLMenuItemToggleGL("Debug Mouse Events", &LLView::sDebugMouseHandling)); - menu->append(new LLMenuItemToggleGL("Debug Keys", &LLView::sDebugKeys)); - menu->append(new LLMenuItemToggleGL("Debug WindowProc", &gDebugWindowProc)); - menu->append(new LLMenuItemToggleGL("Debug Text Editor Tips", &gDebugTextEditorTips)); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Show Time", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowTime")); - menu->append(new LLMenuItemCheckGL("Show Render Info", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderInfo")); - menu->append(new LLMenuItemCheckGL("Show Matrices", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowRenderMatrices")); - menu->append(new LLMenuItemCheckGL("Show Color Under Cursor", menu_toggle_control, NULL, menu_check_control, (void*)"DebugShowColor")); - - menu->createJumpKeys(); -} - -void init_debug_xui_menu(LLMenuGL* menu) -{ - menu->append(new LLMenuItemCallGL("Floater Test...", LLFloaterTest::show)); - menu->append(new LLMenuItemCallGL("Font Test...", LLFloaterFontTest::show)); - menu->append(new LLMenuItemCallGL("Export Menus to XML...", handle_export_menus_to_xml)); - menu->append(new LLMenuItemCallGL("Edit UI...", LLFloaterEditUI::show)); - menu->append(new LLMenuItemCallGL("Load from XML...", handle_load_from_xml)); - menu->append(new LLMenuItemCallGL("Save to XML...", handle_save_to_xml)); - menu->append(new LLMenuItemCheckGL("Show XUI Names", toggle_show_xui_names, NULL, check_show_xui_names, NULL)); - - //menu->append(new LLMenuItemCallGL("Buy Currency...", handle_buy_currency)); - menu->createJumpKeys(); -} - -void init_debug_rendering_menu(LLMenuGL* menu) -{ - LLMenuGL* sub_menu = NULL; - - /////////////////////////// - // - // Debug menu for types/pools - // - sub_menu = new LLMenuGL("Types"); - menu->appendMenu(sub_menu); - - sub_menu->append(new LLMenuItemCheckGL("Simple", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_SIMPLE, '1', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Alpha", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_ALPHA, '2', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Tree", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_TREE, '3', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Character", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_AVATAR, '4', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("SurfacePatch", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_TERRAIN, '5', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Sky", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_SKY, '6', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Water", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_WATER, '7', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Ground", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_GROUND, '8', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Volume", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_VOLUME, '9', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Grass", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_GRASS, '0', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Clouds", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_CLOUDS, '-', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Particles", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_PARTICLES, '`', MASK_ALT|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Bump", - &LLPipeline::toggleRenderTypeControl, NULL, - &LLPipeline::hasRenderTypeControl, - (void*)LLPipeline::RENDER_TYPE_BUMP, '\\', MASK_ALT|MASK_SHIFT)); - - sub_menu->createJumpKeys(); - sub_menu = new LLMenuGL("Features"); - menu->appendMenu(sub_menu); - sub_menu->append(new LLMenuItemCheckGL("UI", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_UI, KEY_F1, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Selected", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_SELECTED, KEY_F2, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Highlighted", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED, KEY_F3, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Dynamic Textures", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES, KEY_F4, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL( "Foot Shadows", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS, KEY_F5, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Fog", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_FOG, KEY_F6, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL("Test FRInfo", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO, KEY_F8, MASK_CONTROL|MASK_SHIFT)); - sub_menu->append(new LLMenuItemCheckGL( "Flexible Objects", - &LLPipeline::toggleRenderDebugFeature, NULL, - &LLPipeline::toggleRenderDebugFeatureControl, - (void*)LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE, KEY_F9, MASK_CONTROL|MASK_SHIFT)); - sub_menu->createJumpKeys(); - - ///////////////////////////// - // - // Debug menu for info displays - // - sub_menu = new LLMenuGL("Info Displays"); - menu->appendMenu(sub_menu); - - sub_menu->append(new LLMenuItemCheckGL("Verify", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_VERIFY)); - sub_menu->append(new LLMenuItemCheckGL("BBoxes", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_BBOXES)); - sub_menu->append(new LLMenuItemCheckGL("Points", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_POINTS)); - sub_menu->append(new LLMenuItemCheckGL("Octree", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_OCTREE)); - sub_menu->append(new LLMenuItemCheckGL("Shadow Frusta", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA)); - sub_menu->append(new LLMenuItemCheckGL("Occlusion", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_OCCLUSION)); - sub_menu->append(new LLMenuItemCheckGL("Render Batches", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_BATCH_SIZE)); - sub_menu->append(new LLMenuItemCheckGL("Animated Textures", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_TEXTURE_ANIM)); - sub_menu->append(new LLMenuItemCheckGL("Texture Priority", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)); - sub_menu->append(new LLMenuItemCheckGL("Avatar Rendering Cost", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_SHAME)); - sub_menu->append(new LLMenuItemCheckGL("Texture Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_TEXTURE_AREA)); - sub_menu->append(new LLMenuItemCheckGL("Face Area (sqrt(A))",&LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_FACE_AREA)); - sub_menu->append(new LLMenuItemCheckGL("Lights", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_LIGHTS)); - sub_menu->append(new LLMenuItemCheckGL("Particles", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_PARTICLES)); - sub_menu->append(new LLMenuItemCheckGL("Composition", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_COMPOSITION)); - sub_menu->append(new LLMenuItemCheckGL("Glow",&LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_GLOW)); - sub_menu->append(new LLMenuItemCheckGL("Raycasting", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_RAYCAST)); - sub_menu->append(new LLMenuItemCheckGL("Sculpt", &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_SCULPTED)); - - sub_menu->append(new LLMenuItemCallGL("Vectorize Perf Test", &run_vectorize_perf_test)); - - sub_menu = new LLMenuGL("Render Tests"); - - sub_menu->append(new LLMenuItemCheckGL("Camera Offset", - &menu_toggle_control, - NULL, - &menu_check_control, - (void*)"CameraOffset")); - - sub_menu->append(new LLMenuItemToggleGL("Randomize Framerate", &gRandomizeFramerate)); - - sub_menu->append(new LLMenuItemToggleGL("Periodic Slow Frame", &gPeriodicSlowFrame)); - - sub_menu->append(new LLMenuItemToggleGL("Frame Test", &LLPipeline::sRenderFrameTest)); - - sub_menu->createJumpKeys(); - - menu->appendMenu( sub_menu ); - - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Axes", menu_toggle_control, NULL, menu_check_control, (void*)"ShowAxes")); -// menu->append(new LLMenuItemCheckGL("Cull Small Objects", toggle_cull_small, NULL, menu_check_control, (void*)"RenderCullBySize")); - - menu->appendSeparator(); - menu->append(new LLMenuItemToggleGL("Hide Selected", &gHideSelectedObjects)); - menu->appendSeparator(); - menu->append(new LLMenuItemCheckGL("Tangent Basis", menu_toggle_control, NULL, menu_check_control, (void*)"ShowTangentBasis")); - menu->append(new LLMenuItemCallGL("Selected Texture Info", handle_selected_texture_info, NULL, NULL, 'T', MASK_CONTROL|MASK_SHIFT|MASK_ALT)); - //menu->append(new LLMenuItemCallGL("Dump Image List", handle_dump_image_list, NULL, NULL, 'I', MASK_CONTROL|MASK_SHIFT)); - - menu->append(new LLMenuItemToggleGL("Wireframe", &gUseWireframe, - 'R', MASK_CONTROL|MASK_SHIFT)); - - LLMenuItemCheckGL* item; - item = new LLMenuItemCheckGL("Object-Object Occlusion", menu_toggle_control, NULL, menu_check_control, (void*)"UseOcclusion", 'O', MASK_CONTROL|MASK_SHIFT); - item->setEnabled(gGLManager.mHasOcclusionQuery && LLFeatureManager::getInstance()->isFeatureAvailable("UseOcclusion")); - menu->append(item); - - item = new LLMenuItemCheckGL("Debug GL", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugGL"); - menu->append(item); - - item = new LLMenuItemCheckGL("Debug Pipeline", menu_toggle_control, NULL, menu_check_control, (void*)"RenderDebugPipeline"); - menu->append(item); - - item = new LLMenuItemCheckGL("Fast Alpha", menu_toggle_control, NULL, menu_check_control, (void*)"RenderFastAlpha"); - menu->append(item); - - item = new LLMenuItemCheckGL("Animate Textures", menu_toggle_control, NULL, menu_check_control, (void*)"AnimateTextures"); - menu->append(item); - - item = new LLMenuItemCheckGL("Disable Textures", menu_toggle_variable, NULL, menu_check_variable, (void*)&LLViewerImage::sDontLoadVolumeTextures); - menu->append(item); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - item = new LLMenuItemCheckGL("HTTP Get Textures", menu_toggle_control, NULL, menu_check_control, (void*)"ImagePipelineUseHTTP"); - menu->append(item); -#endif - - item = new LLMenuItemCheckGL("Run Multiple Threads", menu_toggle_control, NULL, menu_check_control, (void*)"RunMultipleThreads"); - menu->append(item); - - item = new LLMenuItemCheckGL("Cheesy Beacon", menu_toggle_control, NULL, menu_check_control, (void*)"CheesyBeacon"); - menu->append(item); - - item = new LLMenuItemCheckGL("Attached Lights", menu_toggle_attached_lights, NULL, menu_check_control, (void*)"RenderAttachedLights"); - menu->append(item); - - item = new LLMenuItemCheckGL("Attached Particles", menu_toggle_attached_particles, NULL, menu_check_control, (void*)"RenderAttachedParticles"); - menu->append(item); - -#ifndef LL_RELEASE_FOR_DOWNLOAD - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); -#else - if(gSavedSettings.getBOOL("QAMode")) + bool handleEvent(const LLSD& userdata) { - menu->appendSeparator(); - menu->append(new LLMenuItemCallGL("Memory Leaking Simulation", LLFloaterMemLeak::show, NULL, NULL)); + handle_force_delete(NULL); + return true; } -#endif - - menu->createJumpKeys(); -} +}; -void init_debug_avatar_menu(LLMenuGL* menu) -{ - LLMenuGL* sub_menu = new LLMenuGL("Grab Baked Texture"); - init_debug_baked_texture_menu(sub_menu); - menu->appendMenu(sub_menu); - - sub_menu = new LLMenuGL("Character Tests"); - sub_menu->append(new LLMenuItemCheckGL("Go Away/AFK When Idle", - menu_toggle_control, - NULL, - menu_check_control, - (void*)"AllowIdleAFK")); - - sub_menu->append(new LLMenuItemCallGL("Appearance To XML", - &LLVOAvatar::dumpArchetypeXML)); - - // HACK for easy testing of avatar geometry - sub_menu->append(new LLMenuItemCallGL( "Toggle Character Geometry", - &handle_god_request_avatar_geometry, &enable_god_customer_service, NULL)); - - sub_menu->append(new LLMenuItemCallGL("Test Male", - handle_test_male)); - - sub_menu->append(new LLMenuItemCallGL("Test Female", - handle_test_female)); - - sub_menu->append(new LLMenuItemCallGL("Toggle PG", handle_toggle_pg)); - - sub_menu->append(new LLMenuItemToggleGL("Allow Select Avatar", &gAllowSelectAvatar)); - sub_menu->createJumpKeys(); - - menu->appendMenu(sub_menu); - - menu->append(new LLMenuItemCheckGL("Enable Lip Sync (Beta)", menu_toggle_control, NULL, menu_check_control, (void*)"LipSyncEnabled")); - menu->append(new LLMenuItemToggleGL("Tap-Tap-Hold To Run", &gAllowTapTapHoldRun)); - menu->append(new LLMenuItemCallGL("Force Params to Default", &LLAgent::clearVisualParams, NULL)); - menu->append(new LLMenuItemCallGL("Reload Vertex Shader", &reload_vertex_shader, NULL)); - menu->append(new LLMenuItemToggleGL("Animation Info", &LLVOAvatar::sShowAnimationDebug)); - menu->append(new LLMenuItemCallGL("Slow Motion Animations", &slow_mo_animations, NULL)); - menu->append(new LLMenuItemToggleGL("Show Look At", &LLHUDEffectLookAt::sDebugLookAt)); - menu->append(new LLMenuItemToggleGL("Show Point At", &LLHUDEffectPointAt::sDebugPointAt)); - menu->append(new LLMenuItemToggleGL("Debug Joint Updates", &LLVOAvatar::sJointDebug)); - menu->append(new LLMenuItemToggleGL("Disable LOD", &LLViewerJoint::sDisableLOD)); - menu->append(new LLMenuItemToggleGL("Debug Character Vis", &LLVOAvatar::sDebugInvisible)); - //menu->append(new LLMenuItemToggleGL("Show Attachment Points", &LLVOAvatar::sShowAttachmentPoints)); - //diabling collision plane due to DEV-14477 -brad - //menu->append(new LLMenuItemToggleGL("Show Collision Plane", &LLVOAvatar::sShowFootPlane)); - menu->append(new LLMenuItemCheckGL("Show Collision Skeleton", - &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_AVATAR_VOLUME)); - menu->append(new LLMenuItemCheckGL("Display Agent Target", - &LLPipeline::toggleRenderDebug, NULL, - &LLPipeline::toggleRenderDebugControl, - (void*)LLPipeline::RENDER_DEBUG_AGENT_TARGET)); - menu->append(new LLMenuItemToggleGL( "Debug Rotation", &LLVOAvatar::sDebugAvatarRotation)); - menu->append(new LLMenuItemCallGL("Dump Attachments", handle_dump_attachments)); - menu->append(new LLMenuItemCallGL("Rebake Textures", handle_rebake_textures, NULL, NULL, 'R', MASK_ALT | MASK_CONTROL )); -#ifndef LL_RELEASE_FOR_DOWNLOAD - menu->append(new LLMenuItemCallGL("Debug Avatar Textures", handle_debug_avatar_textures, NULL, NULL, 'A', MASK_SHIFT|MASK_CONTROL|MASK_ALT)); - menu->append(new LLMenuItemCallGL("Dump Local Textures", handle_dump_avatar_local_textures, NULL, NULL, 'M', MASK_SHIFT|MASK_ALT )); -#endif - menu->createJumpKeys(); -} - -void init_debug_baked_texture_menu(LLMenuGL* menu) -{ - menu->append(new LLMenuItemCallGL("Iris", handle_grab_texture, enable_grab_texture, (void*) TEX_EYES_BAKED)); - menu->append(new LLMenuItemCallGL("Head", handle_grab_texture, enable_grab_texture, (void*) TEX_HEAD_BAKED)); - menu->append(new LLMenuItemCallGL("Upper Body", handle_grab_texture, enable_grab_texture, (void*) TEX_UPPER_BAKED)); - menu->append(new LLMenuItemCallGL("Lower Body", handle_grab_texture, enable_grab_texture, (void*) TEX_LOWER_BAKED)); - menu->append(new LLMenuItemCallGL("Skirt", handle_grab_texture, enable_grab_texture, (void*) TEX_SKIRT_BAKED)); - menu->append(new LLMenuItemCallGL("Hair", handle_grab_texture, enable_grab_texture, (void*) TEX_HAIR_BAKED)); - menu->createJumpKeys(); -} - -void init_server_menu(LLMenuGL* menu) +class LLAdminHandleObjectLock : public view_listener_t { + bool handleEvent(const LLSD& userdata) { - LLMenuGL* sub = new LLMenuGL("Object"); - menu->appendMenu(sub); - - sub->append(new LLMenuItemCallGL( "Take Copy", - &force_take_copy, &enable_god_customer_service, NULL, - 'O', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); -#ifdef _CORY_TESTING - sub->append(new LLMenuItemCallGL( "Export Copy", - &force_export_copy, NULL, NULL)); - sub->append(new LLMenuItemCallGL( "Import Geometry", - &force_import_geometry, NULL, NULL)); -#endif - //sub->append(new LLMenuItemCallGL( "Force Public", - // &handle_object_owner_none, NULL, NULL)); - //sub->append(new LLMenuItemCallGL( "Force Ownership/Permissive", - // &handle_object_owner_self_and_permissive, NULL, NULL, 'K', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Force Owner To Me", - &handle_object_owner_self, &enable_god_customer_service)); - sub->append(new LLMenuItemCallGL( "Force Owner Permissive", - &handle_object_owner_permissive, &enable_god_customer_service)); - //sub->append(new LLMenuItemCallGL( "Force Totally Permissive", - // &handle_object_permissive)); - sub->append(new LLMenuItemCallGL( "Delete", - &handle_force_delete, &enable_god_customer_service, NULL, KEY_DELETE, MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Lock", - &handle_object_lock, &enable_god_customer_service, NULL, 'L', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->append(new LLMenuItemCallGL( "Get Asset IDs", - &handle_object_asset_ids, &enable_god_customer_service, NULL, 'I', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->createJumpKeys(); + handle_object_lock(NULL); + return true; } - { - LLMenuGL* sub = new LLMenuGL("Parcel"); - menu->appendMenu(sub); +}; - sub->append(new LLMenuItemCallGL("Owner To Me", - &handle_force_parcel_owner_to_me, - &enable_god_customer_service, NULL)); - sub->append(new LLMenuItemCallGL("Set to Linden Content", - &handle_force_parcel_to_content, - &enable_god_customer_service, NULL, - 'C', MASK_SHIFT | MASK_ALT | MASK_CONTROL)); - sub->appendSeparator(); - sub->append(new LLMenuItemCallGL("Claim Public Land", - &handle_claim_public_land, &enable_god_customer_service)); - - sub->createJumpKeys(); - } +class LLAdminHandleObjectAssetIDs: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) { - LLMenuGL* sub = new LLMenuGL("Region"); - menu->appendMenu(sub); - sub->append(new LLMenuItemCallGL("Dump Temp Asset Data", - &handle_region_dump_temp_asset_data, - &enable_god_customer_service, NULL)); - sub->createJumpKeys(); + handle_object_asset_ids(NULL); + return true; } - menu->append(new LLMenuItemCallGL( "God Tools...", - &LLFloaterGodTools::show, &enable_god_basic, NULL)); +}; - menu->appendSeparator(); +//Admin >Parcel +class LLAdminHandleForceParcelOwnerToMe: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_owner_to_me(NULL); + return true; + } +}; +class LLAdminHandleForceParcelToContent: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_force_parcel_to_content(NULL); + return true; + } +}; +class LLAdminHandleClaimPublicLand: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_claim_public_land(NULL); + return true; + } +}; - menu->append(new LLMenuItemCallGL("Save Region State", - &LLPanelRegionTools::onSaveState, &enable_god_customer_service, NULL)); +// Admin > Region +class LLAdminHandleRegionDumpTempAssetData: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + handle_region_dump_temp_asset_data(NULL); + return true; + } +}; +//Admin (Top Level) -// menu->append(new LLMenuItemCallGL("Force Join Group", handle_force_join_group)); -// -// menu->appendSeparator(); -// -// menu->append(new LLMenuItemCallGL( "OverlayTitle", -// &handle_show_overlay_title, &enable_god_customer_service, NULL)); - menu->createJumpKeys(); +class LLAdminOnSaveState: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLPanelRegionTools::onSaveState(NULL); + return true; } +}; -static std::vector > sMenus; //----------------------------------------------------------------------------- // cleanup_menus() @@ -1513,8 +2421,6 @@ void cleanup_menus() delete gMenuHolder; gMenuHolder = NULL; - - sMenus.clear(); } //----------------------------------------------------------------------------- @@ -1523,7 +2429,7 @@ void cleanup_menus() class LLObjectReportAbuse : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (objectp) @@ -1537,17 +2443,16 @@ class LLObjectReportAbuse : public view_listener_t // Enabled it you clicked an object class LLObjectEnableReportAbuse : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLObjectTouch : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return true; @@ -1598,45 +2503,42 @@ class LLObjectTouch : public view_listener_t // One object must have touch sensor class LLObjectEnableTouch : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); bool new_value = obj && obj->flagHandleTouch(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); // Update label based on the node touch name if available. - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - std::string touch_text; + LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if (node && node->mValid && !node->mTouchName.empty()) { - touch_text = node->mTouchName; + touch_text = node->mTouchName; } else { - touch_text = userdata["data"].asString(); + touch_text = userdata.asString(); } - gMenuHolder->childSetText("Object Touch", touch_text); gMenuHolder->childSetText("Attachment Object Touch", touch_text); - return true; + return new_value; } }; -void label_touch(std::string& label, void*) -{ - LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); - if (node && node->mValid && !node->mTouchName.empty()) - { - label.assign(node->mTouchName); - } - else - { - label.assign("Touch"); - } -} - +//void label_touch(std::string& label, void*) +//{ +// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); +// if (node && node->mValid && !node->mTouchName.empty()) +// { +// label.assign(node->mTouchName); +// } +// else +// { +// label.assign("Touch"); +// } +//} +/* bool handle_object_open() { LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -1648,15 +2550,15 @@ bool handle_object_open() class LLObjectOpen : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { return handle_object_open(); } }; - +*/ class LLObjectEnableOpen : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // Look for contents in root object, which is all the LLFloaterOpenObject // understands. @@ -1668,96 +2570,14 @@ class LLObjectEnableOpen : public view_listener_t if (!root) new_value = false; else new_value = root->allowOpen(); } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; - - -class LLViewCheckBuildMode : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_value = LLToolMgr::getInstance()->inEdit(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; - -bool toggle_build_mode() -{ - if (LLToolMgr::getInstance()->inBuildMode()) - { - if (gSavedSettings.getBOOL("EditCameraMovement")) - { - // just reset the view, will pull us out of edit mode - handle_reset_view(); - } - else - { - // manually disable edit mode, but do not affect the camera - gAgent.resetView(false); - gFloaterTools->close(); - gViewerWindow->showCursor(); - } - // avoid spurious avatar movements pulling out of edit mode - LLViewerJoystick::getInstance()->setNeedsReset(); - } - else - { - ECameraMode camMode = gAgent.getCameraMode(); - if (CAMERA_MODE_MOUSELOOK == camMode || CAMERA_MODE_CUSTOMIZE_AVATAR == camMode) - { - // pull the user out of mouselook or appearance mode when entering build mode - handle_reset_view(); - } - - if (gSavedSettings.getBOOL("EditCameraMovement")) - { - // camera should be set - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { - handle_toggle_flycam(); - } - - if (gAgent.getFocusOnAvatar()) - { - // zoom in if we're looking at the avatar - gAgent.setFocusOnAvatar(FALSE, ANIMATE); - gAgent.setFocusGlobal(gAgent.getPositionGlobal() + 2.0 * LLVector3d(gAgent.getAtAxis())); - gAgent.cameraZoomIn(0.666f); - gAgent.cameraOrbitOver( 30.f * DEG_TO_RAD ); - } - } - - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() ); - - // Could be first use - LLFirstUse::useBuild(); - - gAgent.resetView(false); - - // avoid spurious avatar movements - LLViewerJoystick::getInstance()->setNeedsReset(); - - } - return true; -} - -class LLViewBuildMode : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - return toggle_build_mode(); + return new_value; } }; class LLViewJoystickFlycam : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { handle_toggle_flycam(); return true; @@ -1766,31 +2586,13 @@ class LLViewJoystickFlycam : public view_listener_t class LLViewCheckJoystickFlycam : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - bool new_val = LLViewerJoystick::getInstance()->getOverrideCamera(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_val); - return true; + bool handleEvent(const LLSD& userdata) + { + bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera(); + return new_value; } }; -class LLViewCommunicate : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - if (LLFloaterChatterBox::getInstance()->getFloaterCount() == 0) - { - LLFloaterMyFriends::toggleInstance(); - } - else - { - LLFloaterChatterBox::toggleInstance(); - } - return true; - } -}; - - void handle_toggle_flycam() { LLViewerJoystick::getInstance()->toggleFlycam(); @@ -1798,7 +2600,7 @@ void handle_toggle_flycam() class LLObjectBuild : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (gAgent.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") ) { @@ -1826,7 +2628,7 @@ class LLObjectBuild : public view_listener_t class LLObjectEdit : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerParcelMgr::getInstance()->deselectLand(); @@ -1856,7 +2658,7 @@ class LLObjectEdit : public view_listener_t } } - gFloaterTools->open(); /* Flawfinder: ignore */ + LLFloaterReg::showInstance("build"); LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() ); @@ -1870,22 +2672,12 @@ class LLObjectEdit : public view_listener_t } }; -class LLObjectInspect : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterInspect::show(); - return true; - } -}; - - //--------------------------------------------------------------------------- // Land pie menu //--------------------------------------------------------------------------- class LLLandBuild : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerParcelMgr::getInstance()->deselectLand(); @@ -1917,7 +2709,7 @@ class LLLandBuild : public view_listener_t class LLLandBuyPass : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLPanelLandGeneral::onClickBuyPass((void *)FALSE); return true; @@ -1926,11 +2718,10 @@ class LLLandBuyPass : public view_listener_t class LLLandEnableBuyPass : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLPanelLandGeneral::enableBuyPass(NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -1966,7 +2757,7 @@ BOOL enable_object_build(void*) class LLEnableEdit : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // *HACK: The new "prelude" Help Islands have a build sandbox area, // so users need the Edit and Create pie menu options when they are @@ -1979,23 +2770,22 @@ class LLEnableEdit : public view_listener_t enable = LLViewerParcelMgr::getInstance()->agentCanBuild() || LLSelectMgr::getInstance()->getSelection()->isAttachment(); } - gMenuHolder->findControl(userdata["control"].asString())->setValue(enable); - return true; + return enable; } }; class LLSelfRemoveAllAttachments : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - LLAgent::userRemoveAllAttachments(NULL); + LLAgentWearables::userRemoveAllAttachments(NULL); return true; } }; class LLSelfEnableRemoveAllAttachments : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = false; if (gAgent.getAvatarObject()) @@ -2013,8 +2803,7 @@ class LLSelfEnableRemoveAllAttachments : public view_listener_t } } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -2027,19 +2816,19 @@ BOOL enable_has_attachments(void*) //--------------------------------------------------------------------------- // Avatar pie menu //--------------------------------------------------------------------------- -void handle_follow(void *userdata) -{ - // follow a given avatar by ID - LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); - if (objectp) - { - gAgent.startFollowPilot(objectp->getID()); - } -} +//void handle_follow(void *userdata) +//{ +// // follow a given avatar by ID +// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); +// if (objectp) +// { +// gAgent.startFollowPilot(objectp->getID()); +// } +//} class LLObjectEnableMute : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); bool new_value = (object != NULL); @@ -2055,14 +2844,13 @@ class LLObjectEnableMute : public view_listener_t new_value = !is_linden && !is_self; } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLObjectMute : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return true; @@ -2108,7 +2896,7 @@ class LLObjectMute : public view_listener_t else { LLMuteList::getInstance()->add(mute); - LLFloaterMute::showInstance(); + LLFloaterReg::showInstance("mute"); } return true; @@ -2148,12 +2936,26 @@ bool handle_go_to() class LLGoToObject : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { return handle_go_to(); } }; +class LLAvatarReportAbuse : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + LLFloaterReporter::showFromObject(avatar->getID()); + } + return true; + } +}; + + //--------------------------------------------------------------------------- // Parcel freeze, eject, etc. //--------------------------------------------------------------------------- @@ -2192,7 +2994,7 @@ bool callback_freeze(const LLSD& notification, const LLSD& response) class LLAvatarFreeze : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if( avatar ) @@ -2224,38 +3026,37 @@ class LLAvatarFreeze : public view_listener_t class LLAvatarVisibleDebug : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = gAgent.isGodlike(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return gAgent.isGodlike(); } }; class LLAvatarEnableDebug : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = gAgent.isGodlike(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return gAgent.isGodlike(); } }; class LLAvatarDebug : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if( avatar ) { - avatar->dumpLocalTextures(); + if (avatar->isSelf()) + { + ((LLVOAvatarSelf *)avatar)->dumpLocalTextures(); + } llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl; std::vector strings; strings.push_back(avatar->getID().asString()); LLUUID invoice; send_generic_message("dumptempassetdata", strings, invoice); - LLFloaterAvatarTextures::show( avatar->getID() ); + LLFloaterReg::showInstance( "avatar_tetures", LLSD(avatar->getID()) ); } return true; } @@ -2317,7 +3118,7 @@ bool callback_eject(const LLSD& notification, const LLSD& response) class LLAvatarEject : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if( avatar ) @@ -2376,7 +3177,7 @@ class LLAvatarEject : public view_listener_t class LLAvatarEnableFreezeEject : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); bool new_value = (avatar != NULL); @@ -2399,14 +3200,13 @@ class LLAvatarEnableFreezeEject : public view_listener_t } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLAvatarGiveCard : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { llinfos << "handle_give_card()" << llendl; LLViewerObject* dest = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -2461,7 +3261,7 @@ void login_done(S32 which, void *user) { llinfos << "Login done " << which << llendl; - LLPanelLogin::close(); + LLPanelLogin::closePanel(); } @@ -2477,22 +3277,12 @@ bool callback_leave_group(const LLSD& notification, const LLSD& response) msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() ); msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_GroupData); - msg->addUUIDFast(_PREHASH_GroupID, gAgent.mGroupID ); + msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() ); gAgent.sendReliableMessage(); } return false; } -void handle_leave_group(void *) -{ - if (gAgent.getGroupID() != LLUUID::null) - { - LLSD args; - args["GROUP"] = gAgent.mGroupName; - LLNotifications::instance().add("GroupLeaveConfirmMember", args, LLSD(), callback_leave_group); - } -} - void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt) { LLAggregatePermissions::EValue val = ag_perm.getValue(bit); @@ -2538,11 +3328,10 @@ BOOL enable_buy(void*) class LLObjectEnableBuy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = enable_buy(NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -2624,18 +3413,9 @@ void handle_region_dump_settings(void*) } } -void handle_show_notifications_console(void *) -{ - LLFloaterNotificationConsole::showInstance(); -} - void handle_dump_group_info(void *) { - llinfos << "group " << gAgent.mGroupName << llendl; - llinfos << "ID " << gAgent.mGroupID << llendl; - llinfos << "powers " << gAgent.mGroupPowers << llendl; - llinfos << "title " << gAgent.mGroupTitle << llendl; - //llinfos << "insig " << gAgent.mGroupInsigniaID << llendl; + gAgent.dumpGroupInfo(); } void handle_dump_capabilities_info(void *) @@ -2665,19 +3445,43 @@ void handle_dump_focus(void *) class LLSelfStandUp : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + gAgent.standUp(); return true; } }; class LLSelfEnableStandUp : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = gAgent.getAvatarObject() && gAgent.getAvatarObject()->mIsSitting; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + bool new_value = gAgent.getAvatarObject() && gAgent.getAvatarObject()->isSitting(); + return new_value; + } +}; + +class LLSelfFriends : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + // Open "Friends" tab of the "People" panel in side tray. + LLSD param; + param["people_panel_tab_name"] = "friends_panel"; + + LLSideTray::getInstance()->showPanel("panel_people", param); + return true; + } +}; + +class LLSelfGroups : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + // Open "Groups" tab of the "People" panel in side tray. + LLSD param; + param["people_panel_tab_name"] = "groups_panel"; + LLSideTray::getInstance()->showPanel("panel_people", param); return true; } }; @@ -2740,7 +3544,6 @@ void set_god_level(U8 god_level) LLNotifications::instance().add("LeavingGodMode", args); } - // changing god-level can affect which menus we see show_debug_menus(); } @@ -2756,6 +3559,11 @@ BOOL check_toggle_hacked_godmode(void*) { return gHackGodmode; } + +bool enable_toggle_hacked_godmode(void*) +{ + return !LLViewerLogin::getInstance()->isInProductionGrid(); +} #endif void process_grant_godlike_powers(LLMessageSystem* msg, void**) @@ -2811,48 +3619,23 @@ bool LLHaveCallingcard::operator()(LLInventoryCategory* cat, } */ -BOOL is_agent_friend(const LLUUID& agent_id) -{ - return (LLAvatarTracker::instance().getBuddyInfo(agent_id) != NULL); -} - BOOL is_agent_mappable(const LLUUID& agent_id) { - return (is_agent_friend(agent_id) && + return (LLAvatarActions::isFriend(agent_id) && LLAvatarTracker::instance().getBuddyInfo(agent_id)->isOnline() && LLAvatarTracker::instance().getBuddyInfo(agent_id)->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION) ); } -// Enable a menu item when you have someone's card. -/* -BOOL enable_have_card(void *userdata) -{ - LLUUID* avatar_id = (LLUUID *)userdata; - if (gAgent.isGodlike()) - { - return TRUE; - } - else if(avatar_id) - { - return is_agent_friend(*avatar_id); - } - else - { - return FALSE; - } -} -*/ // Enable a menu item when you don't have someone's card. class LLAvatarEnableAddFriend : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); - bool new_value = avatar && !is_agent_friend(avatar->getID()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID()); + return new_value; } }; @@ -2875,7 +3658,7 @@ void request_friendship(const LLUUID& dest_id) } if (!fullname.empty()) { - LLPanelFriends::requestFriendshipDialog(dest_id, fullname); + LLAvatarActions::requestFriendshipDialog(dest_id, fullname); } else { @@ -2887,13 +3670,10 @@ void request_friendship(const LLUUID& dest_id) class LLEditEnableCustomizeAvatar : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = (gAgent.getAvatarObject() && - gAgent.getAvatarObject()->isFullyLoaded() && - gAgent.areWearablesLoaded()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + bool new_value = gAgentWearables.areWearablesLoaded(); + return new_value; } }; @@ -2909,7 +3689,7 @@ bool handle_sit_or_stand() if (sitting_on_selection()) { - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + gAgent.standUp(); return true; } @@ -2917,6 +3697,7 @@ bool handle_sit_or_stand() if (object && object->getPCode() == LL_PCODE_VOLUME) { + gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit); gMessageSystem->nextBlockFast(_PREHASH_AgentData); gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); @@ -2932,7 +3713,7 @@ bool handle_sit_or_stand() class LLObjectSitOrStand : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { return handle_sit_or_stand(); } @@ -2952,9 +3733,9 @@ void near_sit_down_point(BOOL success, void *) class LLLandSit : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - gAgent.setControlFlags(AGENT_CONTROL_STAND_UP); + gAgent.standUp(); LLViewerParcelMgr::getInstance()->deselectLand(); LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal; @@ -2973,137 +3754,6 @@ class LLLandSit : public view_listener_t } }; -void show_permissions_control(void*) -{ - LLFloaterPermissionsMgr* floaterp = LLFloaterPermissionsMgr::show(); - floaterp->mPermissions->addPermissionsData("foo1", LLUUID::null, 0); - floaterp->mPermissions->addPermissionsData("foo2", LLUUID::null, 0); - floaterp->mPermissions->addPermissionsData("foo3", LLUUID::null, 0); -} - - -class LLCreateLandmarkCallback : public LLInventoryCallback -{ -public: - /*virtual*/ void fire(const LLUUID& inv_item) - { - llinfos << "Created landmark with inventory id " << inv_item - << llendl; - } -}; - -void reload_ui(void *) -{ - LLUICtrlFactory::getInstance()->rebuild(); -} - -class LLWorldFly : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - gAgent.toggleFlying(); - return true; - } -}; - -class LLWorldEnableFly : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - BOOL sitting = FALSE; - if (gAgent.getAvatarObject()) - { - sitting = gAgent.getAvatarObject()->mIsSitting; - } - gMenuHolder->findControl(userdata["control"].asString())->setValue(!sitting); - return true; - } -}; - - -void handle_agent_stop_moving(void*) -{ - // stop agent - gAgent.setControlFlags(AGENT_CONTROL_STOP); - - // cancel autopilot - gAgent.stopAutoPilot(); -} - -void print_packets_lost(void*) -{ - LLWorld::getInstance()->printPacketsLost(); -} - - -void drop_packet(void*) -{ - gMessageSystem->mPacketRing.dropPackets(1); -} - - -void velocity_interpolate( void* data ) -{ - BOOL toggle = gSavedSettings.getBOOL("VelocityInterpolate"); - LLMessageSystem* msg = gMessageSystem; - if ( !toggle ) - { - msg->newMessageFast(_PREHASH_VelocityInterpolateOn); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation On" << llendl; - } - else - { - msg->newMessageFast(_PREHASH_VelocityInterpolateOff); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - gAgent.sendReliableMessage(); - llinfos << "Velocity Interpolation Off" << llendl; - } - // BUG this is a hack because of the change in menu behavior. The - // old menu system would automatically change a control's value, - // but the new LLMenuGL system doesn't know what a control - // is. However, it's easy to distinguish between the two callers - // because LLMenuGL passes in the name of the user data (the - // control name) to the callback function, and the user data goes - // unused in the old menu code. Thus, if data is not null, then we - // need to swap the value of the control. - if( data ) - { - gSavedSettings.setBOOL( static_cast(data), !toggle ); - } -} - - -void toggle_wind_audio(void) -{ - if (gAudiop) - { - gAudiop->enableWind(!(gAudiop->isWindEnabled())); - } -} - - -// Callback for enablement -BOOL is_inventory_visible( void* user_data ) -{ - LLInventoryView* iv = reinterpret_cast(user_data); - if( iv ) - { - return iv->getVisible(); - } - return FALSE; -} - -void handle_show_newest_map(void*) -{ - LLFloaterWorldMap::show(NULL, FALSE); -} - //------------------------------------------------------------------- // Help menu functions //------------------------------------------------------------------- @@ -3111,24 +3761,24 @@ void handle_show_newest_map(void*) // // Major mode switching // -void reset_view_final( BOOL proceed, void* ); +void reset_view_final( BOOL proceed ); void handle_reset_view() { if( (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgent.getCameraMode()) && gFloaterCustomize ) { // Show dialog box if needed. - gFloaterCustomize->askToSaveIfDirty( reset_view_final, NULL ); + gFloaterCustomize->askToSaveIfDirty( reset_view_final ); } else { - reset_view_final( TRUE, NULL ); + reset_view_final( TRUE ); } } class LLViewResetView : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { handle_reset_view(); return true; @@ -3136,7 +3786,7 @@ class LLViewResetView : public view_listener_t }; // Note: extra parameters allow this function to be called from dialog. -void reset_view_final( BOOL proceed, void* ) +void reset_view_final( BOOL proceed ) { if( !proceed ) { @@ -3148,7 +3798,7 @@ void reset_view_final( BOOL proceed, void* ) class LLViewLookAtLastChatter : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gAgent.lookAtLastChat(); return true; @@ -3157,7 +3807,7 @@ class LLViewLookAtLastChatter : public view_listener_t class LLViewMouselook : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (!gAgent.cameraMouselook()) { @@ -3173,7 +3823,7 @@ class LLViewMouselook : public view_listener_t class LLViewFullscreen : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gViewerWindow->toggleFullscreen(TRUE); return true; @@ -3182,7 +3832,7 @@ class LLViewFullscreen : public view_listener_t class LLViewDefaultUISize : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gSavedSettings.setF32("UIScaleFactor", 1.0f); gSavedSettings.setBOOL("UIAutoScale", FALSE); @@ -3193,7 +3843,7 @@ class LLViewDefaultUISize : public view_listener_t class LLEditDuplicate : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if(LLEditMenuHandler::gEditMenuHandler) { @@ -3205,23 +3855,13 @@ class LLEditDuplicate : public view_listener_t class LLEditEnableDuplicate : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; - -void disabled_duplicate(void*) -{ - if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()) - { - LLNotifications::instance().add("CopyFailed"); - } -} - void handle_duplicate_in_place(void*) { llinfos << "handle_duplicate_in_place" << llendl; @@ -3230,11 +3870,6 @@ void handle_duplicate_in_place(void*) LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE); } -void handle_repeat_duplicate(void*) -{ - LLSelectMgr::getInstance()->repeatDuplicate(); -} - /* dead code 30-apr-2008 void handle_deed_object_to_group(void*) { @@ -3386,37 +4021,6 @@ void handle_claim_public_land(void*) gAgent.sendReliableMessage(); } -void handle_god_request_havok(void *) -{ - if (gAgent.isGodlike()) - { - LLSelectMgr::getInstance()->sendGodlikeRequest("havok", "infoverbose"); - } -} - -//void handle_god_request_foo(void *) -//{ -// if (gAgent.isGodlike()) -// { -// LLSelectMgr::getInstance()->sendGodlikeRequest(GOD_WANTS_FOO); -// } -//} - -//void handle_god_request_terrain_save(void *) -//{ -// if (gAgent.isGodlike()) -// { -// LLSelectMgr::getInstance()->sendGodlikeRequest("terrain", "save"); -// } -//} - -//void handle_god_request_terrain_load(void *) -//{ -// if (gAgent.isGodlike()) -// { -// LLSelectMgr::getInstance()->sendGodlikeRequest("terrain", "load"); -// } -//} // HACK for easily testing new avatar geometry @@ -3429,12 +4033,6 @@ void handle_god_request_avatar_geometry(void *) } -void handle_show_overlay_title(void*) -{ - gShowOverlayTitle = !gShowOverlayTitle; - gSavedSettings.setBOOL("ShowOverlayTitle", gShowOverlayTitle); -} - void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) { if(gAgent.cameraMouselook()) @@ -3590,7 +4188,7 @@ void derez_objects(EDeRezDestination dest, const LLUUID& dest_id) class LLToolsTakeCopy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; @@ -3605,7 +4203,7 @@ class LLToolsTakeCopy : public view_listener_t // You can return an object to its owner if it is on your land. class LLObjectReturn : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true; @@ -3638,7 +4236,7 @@ protected: // over land you own. class LLObjectEnableReturn : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { #ifdef HACKED_GODLIKE_VIEWER bool new_value = true; @@ -3675,8 +4273,7 @@ class LLObjectEnableReturn : public view_listener_t } } #endif - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -3752,7 +4349,7 @@ void handle_take() } // check library - if(gInventory.isObjectDescendentOf(category_id, gInventoryLibraryRoot)) + if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID())) { category_id.setNull(); } @@ -3767,8 +4364,8 @@ void handle_take() payload["folder_id"] = category_id; LLNotification::Params params("ConfirmObjectTakeLock"); - params.payload(payload) - .functor(confirm_take); + params.payload(payload); + params.functor.function(confirm_take); if(locked_but_takeable_object || !you_own_everything) @@ -3776,7 +4373,6 @@ void handle_take() if(locked_but_takeable_object && you_own_everything) { params.name("ConfirmObjectTakeLock"); - } else if(!locked_but_takeable_object && !you_own_everything) { @@ -3849,7 +4445,7 @@ BOOL enable_take() class LLToolsBuyOrTake : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) { @@ -3880,17 +4476,16 @@ class LLToolsBuyOrTake : public view_listener_t class LLToolsEnableBuyOrTake : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool is_buy = is_selection_buy_not_take(); bool new_value = is_buy ? enable_buy(NULL) : enable_take(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); // Update label std::string label; std::string buy_text; std::string take_text; - std::string param = userdata["data"].asString(); + std::string param = userdata.asString(); std::string::size_type offset = param.find(","); if (offset != param.npos) { @@ -3908,7 +4503,7 @@ class LLToolsEnableBuyOrTake : public view_listener_t gMenuHolder->childSetText("Pie Object Take", label); gMenuHolder->childSetText("Menu Object Take", label); - return true; + return new_value; } }; @@ -3963,42 +4558,36 @@ S32 selection_price() return total_price; } - +/* bool callback_show_buy_currency(const LLSD& notification, const LLSD& response) { S32 option = LLNotification::getSelectedOption(notification, response); if (0 == option) { - llinfos << "Loading page " << BUY_CURRENCY_URL << llendl; - LLWeb::loadURL(BUY_CURRENCY_URL); + llinfos << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << llendl; + LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")); } return false; } - +*/ void show_buy_currency(const char* extra) { // Don't show currency web page for branded clients. - +/* std::ostringstream mesg; if (extra != NULL) { mesg << extra << "\n \n"; } - mesg << "Go to " << BUY_CURRENCY_URL << "\nfor information on purchasing currency?"; - + mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?"; +*/ LLSD args; if (extra != NULL) { args["EXTRA"] = extra; } - args["URL"] = BUY_CURRENCY_URL; - LLNotifications::instance().add("PromptGoToCurrencyPage", args, LLSD(), callback_show_buy_currency); -} - -void handle_buy_currency(void*) -{ -// LLFloaterBuyCurrency::buyCurrency(); + LLNotifications::instance().add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency); } void handle_buy(void*) @@ -4021,7 +4610,7 @@ void handle_buy(void*) class LLObjectBuy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { handle_buy(NULL); return true; @@ -4054,12 +4643,24 @@ BOOL sitting_on_selection() return FALSE; } - return (avatar->mIsSitting && avatar->getRoot() == root_object); + return (avatar->isSitting() && avatar->getRoot() == root_object); } +class LLToolsSaveToInventory : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + if(enable_save_into_inventory(NULL)) + { + derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null); + } + return true; + } +}; + class LLToolsSaveToObjectInventory : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); if(node && (node->mValid) && (!node->mFromTaskID.isNull())) @@ -4074,7 +4675,7 @@ class LLToolsSaveToObjectInventory : public view_listener_t // Round the position of all root objects to the grid class LLToolsSnapObjectXY : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { F64 snap_size = (F64)gSavedSettings.getF32("GridResolution"); @@ -4128,7 +4729,7 @@ class LLToolsSnapObjectXY : public view_listener_t // reasonable expectation for the link to work, but it will fail. class LLToolsEnableLink : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = false; // check if there are at least 2 objects selected, and that the @@ -4150,14 +4751,13 @@ class LLToolsEnableLink : public view_listener_t new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLToolsLink : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if(!LLSelectMgr::getInstance()->selectGetAllRootsValid()) { @@ -4203,19 +4803,18 @@ class LLToolsLink : public view_listener_t class LLToolsEnableUnlink : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLSelectMgr::getInstance()->selectGetAllRootsValid() && LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() && !LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject()->isAttachment(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLToolsUnlink : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLSelectMgr::getInstance()->sendDelink(); return true; @@ -4225,7 +4824,7 @@ class LLToolsUnlink : public view_listener_t class LLToolsStopAllAnimations : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gAgent.stopCurrentAnimations(); return true; @@ -4234,7 +4833,7 @@ class LLToolsStopAllAnimations : public view_listener_t class LLToolsReleaseKeys : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gAgent.forceReleaseControls(); @@ -4244,58 +4843,25 @@ class LLToolsReleaseKeys : public view_listener_t class LLToolsEnableReleaseKeys : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - gMenuHolder->findControl(userdata["control"].asString())->setValue( gAgent.anyControlGrabbed() ); - return true; + return gAgent.anyControlGrabbed(); } }; -//void handle_hinge(void*) -//{ -// LLSelectMgr::getInstance()->sendHinge(1); -//} - -//void handle_ptop(void*) -//{ -// LLSelectMgr::getInstance()->sendHinge(2); -//} - -//void handle_lptop(void*) -//{ -// LLSelectMgr::getInstance()->sendHinge(3); -//} - -//void handle_wheel(void*) -//{ -// LLSelectMgr::getInstance()->sendHinge(4); -//} - -//void handle_dehinge(void*) -//{ -// LLSelectMgr::getInstance()->sendDehinge(); -//} - -//BOOL enable_dehinge(void*) -//{ -// LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject(); -// return obj && !obj->isAttachment(); -//} - class LLEditEnableCut : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditCut : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -4307,17 +4873,16 @@ class LLEditCut : public view_listener_t class LLEditEnableCopy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditCopy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -4329,17 +4894,16 @@ class LLEditCopy : public view_listener_t class LLEditEnablePaste : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditPaste : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -4351,17 +4915,16 @@ class LLEditPaste : public view_listener_t class LLEditEnableDelete : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditDelete : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // If a text field can do a deletion, it gets precedence over deleting // an object in the world. @@ -4375,14 +4938,14 @@ class LLEditDelete : public view_listener_t // When deleting an object we may not actually be done // Keep selection so we know what to delete when confirmation is needed about the delete - gPieObject->hide(TRUE); + gPieObject->hide(); return true; } }; class LLObjectEnableDelete : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = #ifdef HACKED_GODLIKE_VIEWER @@ -4394,23 +4957,13 @@ class LLObjectEnableDelete : public view_listener_t # endif LLSelectMgr::getInstance()->canDoDelete(); #endif - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; - } -}; - -class LLEditSearch : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterDirectory::toggleFind(NULL); - return true; + return new_value; } }; class LLObjectDelete : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (LLSelectMgr::getInstance()) { @@ -4422,7 +4975,7 @@ class LLObjectDelete : public view_listener_t // When deleting an object we may not actually be done // Keep selection so we know what to delete when confirmation is needed about the delete - gPieObject->hide(TRUE); + gPieObject->hide(); return true; } }; @@ -4434,38 +4987,35 @@ void handle_force_delete(void*) class LLViewEnableJoystickFlycam : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled")); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLViewEnableLastChatter : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // *TODO: add check that last chatter is in range bool new_value = (gAgent.cameraThirdPerson() && gAgent.getLastChatter().notNull()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditEnableDeselect : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditDeselect : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -4477,18 +5027,17 @@ class LLEditDeselect : public view_listener_t class LLEditEnableSelectAll : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditSelectAll : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler ) { @@ -4501,17 +5050,16 @@ class LLEditSelectAll : public view_listener_t class LLEditEnableUndo : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditUndo : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() ) { @@ -4523,17 +5071,16 @@ class LLEditUndo : public view_listener_t class LLEditEnableRedo : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditRedo : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() ) { @@ -4571,35 +5118,42 @@ void print_agent_nvpairs(void*) void show_debug_menus() { - // this can get called at login screen where there is no menu so only toggle it if one exists + // this might get called at login screen where there is no menu so only toggle it if one exists if ( gMenuBarView ) { BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); - - if(debug) - { - LLFirstUse::useDebugMenus(); - } + BOOL qamode = gSavedSettings.getBOOL("QAMode"); - gMenuBarView->setItemVisible(CLIENT_MENU_NAME, debug); - gMenuBarView->setItemEnabled(CLIENT_MENU_NAME, debug); + gMenuBarView->setItemVisible("Advanced", debug); +// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden + + gMenuBarView->setItemVisible("Debug", qamode); + gMenuBarView->setItemEnabled("Debug", qamode); + + gMenuBarView->setItemVisible("Develop", qamode); + gMenuBarView->setItemEnabled("Develop", qamode); // Server ('Admin') menu hidden when not in godmode. const bool show_server_menu = debug && (gAgent.getGodLevel() > GOD_NOT); - gMenuBarView->setItemVisible(SERVER_MENU_NAME, show_server_menu); - gMenuBarView->setItemEnabled(SERVER_MENU_NAME, show_server_menu); - - //gMenuBarView->setItemVisible("DebugOptions", visible); - //gMenuBarView->setItemVisible(std::string(AVI_TOOLS), visible); - - gMenuBarView->arrange(); // clean-up positioning - }; + gMenuBarView->setItemVisible("Admin", show_server_menu); + gMenuBarView->setItemEnabled("Admin", show_server_menu); + } + if (gLoginMenuBarView) + { + BOOL debug = gSavedSettings.getBOOL("UseDebugMenus"); + gLoginMenuBarView->setItemVisible("Debug", debug); + gLoginMenuBarView->setItemEnabled("Debug", debug); + } } void toggle_debug_menus(void*) { BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus"); gSavedSettings.setBOOL("UseDebugMenus", visible); + if(visible) + { + LLFirstUse::useDebugMenus(); + } show_debug_menus(); } @@ -4641,27 +5195,12 @@ void toggle_debug_menus(void*) // gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects..."); // } +// -BOOL menu_check_build_tool( void* user_data ) -{ - S32 index = (intptr_t) user_data; - return LLToolMgr::getInstance()->getCurrentToolset()->isToolSelected( index ); -} - -void handle_reload_settings(void*) -{ - gSavedSettings.resetToDefaults(); - gSavedSettings.loadFromFile(gSavedSettings.getString("ClientSettingsFile")); - - llinfos << "Loading colors from colors.xml" << llendl; - std::string color_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"colors.xml"); - gColors.resetToDefaults(); - gColors.loadFromFileLegacy(color_file, FALSE, TYPE_COL4U); -} class LLWorldSetHomeLocation : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // we just send the message and let the server check for failure cases // server will echo back a "Home position set." alert if it succeeds @@ -4673,7 +5212,7 @@ class LLWorldSetHomeLocation : public view_listener_t class LLWorldTeleportHome : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { gAgent.teleportHome(); return true; @@ -4682,7 +5221,7 @@ class LLWorldTeleportHome : public view_listener_t class LLWorldAlwaysRun : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // as well as altering the default walk-vs-run state, // we also change the *current* walk-vs-run state. @@ -4700,23 +5239,25 @@ class LLWorldAlwaysRun : public view_listener_t // tell the simulator. gAgent.sendWalkRun(gAgent.getAlwaysRun()); + // Update Movement Controls according to AlwaysRun mode + LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun()); + return true; } }; class LLWorldCheckAlwaysRun : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = gAgent.getAlwaysRun(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLWorldSetAway : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (gAgent.getAFK()) { @@ -4732,7 +5273,7 @@ class LLWorldSetAway : public view_listener_t class LLWorldSetBusy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (gAgent.getBusy()) { @@ -4747,53 +5288,19 @@ class LLWorldSetBusy : public view_listener_t } }; -bool can_create_landmark() -{ - BOOL can = FALSE; - - LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); - if (agent_parcel) - { - - if (agent_parcel->getAllowLandmark() - || LLViewerParcelMgr::isParcelOwnedByAgent(agent_parcel, GP_LAND_ALLOW_LANDMARK)) - { - can = TRUE; - } - } - - return can; -} - class LLWorldCreateLandmark : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - if (!can_create_landmark()) - { - LLNotifications::instance().add("CannotCreateLandmarkNotOwner"); - return true; - } + LLSideTray::getInstance()->showPanel("panel_places", LLSD().insert("type", "create_landmark")); - LLUUID folder_id; - folder_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_LANDMARK); - std::string pos_string; - gAgent.buildLocationString(pos_string); - - create_inventory_item(gAgent.getID(), gAgent.getSessionID(), - folder_id, LLTransactionID::tnull, - pos_string, pos_string, // name, desc - LLAssetType::AT_LANDMARK, - LLInventoryType::IT_LANDMARK, - NOT_WEARABLE, PERM_ALL, - new LLCreateLandmarkCallback); return true; } }; class LLToolsLookAtSelection : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { const F32 PADDING_FACTOR = 2.f; BOOL zoom = (userdata.asString() == "zoom"); @@ -4828,10 +5335,10 @@ class LLToolsLookAtSelection : public view_listener_t } }; -void callback_invite_to_group(LLUUID group_id, void *user_data) +void callback_invite_to_group(LLUUID group_id, LLUUID dest_id) { std::vector agent_ids; - agent_ids.push_back(*(LLUUID *)user_data); + agent_ids.push_back(dest_id); LLFloaterGroupInvite::showForGroup(group_id, &agent_ids); } @@ -4841,20 +5348,19 @@ void invite_to_group(const LLUUID& dest_id) LLViewerObject* dest = gObjectList.findObject(dest_id); if(dest && dest->isAvatar()) { - LLFloaterGroupPicker* widget; - widget = LLFloaterGroupPicker::showInstance(LLSD(gAgent.getID())); + LLFloaterGroupPicker* widget = LLFloaterReg::showTypedInstance("group_picker", LLSD(gAgent.getID())); if (widget) { widget->center(); widget->setPowersMask(GP_MEMBER_INVITE); - widget->setSelectCallback(callback_invite_to_group, (void *)&dest_id); + widget->setSelectGroupCallback(boost::bind(callback_invite_to_group, _1, dest_id)); } } } class LLAvatarInviteToGroup : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -4867,10 +5373,10 @@ class LLAvatarInviteToGroup : public view_listener_t class LLAvatarAddFriend : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar && !is_agent_friend(avatar->getID())) + if(avatar && !LLAvatarActions::isFriend(avatar->getID())) { request_friendship(avatar->getID()); } @@ -4878,6 +5384,19 @@ class LLAvatarAddFriend : public view_listener_t } }; +class LLAvatarAddContact : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); + if(avatar) + { + create_inventory_callingcard(avatar->getID()); + } + return true; + } +}; + bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle handle) { S32 option = LLNotification::getSelectedOption(notification, response); @@ -4917,7 +5436,7 @@ bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjec bool handle_give_money_dialog() { LLNotification::Params params("BusyModePay"); - params.functor(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); + params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection())); if (gAgent.getBusy()) { @@ -4933,7 +5452,7 @@ bool handle_give_money_dialog() class LLPayObject : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { return handle_give_money_dialog(); } @@ -4941,7 +5460,7 @@ class LLPayObject : public view_listener_t class LLEnablePayObject : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()); bool new_value = (avatar != NULL); @@ -4957,14 +5476,13 @@ class LLEnablePayObject : public view_listener_t } } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLObjectEnableSitOrStand : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = false; LLViewerObject* dest_object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); @@ -4976,13 +5494,11 @@ class LLObjectEnableSitOrStand : public view_listener_t new_value = true; } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - // Update label std::string label; std::string sit_text; std::string stand_text; - std::string param = userdata["data"].asString(); + std::string param = userdata.asString(); std::string::size_type offset = param.find(","); if (offset != param.npos) { @@ -5007,7 +5523,7 @@ class LLObjectEnableSitOrStand : public view_listener_t } gMenuHolder->childSetText("Object Sit", label); - return true; + return new_value; } }; @@ -5026,29 +5542,6 @@ void dump_inventory(void*) gInventory.dumpInventory(); } -// forcibly unlock an object -void handle_force_unlock(void*) -{ - // First, make it public. - LLSelectMgr::getInstance()->sendOwner(LLUUID::null, LLUUID::null, TRUE); - - // Second, lie to the viewer and mark it editable and unowned - - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* object) - { - object->mFlags |= FLAGS_OBJECT_MOVE; - object->mFlags |= FLAGS_OBJECT_MODIFY; - object->mFlags |= FLAGS_OBJECT_COPY; - - object->mFlags &= ~FLAGS_OBJECT_ANY_OWNER; - object->mFlags &= ~FLAGS_OBJECT_YOU_OWNER; - return true; - } - } func; - LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func); -} void handle_dump_followcam(void*) { @@ -5065,84 +5558,22 @@ void handle_viewer_disable_message_log(void*) gMessageSystem->stopLogging(); } -// TomY TODO: Move! class LLShowFloater : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string floater_name = userdata.asString(); - if (floater_name == "gestures") + if (floater_name == "appearance") { - LLFloaterGesture::toggleVisibility(); - } - else if (floater_name == "appearance") - { - if (gAgent.areWearablesLoaded()) + if (gAgentWearables.areWearablesLoaded()) { gAgent.changeCameraToCustomizeAvatar(); } } - else if (floater_name == "friends") - { - LLFloaterMyFriends::toggleInstance(0); - } - else if (floater_name == "preferences") - { - LLFloaterPreference::show(NULL); - } else if (floater_name == "toolbar") { LLToolBar::toggle(NULL); } - else if (floater_name == "chat history") - { - LLFloaterChat::toggleInstance(LLSD()); - } - else if (floater_name == "im") - { - LLFloaterChatterBox::toggleInstance(LLSD()); - } - else if (floater_name == "inventory") - { - LLInventoryView::toggleVisibility(NULL); - } - else if (floater_name == "mute list") - { - LLFloaterMute::toggleInstance(); - } - else if (floater_name == "camera controls") - { - LLFloaterCamera::toggleInstance(); - } - else if (floater_name == "movement controls") - { - LLFloaterMove::toggleInstance(); - } - else if (floater_name == "world map") - { - LLFloaterWorldMap::toggle(NULL); - } - else if (floater_name == "mini map") - { - LLFloaterMap::toggleInstance(); - } - else if (floater_name == "stat bar") - { - LLFloaterStats::toggleInstance(); - } - else if (floater_name == "my land") - { - LLFloaterLandHoldings::show(NULL); - } - else if (floater_name == "about land") - { - if (LLViewerParcelMgr::getInstance()->selectionEmpty()) - { - LLViewerParcelMgr::getInstance()->selectParcelAt(gAgent.getPositionGlobal()); - } - - LLFloaterLand::showInstance(); - } else if (floater_name == "buy land") { if (LLViewerParcelMgr::getInstance()->selectionEmpty()) @@ -5152,68 +5583,28 @@ class LLShowFloater : public view_listener_t LLViewerParcelMgr::getInstance()->startBuyLand(); } - else if (floater_name == "about region") - { - LLFloaterRegionInfo::showInstance(); - } - else if (floater_name == "grid options") - { - LLFloaterBuildOptions::show(NULL); - } else if (floater_name == "script errors") { LLFloaterScriptDebug::show(LLUUID::null); } else if (floater_name == "help f1") { + llinfos << "Spawning HTML help window" << llendl; gViewerHtmlHelp.show(); } - else if (floater_name == "help tutorial") - { - LLFloaterHUD::showHUD(); - } else if (floater_name == "complaint reporter") { // Prevent menu from appearing in screen shot. gMenuHolder->hideMenus(); LLFloaterReporter::showFromMenu(COMPLAINT_REPORT); } - else if (floater_name == "mean events") - { - if (!gNoRender) - { - LLFloaterBump::show(NULL); - } - } - else if (floater_name == "lag meter") - { - LLFloaterLagMeter::showInstance(); - } - else if (floater_name == "bug reporter") - { - // Prevent menu from appearing in screen shot. - gMenuHolder->hideMenus(); - LLFloaterReporter::showFromMenu(BUG_REPORT); - } else if (floater_name == "buy currency") { LLFloaterBuyCurrency::buyCurrency(); } - else if (floater_name == "about") + else { - LLFloaterAbout::show(NULL); - } - else if (floater_name == "active speakers") - { - LLFloaterActiveSpeakers::toggleInstance(LLSD()); - } - else if (floater_name == "beacons") - { - LLFloaterBeacons::toggleInstance(LLSD()); - } - else if (floater_name == "perm prefs") - { - LLFloaterPerms::toggleInstance(LLSD()); + LLFloaterReg::toggleInstance(floater_name); } return true; } @@ -5221,62 +5612,19 @@ class LLShowFloater : public view_listener_t class LLFloaterVisible : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - std::string control_name = userdata["control"].asString(); - std::string floater_name = userdata["data"].asString(); + std::string floater_name = userdata.asString(); bool new_value = false; - if (floater_name == "friends") - { - new_value = LLFloaterMyFriends::instanceVisible(0); - } - else if (floater_name == "communicate") - { - new_value = LLFloaterChatterBox::instanceVisible(); - } - else if (floater_name == "toolbar") + if (floater_name == "toolbar") { new_value = LLToolBar::visible(NULL); } - else if (floater_name == "chat history") + else { - new_value = LLFloaterChat::instanceVisible(); + new_value = LLFloaterReg::instanceVisible(floater_name); } - else if (floater_name == "im") - { - new_value = LLFloaterMyFriends::instanceVisible(0); - } - else if (floater_name == "mute list") - { - new_value = LLFloaterMute::instanceVisible(); - } - else if (floater_name == "camera controls") - { - new_value = LLFloaterCamera::instanceVisible(); - } - else if (floater_name == "movement controls") - { - new_value = LLFloaterMove::instanceVisible(); - } - else if (floater_name == "stat bar") - { - new_value = LLFloaterStats::instanceVisible(); - } - else if (floater_name == "active speakers") - { - new_value = LLFloaterActiveSpeakers::instanceVisible(LLSD()); - } - else if (floater_name == "beacons") - { - new_value = LLFloaterBeacons::instanceVisible(LLSD()); - } - else if (floater_name == "inventory") - { - LLInventoryView* iv = LLInventoryView::getActiveInventory(); - new_value = (NULL != iv && TRUE == iv->getVisible()); - } - gMenuHolder->findControl(control_name)->setValue(new_value); - return true; + return new_value; } }; @@ -5292,7 +5640,7 @@ bool callback_show_url(const LLSD& notification, const LLSD& response) class LLPromptShowURL : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -5332,7 +5680,7 @@ bool callback_show_file(const LLSD& notification, const LLSD& response) class LLPromptShowFile : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string param = userdata.asString(); std::string::size_type offset = param.find(","); @@ -5355,7 +5703,7 @@ class LLPromptShowFile : public view_listener_t class LLShowAgentProfile : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLUUID agent_id; if (userdata.asString() == "agent") @@ -5378,50 +5726,15 @@ class LLShowAgentProfile : public view_listener_t LLVOAvatar* avatar = find_avatar_from_object(agent_id); if (avatar) { - LLFloaterAvatarInfo::show( avatar->getID() ); + LLAvatarActions::showProfile(avatar->getID()); } return true; } }; -class LLShowAgentGroups : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterMyFriends::toggleInstance(1); - return true; - } -}; - -void handle_focus(void *) -{ - if (gDisconnected) - { - return; - } - - if (gAgent.getFocusOnAvatar()) - { - // zoom in if we're looking at the avatar - gAgent.setFocusOnAvatar(FALSE, ANIMATE); - gAgent.setFocusGlobal(LLToolPie::getInstance()->getPick()); - gAgent.cameraZoomIn(0.666f); - } - else - { - gAgent.setFocusGlobal(LLToolPie::getInstance()->getPick()); - } - - gViewerWindow->moveCursorToCenter(); - - // Switch to camera toolset -// LLToolMgr::getInstance()->setCurrentToolset(gCameraToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCamera::getInstance() ); -} - class LLLandEdit : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if (gAgent.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") ) { @@ -5441,7 +5754,7 @@ class LLLandEdit : public view_listener_t LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal ); - gFloaterView->bringToFront( gFloaterTools ); + LLFloaterReg::showInstance("build"); // Switch to land edit toolset LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() ); @@ -5451,15 +5764,14 @@ class LLLandEdit : public view_listener_t class LLWorldEnableBuyLand : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel( LLViewerParcelMgr::getInstance()->selectionEmpty() ? LLViewerParcelMgr::getInstance()->getAgentParcel() : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -5470,26 +5782,6 @@ BOOL enable_buy_land(void*) } -void handle_move(void*) -{ - if (gAgent.getFocusOnAvatar()) - { - // zoom in if we're looking at the avatar - gAgent.setFocusOnAvatar(FALSE, ANIMATE); - gAgent.setFocusGlobal(LLToolPie::getInstance()->getPick()); - - gAgent.cameraZoomIn(0.666f); - } - else - { - gAgent.setFocusGlobal(LLToolPie::getInstance()->getPick()); - } - - gViewerWindow->moveCursorToCenter(); - - LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset); - LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() ); -} class LLObjectAttachToAvatar : public view_listener_t { @@ -5497,7 +5789,7 @@ public: static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; } private: - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { setObjectSelection(LLSelectMgr::getInstance()->getSelection()); LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject(); @@ -5580,7 +5872,7 @@ void confirm_replace_attachment(S32 option, void* user_data) class LLAttachmentDrop : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // Called when the user clicked on an object attached to them // and selected "Drop". @@ -5624,11 +5916,13 @@ class LLAttachmentDrop : public view_listener_t }; // called from avatar pie menu -void handle_detach_from_avatar(void* user_data) +class LLAttachmentDetachFromPoint : public view_listener_t { - LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; + bool handleEvent(const LLSD& user_data) +{ + LLViewerJointAttachment *attachment = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL); - LLViewerObject* attached_object = attachment->getObject(); + LLViewerObject* attached_object = attachment ? attachment->getObject() : NULL; if (attached_object) { @@ -5641,14 +5935,20 @@ void handle_detach_from_avatar(void* user_data) gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID()); gMessageSystem->sendReliable( gAgent.getRegionHost() ); } + return true; } +}; -void attach_label(std::string& label, void* user_data) +static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data) { - LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data; + std::string label; + LLMenuItemGL* menu = dynamic_cast(ctrl); + if (menu) + { + LLViewerJointAttachment *attachmentp = get_if_there(gAgent.getAvatarObject()->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL); if (attachmentp) { - label = attachmentp->getName(); + label = data["label"].asString(); if (attachmentp->getObject()) { LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); @@ -5658,29 +5958,15 @@ void attach_label(std::string& label, void* user_data) } } } + menu->setLabel(label); } - -void detach_label(std::string& label, void* user_data) -{ - LLViewerJointAttachment* attachmentp = (LLViewerJointAttachment*)user_data; - if (attachmentp) - { - label = attachmentp->getName(); - if (attachmentp->getObject()) - { - LLViewerInventoryItem* itemp = gInventory.getItem(attachmentp->getItemID()); - if (itemp) - { - label += std::string(" (") + itemp->getName() + std::string(")"); - } - } - } + return true; } class LLAttachmentDetach : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // Called when the user clicked on an object attached to them // and selected "Detach". @@ -5749,7 +6035,7 @@ protected: // You can only drop items on parcels where you can build. class LLAttachmentEnableDrop : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->agentCanBuild()); @@ -5796,14 +6082,13 @@ class LLAttachmentEnableDrop : public view_listener_t } //now check to make sure that the item is actually in the inventory before we enable dropping it - bool new_value = enable_detach(NULL) && can_build && item; + bool new_value = enable_detach() && can_build && item; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; -BOOL enable_detach(void*) +BOOL enable_detach(const LLSD&) { LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (!object) return FALSE; @@ -5827,18 +6112,16 @@ BOOL enable_detach(void*) class LLAttachmentEnableDetach : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = enable_detach(NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + bool new_value = enable_detach(); + return new_value; } }; // Used to tell if the selected object can be attached to your avatar. -BOOL object_selected_and_point_valid(void *user_data) +BOOL object_selected_and_point_valid(const LLSD&) { - //LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); for (LLObjectSelection::root_iterator iter = selection->root_begin(); iter != selection->root_end(); iter++) @@ -5867,7 +6150,7 @@ BOOL object_selected_and_point_valid(void *user_data) BOOL object_is_wearable() { - if (!object_selected_and_point_valid(NULL)) + if (!object_selected_and_point_valid(LLSD())) { return FALSE; } @@ -5892,25 +6175,29 @@ BOOL object_is_wearable() // Also for seeing if object can be attached. See above. class LLObjectEnableWear : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool is_wearable = object_selected_and_point_valid(NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(is_wearable); - return TRUE; + return object_selected_and_point_valid(LLSD()); } }; - -BOOL object_attached(void *user_data) +class LLAttachmentPointFilled : public view_listener_t { - LLViewerJointAttachment *attachment = (LLViewerJointAttachment *)user_data; - - return attachment->getObject() != NULL; + bool handleEvent(const LLSD& user_data) + { + bool enable = false; + LLVOAvatar::attachment_map_t::iterator found_it = gAgent.getAvatarObject()->mAttachmentPoints.find(user_data.asInteger()); + if (found_it != gAgent.getAvatarObject()->mAttachmentPoints.end()) +{ + enable = found_it->second->getObject() != NULL; + } + return enable; } +}; class LLAvatarSendIM : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); if(avatar) @@ -5925,7 +6212,6 @@ class LLAvatarSendIM : public view_listener_t name.append( last->getString() ); } - gIMMgr->setFloaterOpen(TRUE); //EInstantMessage type = have_agent_callingcard(gLastHitObjectID) // ? IM_SESSION_ADD : IM_SESSION_CARDLESS_START; gIMMgr->addSession(name, @@ -5936,16 +6222,6 @@ class LLAvatarSendIM : public view_listener_t } }; - -void handle_activate(void*) -{ -} - -BOOL enable_activate(void*) -{ - return FALSE; -} - namespace { struct QueueObjects : public LLSelectedObjectFunctor @@ -5972,7 +6248,7 @@ namespace }; } -void queue_actions(LLFloaterScriptQueue* q, const std::string& noscriptmsg, const std::string& nomodmsg) +void queue_actions(LLFloaterScriptQueue* q, const std::string& msg) { QueueObjects func(q); LLSelectMgr *mgr = LLSelectMgr::getInstance(); @@ -5982,10 +6258,12 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& noscriptmsg, cons { if ( !func.scripted ) { + std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts"; LLNotifications::instance().add(noscriptmsg); } else if ( !func.modifiable ) { + std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission"; LLNotifications::instance().add(nomodmsg); } else @@ -6002,62 +6280,51 @@ void queue_actions(LLFloaterScriptQueue* q, const std::string& noscriptmsg, cons } } -void handle_compile_queue(std::string to_lang) -{ - LLFloaterCompileQueue* queue; - if (to_lang == "mono") - { - queue = LLFloaterCompileQueue::create(TRUE); - } - else - { - queue = LLFloaterCompileQueue::create(FALSE); - } - queue_actions(queue, "CannotRecompileSelectObjectsNoScripts", "CannotRecompileSelectObjectsNoPermission"); -} - -void handle_reset_selection(void) -{ - LLFloaterResetQueue* queue = LLFloaterResetQueue::create(); - queue_actions(queue, "CannotResetSelectObjectsNoScripts", "CannotResetSelectObjectsNoPermission"); -} - -void handle_set_run_selection(void) -{ - LLFloaterRunQueue* queue = LLFloaterRunQueue::create(); - queue_actions(queue, "CannotSetRunningSelectObjectsNoScripts", "CannotSerRunningSelectObjectsNoPermission"); -} - -void handle_set_not_run_selection(void) -{ - LLFloaterNotRunQueue* queue = LLFloaterNotRunQueue::create(); - queue_actions(queue, "CannotSetRunningNotSelectObjectsNoScripts", "CannotSerRunningNotSelectObjectsNoPermission"); -} - class LLToolsSelectedScriptAction : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string action = userdata.asString(); + bool mono = false; + std::string msg, name; if (action == "compile mono") { - handle_compile_queue("mono"); + name = "compile_queue"; + mono = true; + msg = "Recompile"; } if (action == "compile lsl") { - handle_compile_queue("lsl"); + name = "compile_queue"; + msg = "Recompile"; } else if (action == "reset") { - handle_reset_selection(); + name = "reset_queue"; + msg = "Reset"; } else if (action == "start") { - handle_set_run_selection(); + name = "start_queue"; + msg = "Running"; } else if (action == "stop") { - handle_set_not_run_selection(); + name = "stop_queue"; + msg = "RunningNot"; + } + LLUUID id; id.generate(); + + LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance(name, LLSD(id)); + if (queue) + { + queue->setMono(mono); + queue_actions(queue, msg); + } + else + { + llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl; + delete queue; } return true; } @@ -6084,7 +6351,7 @@ void handle_selected_texture_info(void*) { if (!node->isTESelected(i)) continue; - LLViewerImage* img = node->getObject()->getTEImage(i); + LLViewerTexture* img = node->getObject()->getTEImage(i); LLUUID image_id = img->getID(); faces_per_texture[image_id].push_back(i); } @@ -6094,7 +6361,7 @@ void handle_selected_texture_info(void*) { LLUUID image_id = it->first; U8 te = it->second[0]; - LLViewerImage* img = node->getObject()->getTEImage(te); + LLViewerTexture* img = node->getObject()->getTEImage(te); S32 height = img->getHeight(); S32 width = img->getWidth(); S32 components = img->getComponents(); @@ -6112,11 +6379,6 @@ void handle_selected_texture_info(void*) } } -void handle_dump_image_list(void*) -{ - gImageList.dump(); -} - void handle_test_male(void*) { wear_outfit_by_name("Male Shape & Outfit"); @@ -6167,107 +6429,76 @@ void handle_dump_attachments(void*) } } -//--------------------------------------------------------------------- -// Callbacks for enabling/disabling items -//--------------------------------------------------------------------- - -BOOL menu_ui_enabled(void *user_data) -{ - BOOL high_res = gSavedSettings.getBOOL( "HighResSnapshot" ); - return !high_res; -} - -// TomY TODO DEPRECATE & REMOVE -void menu_toggle_control( void* user_data ) -{ - BOOL checked = gSavedSettings.getBOOL( static_cast(user_data) ); - if (std::string(static_cast(user_data)) == "HighResSnapshot" && !checked) - { - // High Res Snapshot active, must uncheck RenderUIInSnapshot - gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE ); - } - gSavedSettings.setBOOL( static_cast(user_data), !checked ); -} - // these are used in the gl menus to set control values. class LLToggleControl : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string control_name = userdata.asString(); BOOL checked = gSavedSettings.getBOOL( control_name ); - if (control_name == "HighResSnapshot" && !checked) - { - // High Res Snapshot active, must uncheck RenderUIInSnapshot - gSavedSettings.setBOOL( "RenderUIInSnapshot", FALSE ); - } gSavedSettings.setBOOL( control_name, !checked ); return true; } }; -BOOL menu_check_control( void* user_data) +class LLCheckControl : public view_listener_t { - return gSavedSettings.getBOOL((char*)user_data); + bool handleEvent( const LLSD& userdata) + { + std::string callback_data = userdata.asString(); + bool new_value = gSavedSettings.getBOOL(callback_data); + return new_value; } -// -void menu_toggle_variable( void* user_data ) -{ - BOOL checked = *(BOOL*)user_data; - *(BOOL*)user_data = !checked; -} - -BOOL menu_check_variable( void* user_data) -{ - return *(BOOL*)user_data; -} - - -BOOL enable_land_selected( void* ) -{ - return !(LLViewerParcelMgr::getInstance()->selectionEmpty()); -} +}; void menu_toggle_attached_lights(void* user_data) { - menu_toggle_control(user_data); LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights"); } void menu_toggle_attached_particles(void* user_data) { - menu_toggle_control(user_data); LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles"); } +class LLAdvancedHandleAttchedLightParticles: public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string control_name = userdata.asString(); + if (control_name == "RenderAttachedLights") +{ + menu_toggle_attached_lights(NULL); +} + else if (control_name == "RenderAttachedParticles") +{ + menu_toggle_attached_particles(NULL); +} + return true; +} +}; + class LLSomethingSelected : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLSomethingSelectedNoHUD : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; -BOOL enable_more_than_one_selected(void* ) -{ - return (LLSelectMgr::getInstance()->getSelection()->getObjectCount() > 1); -} - static bool is_editable_selected() { return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL); @@ -6275,106 +6506,62 @@ static bool is_editable_selected() class LLEditableSelected : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - gMenuHolder->findControl(userdata["control"].asString())->setValue(is_editable_selected()); - return true; + return is_editable_selected(); } }; class LLEditableSelectedMono : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { + bool new_value = false; LLViewerRegion* region = gAgent.getRegion(); - if(region && gMenuHolder && gMenuHolder->findControl(userdata["control"].asString())) + if(region && gMenuHolder) { bool have_cap = (! region->getCapability("UpdateScriptTask").empty()); - bool selected = is_editable_selected() && have_cap; - gMenuHolder->findControl(userdata["control"].asString())->setValue(selected); - return true; + new_value = is_editable_selected() && have_cap; } - return false; + return new_value; } }; class LLToolsEnableTakeCopy : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool all_valid = false; if (LLSelectMgr::getInstance()) { if (!LLSelectMgr::getInstance()->getSelection()->isEmpty()) { - all_valid = true; + all_valid = true; #ifndef HACKED_GODLIKE_VIEWER # ifdef TOGGLE_HACKED_GODLIKE_VIEWER - if (LLViewerLogin::getInstance()->isInProductionGrid() - || !gAgent.isGodlike()) + if (LLViewerLogin::getInstance()->isInProductionGrid() + || !gAgent.isGodlike()) # endif + { + struct f : public LLSelectedObjectFunctor { - struct f : public LLSelectedObjectFunctor + virtual bool apply(LLViewerObject* obj) { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permCopy() || obj->isAttachment()); - } - } func; - const bool firstonly = true; - bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - all_valid = !any_invalid; - } -#endif // HACKED_GODLIKE_VIEWER + return (!obj->permCopy() || obj->isAttachment()); + } + } func; + const bool firstonly = true; + bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); + all_valid = !any_invalid; } +#endif // HACKED_GODLIKE_VIEWER + } } - gMenuHolder->findControl(userdata["control"].asString())->setValue(all_valid); - return true; + return all_valid; } }; -BOOL enable_selection_you_own_all(void*) -{ - if (LLSelectMgr::getInstance()) - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (!obj->permYouOwner()); - } - } func; - const bool firstonly = true; - bool no_perms = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - if (no_perms) - { - return FALSE; - } - } - return TRUE; -} - -BOOL enable_selection_you_own_one(void*) -{ - if (LLSelectMgr::getInstance()) - { - struct f : public LLSelectedObjectFunctor - { - virtual bool apply(LLViewerObject* obj) - { - return (obj->permYouOwner()); - } - } func; - const bool firstonly = true; - bool any_perms = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly); - if (!any_perms) - { - return FALSE; - } - } - return TRUE; -} class LLHasAsset : public LLInventoryCollectFunctor { @@ -6436,6 +6623,15 @@ BOOL enable_save_into_inventory(void*) return FALSE; } +class LLToolsEnableSaveToInventory : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + bool new_value = enable_save_into_inventory(NULL); + return new_value; + } +}; + BOOL enable_save_into_task_inventory(void*) { LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode(); @@ -6453,101 +6649,63 @@ BOOL enable_save_into_task_inventory(void*) class LLToolsEnableSaveToObjectInventory : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = enable_save_into_task_inventory(NULL); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; -BOOL enable_not_thirdperson(void*) -{ - return !gAgent.cameraThirdPerson(); -} - - -// BOOL enable_export_selected(void *) -// { -// if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) -// { -// return FALSE; -// } -// if (!gExporterRequestID.isNull()) -// { -// return FALSE; -// } -// if (!LLUploadDialog::modalUploadIsFinished()) -// { -// return FALSE; -// } -// return TRUE; -// } class LLViewEnableMouselook : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // You can't go directly from customize avatar to mouselook. // TODO: write code with appropriate dialogs to handle this transition. bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgent.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime")); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLToolsEnableToolNotPie : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() ); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLWorldEnableCreateLandmark : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - bool new_value = can_create_landmark(); - - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - - return true; + return !LLLandmarkActions::landmarkAlreadyExists(); } }; class LLWorldEnableSetHomeLocation : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = gAgent.isGodlike() || (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLWorldEnableTeleportHome : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLViewerRegion* regionp = gAgent.getRegion(); bool agent_on_prelude = (regionp && regionp->isPrelude()); bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude; - gMenuHolder->findControl(userdata["control"].asString())->setValue(enable_teleport_home); - return true; + return enable_teleport_home; } }; -BOOL enable_region_owner(void*) -{ - if(gAgent.getRegion() && gAgent.getRegion()->getOwner() == gAgent.getID()) - return TRUE; - return enable_god_customer_service(NULL); -} - BOOL enable_god_full(void*) { return gAgent.getGodLevel() >= GOD_FULL; @@ -6568,18 +6726,6 @@ BOOL enable_god_basic(void*) return gAgent.getGodLevel() > GOD_NOT; } -#if 0 // 1.9.2 -void toggle_vertex_shaders(void *) -{ - BOOL use_shaders = gPipeline.getUseVertexShaders(); - gPipeline.setUseVertexShaders(use_shaders); -} - -BOOL check_vertex_shaders(void *) -{ - return gPipeline.getUseVertexShaders(); -} -#endif void toggle_show_xui_names(void *) { @@ -6594,18 +6740,9 @@ BOOL check_show_xui_names(void *) return gSavedSettings.getBOOL("ShowXUINames"); } - - -void toggle_cull_small(void *) -{ -// gPipeline.mCullBySize = !gPipeline.mCullBySize; -// -// gSavedSettings.setBOOL("RenderCullBySize", gPipeline.mCullBySize); -} - class LLToolsSelectOnlyMyObjects : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly"); @@ -6617,7 +6754,7 @@ class LLToolsSelectOnlyMyObjects : public view_listener_t class LLToolsSelectOnlyMovableObjects : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly"); @@ -6629,7 +6766,7 @@ class LLToolsSelectOnlyMovableObjects : public view_listener_t class LLToolsSelectBySurrounding : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive; @@ -6640,7 +6777,7 @@ class LLToolsSelectBySurrounding : public view_listener_t class LLToolsShowHiddenSelection : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // TomY TODO Merge these LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections; @@ -6652,7 +6789,7 @@ class LLToolsShowHiddenSelection : public view_listener_t class LLToolsShowSelectionLightRadius : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { // TomY TODO merge these LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius; @@ -6664,7 +6801,7 @@ class LLToolsShowSelectionLightRadius : public view_listener_t class LLToolsEditLinkedParts : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { BOOL select_individuals = gSavedSettings.getBOOL("EditLinkedParts"); if (select_individuals) @@ -6679,40 +6816,14 @@ class LLToolsEditLinkedParts : public view_listener_t } }; -void reload_personal_settings_overrides(void *) -{ - llinfos << "Loading overrides from " << gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml") << llendl; - - gSavedSettings.loadFromFile(gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,"overrides.xml")); -} - void reload_vertex_shader(void *) { //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP } -void slow_mo_animations(void*) -{ - static BOOL slow_mo = FALSE; - if (slow_mo) - { - gAgent.getAvatarObject()->setAnimTimeFactor(1.f); - slow_mo = FALSE; - } - else - { - gAgent.getAvatarObject()->setAnimTimeFactor(0.2f); - slow_mo = TRUE; - } -} - void handle_dump_avatar_local_textures(void*) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); - if( avatar ) - { - avatar->dumpLocalTextures(); - } + gAgent.getAvatarObject()->dumpLocalTextures(); } void handle_debug_avatar_textures(void*) @@ -6720,14 +6831,14 @@ void handle_debug_avatar_textures(void*) LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject(); if (objectp) { - LLFloaterAvatarTextures::show(objectp->getID()); + LLFloaterReg::showInstance( "avatar_tetures", LLSD(objectp->getID()) ); } } void handle_grab_texture(void* data) { ETextureIndex index = (ETextureIndex)((intptr_t)data); - LLVOAvatar* avatar = gAgent.getAvatarObject(); + const LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if ( avatar ) { const LLUUID& asset_id = avatar->grabLocalTexture(index); @@ -6737,32 +6848,14 @@ void handle_grab_texture(void* data) LLUUID folder_id(gInventory.findCategoryUUIDForType(asset_type)); if(folder_id.notNull()) { - std::string name = "Baked "; - switch (index) + std::string name = "Unknown"; + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); + if (texture_dict->mIsBakedTexture) { - case TEX_EYES_BAKED: - name.append("Iris"); - break; - case TEX_HEAD_BAKED: - name.append("Head"); - break; - case TEX_UPPER_BAKED: - name.append("Upper Body"); - break; - case TEX_LOWER_BAKED: - name.append("Lower Body"); - break; - case TEX_SKIRT_BAKED: - name.append("Skirt"); - break; - case TEX_HAIR_BAKED: - name.append("Hair"); - break; - default: - name.append("Unknown"); - break; + EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mNameCapitalized; } - name.append(" Texture"); + name += " Texture"; LLUUID item_id; item_id.generate(); @@ -6795,17 +6888,17 @@ void handle_grab_texture(void* data) gInventory.updateItem(item); gInventory.notifyObservers(); - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); // Show the preview panel for textures to let // user know that the image is now in inventory. if(view) { - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); view->getPanel()->setSelection(item_id, TAKE_FOCUS_NO); view->getPanel()->openSelected(); - //LLInventoryView::dumpSelectionInformation((void*)view); + //LLFloaterInventory::dumpSelectionInformation((void*)view); // restore keyboard focus gFocusMgr.setKeyboardFocus(focus_ctrl); } @@ -6820,7 +6913,7 @@ void handle_grab_texture(void* data) BOOL enable_grab_texture(void* data) { ETextureIndex index = (ETextureIndex)((intptr_t)data); - LLVOAvatar* avatar = gAgent.getAvatarObject(); + const LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if ( avatar ) { return avatar->canGrabLocalTexture(index); @@ -6842,8 +6935,7 @@ LLVOAvatar* find_avatar_from_object( LLViewerObject* object ) } while( object && !object->isAvatar() ); } - else - if( !object->isAvatar() ) + else if( !object->isAvatar() ) { object = NULL; } @@ -6898,7 +6990,7 @@ void force_error_driver_crash(void *) class LLToolsUseSelectionForGrid : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLSelectMgr::getInstance()->clearGridObjects(); struct f : public LLSelectedObjectFunctor @@ -6931,10 +7023,6 @@ void handle_test_load_url(void*) // LLViewerMenuHolderGL // -LLViewerMenuHolderGL::LLViewerMenuHolderGL() : LLMenuHolderGL() -{ -} - BOOL LLViewerMenuHolderGL::hideMenus() { BOOL handled = LLMenuHolderGL::hideMenus(); @@ -6998,20 +7086,14 @@ void handle_load_from_xml(void*) if (picker.getOpenFile(LLFilePicker::FFLOAD_XML)) { std::string filename = picker.getFirstFile(); - LLFloater* floater = new LLFloater("sample_floater"); - LLUICtrlFactory::getInstance()->buildFloater(floater, filename); + LLFloater* floater = new LLFloater(LLSD()); + LLUICtrlFactory::getInstance()->buildFloater(floater, filename, NULL); } } void handle_web_browser_test(void*) { - const bool open_links_externally = false; - const bool open_app_slurls = true; - LLFloaterHtml::getInstance()->show( - "http://secondlife.com/app/search/slurls.html", - "Web Browser Test", - open_links_externally, - open_app_slurls); + LLWeb::loadURL("http://secondlife.com/app/search/slurls.html"); } void handle_buy_currency_test(void*) @@ -7025,7 +7107,7 @@ void handle_buy_currency_test(void*) // *TODO: Replace with call to LLUI::getLanguage() after windows-setup // branch merges in. JC - std::string language = "en-us"; + std::string language = "en"; language = gSavedSettings.getString("Language"); if (language.empty() || language == "default") { @@ -7037,7 +7119,7 @@ void handle_buy_currency_test(void*) } if (language.empty() || language == "default") { - language = "en-us"; + language = "en"; } replace["[LANGUAGE]"] = language; @@ -7045,15 +7127,12 @@ void handle_buy_currency_test(void*) llinfos << "buy currency url " << url << llendl; - LLFloaterHtmlCurrency* floater = LLFloaterHtmlCurrency::showInstance(url); - // Needed so we can use secondlife:///app/floater/self/close SLURLs - floater->setTrusted(true); - floater->center(); + LLFloaterReg::showInstance("buy_currency_html", LLSD(url)); } void handle_rebake_textures(void*) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if (!avatar) return; // Slam pending upload count to "unstick" things @@ -7076,7 +7155,7 @@ BOOL get_visibility(void* user_data) // TomY TODO: Get rid of these? class LLViewShowHoverTips : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLHoverView::sShowHoverTips = !LLHoverView::sShowHoverTips; return true; @@ -7085,18 +7164,17 @@ class LLViewShowHoverTips : public view_listener_t class LLViewCheckShowHoverTips : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLHoverView::sShowHoverTips; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; // TomY TODO: Get rid of these? class LLViewHighlightTransparent : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha; return true; @@ -7105,17 +7183,157 @@ class LLViewHighlightTransparent : public view_listener_t class LLViewCheckHighlightTransparent : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLDrawPoolAlpha::sShowDebugAlpha; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); + return new_value; + } +}; + +class LLViewBeaconWidth : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string width = userdata.asString(); + if(width == "1") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 1); + } + else if(width == "4") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 4); + } + else if(width == "16") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 16); + } + else if(width == "32") + { + gSavedSettings.setS32("DebugBeaconLineWidth", 32); + } + return true; } }; + +class LLViewToggleBeacon : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + if (beacon == "scriptsbeacon") + { + LLPipeline::toggleRenderScriptedBeacons(NULL); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL)) + { + LLPipeline::toggleRenderScriptedTouchBeacons(NULL); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) ); + } + } + else if (beacon == "physicalbeacon") + { + LLPipeline::toggleRenderPhysicalBeacons(NULL); + gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) ); + } + else if (beacon == "soundsbeacon") + { + LLPipeline::toggleRenderSoundBeacons(NULL); + gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons(NULL) ); + } + else if (beacon == "particlesbeacon") + { + LLPipeline::toggleRenderParticleBeacons(NULL); + gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons(NULL) ); + } + else if (beacon == "scripttouchbeacon") + { + LLPipeline::toggleRenderScriptedTouchBeacons(NULL); + gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) ); + // toggle the other one off if it's on + if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL)) + { + LLPipeline::toggleRenderScriptedBeacons(NULL); + gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) ); + } + } + else if (beacon == "renderbeacons") + { + LLPipeline::toggleRenderBeacons(NULL); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL)) + { + LLPipeline::toggleRenderHighlights(NULL); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) ); + } + } + else if (beacon == "renderhighlights") + { + LLPipeline::toggleRenderHighlights(NULL); + gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) ); + // toggle the other one on if it's not + if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL)) + { + LLPipeline::toggleRenderBeacons(NULL); + gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) ); + } + } + + return true; + } +}; + +class LLViewCheckBeaconEnabled : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + std::string beacon = userdata.asString(); + bool new_value = false; + if (beacon == "scriptsbeacon") + { + new_value = gSavedSettings.getBOOL( "scriptsbeacon"); + LLPipeline::setRenderScriptedBeacons(new_value); + } + else if (beacon == "physicalbeacon") + { + new_value = gSavedSettings.getBOOL( "physicalbeacon"); + LLPipeline::setRenderPhysicalBeacons(new_value); + } + else if (beacon == "soundsbeacon") + { + new_value = gSavedSettings.getBOOL( "soundsbeacon"); + LLPipeline::setRenderSoundBeacons(new_value); + } + else if (beacon == "particlesbeacon") + { + new_value = gSavedSettings.getBOOL( "particlesbeacon"); + LLPipeline::setRenderParticleBeacons(new_value); + } + else if (beacon == "scripttouchbeacon") + { + new_value = gSavedSettings.getBOOL( "scripttouchbeacon"); + LLPipeline::setRenderScriptedTouchBeacons(new_value); + } + else if (beacon == "renderbeacons") + { + new_value = gSavedSettings.getBOOL( "renderbeacons"); + LLPipeline::setRenderBeacons(new_value); + } + else if (beacon == "renderhighlights") + { + new_value = gSavedSettings.getBOOL( "renderhighlights"); + LLPipeline::setRenderHighlights(new_value); + } + return new_value; + } +}; + class LLViewToggleRenderType : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string type = userdata.asString(); if (type == "hideparticles") @@ -7128,22 +7346,21 @@ class LLViewToggleRenderType : public view_listener_t class LLViewCheckRenderType : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - std::string type = userdata["data"].asString(); + std::string type = userdata.asString(); bool new_value = false; if (type == "hideparticles") { new_value = LLPipeline::toggleRenderTypeControlNegated((void *)LLPipeline::RENDER_TYPE_PARTICLES); } - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLViewShowHUDAttachments : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments; return true; @@ -7152,123 +7369,127 @@ class LLViewShowHUDAttachments : public view_listener_t class LLViewCheckHUDAttachments : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = LLPipeline::sShowHUDAttachments; - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLEditEnableTakeOff : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - std::string control_name = userdata["control"].asString(); - std::string clothing = userdata["data"].asString(); + std::string clothing = userdata.asString(); bool new_value = false; if (clothing == "shirt") { - new_value = LLAgent::selfHasWearable((void *)WT_SHIRT); + new_value = LLAgentWearables::selfHasWearable(WT_SHIRT); } if (clothing == "pants") { - new_value = LLAgent::selfHasWearable((void *)WT_PANTS); + new_value = LLAgentWearables::selfHasWearable(WT_PANTS); } if (clothing == "shoes") { - new_value = LLAgent::selfHasWearable((void *)WT_SHOES); + new_value = LLAgentWearables::selfHasWearable(WT_SHOES); } if (clothing == "socks") { - new_value = LLAgent::selfHasWearable((void *)WT_SOCKS); + new_value = LLAgentWearables::selfHasWearable(WT_SOCKS); } if (clothing == "jacket") { - new_value = LLAgent::selfHasWearable((void *)WT_JACKET); + new_value = LLAgentWearables::selfHasWearable(WT_JACKET); } if (clothing == "gloves") { - new_value = LLAgent::selfHasWearable((void *)WT_GLOVES); + new_value = LLAgentWearables::selfHasWearable(WT_GLOVES); } if (clothing == "undershirt") { - new_value = LLAgent::selfHasWearable((void *)WT_UNDERSHIRT); + new_value = LLAgentWearables::selfHasWearable(WT_UNDERSHIRT); } if (clothing == "underpants") { - new_value = LLAgent::selfHasWearable((void *)WT_UNDERPANTS); + new_value = LLAgentWearables::selfHasWearable(WT_UNDERPANTS); } if (clothing == "skirt") { - new_value = LLAgent::selfHasWearable((void *)WT_SKIRT); + new_value = LLAgentWearables::selfHasWearable(WT_SKIRT); } - gMenuHolder->findControl(control_name)->setValue(new_value); - return true; + if (clothing == "alpha") + { + new_value = LLAgentWearables::selfHasWearable(WT_ALPHA); + } + if (clothing == "tattoo") + { + new_value = LLAgentWearables::selfHasWearable(WT_TATTOO); + } + return new_value; } }; class LLEditTakeOff : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string clothing = userdata.asString(); if (clothing == "shirt") { - LLAgent::userRemoveWearable((void*)WT_SHIRT); + LLAgentWearables::userRemoveWearable((void*)WT_SHIRT); } else if (clothing == "pants") { - LLAgent::userRemoveWearable((void*)WT_PANTS); + LLAgentWearables::userRemoveWearable((void*)WT_PANTS); } else if (clothing == "shoes") { - LLAgent::userRemoveWearable((void*)WT_SHOES); + LLAgentWearables::userRemoveWearable((void*)WT_SHOES); } else if (clothing == "socks") { - LLAgent::userRemoveWearable((void*)WT_SOCKS); + LLAgentWearables::userRemoveWearable((void*)WT_SOCKS); } else if (clothing == "jacket") { - LLAgent::userRemoveWearable((void*)WT_JACKET); + LLAgentWearables::userRemoveWearable((void*)WT_JACKET); } else if (clothing == "gloves") { - LLAgent::userRemoveWearable((void*)WT_GLOVES); + LLAgentWearables::userRemoveWearable((void*)WT_GLOVES); } else if (clothing == "undershirt") { - LLAgent::userRemoveWearable((void*)WT_UNDERSHIRT); + LLAgentWearables::userRemoveWearable((void*)WT_UNDERSHIRT); } else if (clothing == "underpants") { - LLAgent::userRemoveWearable((void*)WT_UNDERPANTS); + LLAgentWearables::userRemoveWearable((void*)WT_UNDERPANTS); } else if (clothing == "skirt") { - LLAgent::userRemoveWearable((void*)WT_SKIRT); + LLAgentWearables::userRemoveWearable((void*)WT_SKIRT); + } + else if (clothing == "alpha") + { + LLAgentWearables::userRemoveWearable((void*)WT_ALPHA); + } + else if (clothing == "tattoo") + { + LLAgentWearables::userRemoveWearable((void*)WT_TATTOO); } else if (clothing == "all") { - LLAgent::userRemoveAllClothes(NULL); + LLAgentWearables::userRemoveAllClothes(NULL); } return true; } }; -class LLWorldChat : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - handle_chat(NULL); - return true; - } -}; - class LLToolsSelectTool : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string tool_name = userdata.asString(); if (tool_name == "focus") @@ -7298,7 +7519,7 @@ class LLToolsSelectTool : public view_listener_t /// WINDLIGHT callbacks class LLWorldEnvSettings : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string tod = userdata.asString(); LLVector3 sun_direction; @@ -7306,16 +7527,7 @@ class LLWorldEnvSettings : public view_listener_t if (tod == "editor") { // if not there or is hidden, show it - if( !LLFloaterEnvSettings::isOpen() || - !LLFloaterEnvSettings::instance()->getVisible()) { - LLFloaterEnvSettings::show(); - - // otherwise, close it button acts like a toggle - } - else - { - LLFloaterEnvSettings::instance()->close(); - } + LLFloaterReg::toggleInstance("env_settings"); return true; } @@ -7375,19 +7587,9 @@ class LLWorldEnvSettings : public view_listener_t /// Water Menu callbacks class LLWorldWaterSettings : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - // if not there or is hidden, show it - if( !LLFloaterWater::isOpen() || - !LLFloaterWater::instance()->getVisible()) { - LLFloaterWater::show(); - - // otherwise, close it button acts like a toggle - } - else - { - LLFloaterWater::instance()->close(); - } + LLFloaterReg::toggleInstance("env_water"); return true; } }; @@ -7395,9 +7597,9 @@ class LLWorldWaterSettings : public view_listener_t /// Post-Process callbacks class LLWorldPostProcess : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - LLFloaterPostProcess::show(); + LLFloaterReg::showInstance("env_post_process"); return true; } }; @@ -7405,20 +7607,30 @@ class LLWorldPostProcess : public view_listener_t /// Day Cycle callbacks class LLWorldDayCycle : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { - LLFloaterDayCycle::show(); + LLFloaterReg::showInstance("env_day_cycle"); return true; } }; - - -static void addMenu(view_listener_t *menu, const std::string& name) +/// Show First Time Tips calbacks +class LLHelpCheckShowFirstTimeTip : public view_listener_t { - sMenus.push_back(menu); - menu->registerListener(gMenuHolder, name); -} + bool handleEvent(const LLSD& userdata) + { + return LLFirstTimeTipsManager::tipsEnabled(); + } +}; + +class LLHelpShowFirstTimeTip : public view_listener_t +{ + bool handleEvent(const LLSD& userdata) + { + LLFirstTimeTipsManager::enabledTip(!userdata.asBoolean()); + return true; + } +}; void initialize_menus() { @@ -7428,7 +7640,7 @@ void initialize_menus() public: // The "mult" parameter says whether "val" is a multiplier or used to set the value. LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {} - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal; LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad); @@ -7440,217 +7652,381 @@ void initialize_menus() bool mMult; }; - class LLAvatarReportAbuse : public view_listener_t - { - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() ); - if(avatar) - { - LLFloaterReporter::showFromObject(avatar->getID()); - } - return true; - } - }; + LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar(); + LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar(); + + // Enable God Mode + view_listener_t::addMenu(new LLEnableGodCustomerService(), "EnableGodCustomerService"); + + // Agent + commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying)); + enable.add("Agent.emableFlying", boost::bind(&LLAgent::enableFlying)); // File menu init_menu_file(); // Edit menu - addMenu(new LLEditUndo(), "Edit.Undo"); - addMenu(new LLEditRedo(), "Edit.Redo"); - addMenu(new LLEditCut(), "Edit.Cut"); - addMenu(new LLEditCopy(), "Edit.Copy"); - addMenu(new LLEditPaste(), "Edit.Paste"); - addMenu(new LLEditDelete(), "Edit.Delete"); - addMenu(new LLEditSearch(), "Edit.Search"); - addMenu(new LLEditSelectAll(), "Edit.SelectAll"); - addMenu(new LLEditDeselect(), "Edit.Deselect"); - addMenu(new LLEditDuplicate(), "Edit.Duplicate"); - addMenu(new LLEditTakeOff(), "Edit.TakeOff"); + view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo"); + view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo"); + view_listener_t::addMenu(new LLEditCut(), "Edit.Cut"); + view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy"); + view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste"); + view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete"); + view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll"); + view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect"); + view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate"); + view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff"); - addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); - addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); - addMenu(new LLEditEnableCut(), "Edit.EnableCut"); - addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); - addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); - addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); - addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); - addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); - addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate"); - addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); - addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); + view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo"); + view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo"); + view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut"); + view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy"); + view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste"); + view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete"); + view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll"); + view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect"); + view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate"); + view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff"); + view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar"); // View menu - addMenu(new LLViewMouselook(), "View.Mouselook"); - addMenu(new LLViewBuildMode(), "View.BuildMode"); - addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); - addMenu(new LLViewCommunicate(), "View.Communicate"); - addMenu(new LLViewResetView(), "View.ResetView"); - addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); - addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); - addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); - addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); - addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); - addMenu(new LLZoomer(1.2f), "View.ZoomOut"); - addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); - addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); - addMenu(new LLViewFullscreen(), "View.Fullscreen"); - addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); + view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook"); + view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam"); + view_listener_t::addMenu(new LLViewResetView(), "View.ResetView"); + view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter"); + view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips"); + view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent"); + view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType"); + view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments"); + view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut"); + view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn"); + view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault"); + view_listener_t::addMenu(new LLViewFullscreen(), "View.Fullscreen"); + view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize"); - addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); - addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); - addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); + view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook"); + view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam"); + view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter"); - addMenu(new LLViewCheckBuildMode(), "View.CheckBuildMode"); - addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); - addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); - addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); - addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); - addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); + view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam"); + view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips"); + view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent"); + view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType"); + view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments"); // World menu - addMenu(new LLWorldChat(), "World.Chat"); - addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); - addMenu(new LLWorldFly(), "World.Fly"); - addMenu(new LLWorldEnableFly(), "World.EnableFly"); - addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); - addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); - addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); - addMenu(new LLWorldSetAway(), "World.SetAway"); - addMenu(new LLWorldSetBusy(), "World.SetBusy"); + commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL)); + view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun"); + view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark"); + view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation"); + view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome"); + view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway"); + view_listener_t::addMenu(new LLWorldSetBusy(), "World.SetBusy"); - addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); - addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); - addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); - addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); + view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark"); + view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation"); + view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome"); + view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand"); - addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); + view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun"); - (new LLWorldEnvSettings())->registerListener(gMenuHolder, "World.EnvSettings"); - (new LLWorldWaterSettings())->registerListener(gMenuHolder, "World.WaterSettings"); - (new LLWorldPostProcess())->registerListener(gMenuHolder, "World.PostProcess"); - (new LLWorldDayCycle())->registerListener(gMenuHolder, "World.DayCycle"); + view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings"); + view_listener_t::addMenu(new LLWorldWaterSettings(), "World.WaterSettings"); + view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess"); + view_listener_t::addMenu(new LLWorldDayCycle(), "World.DayCycle"); + + view_listener_t::addMenu(new LLHelpCheckShowFirstTimeTip(), "Help.CheckShowFirstTimeTip"); + view_listener_t::addMenu(new LLHelpShowFirstTimeTip(), "Help.ShowQuickTips"); // Tools menu - addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); - addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); - addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); - addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); - addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); - addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); - addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); - addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); - addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); - addMenu(new LLToolsLink(), "Tools.Link"); - addMenu(new LLToolsUnlink(), "Tools.Unlink"); - addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); - addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); - addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); - addMenu(new LLToolsLookAtSelection(), "Tools.LookAtSelection"); - addMenu(new LLToolsBuyOrTake(), "Tools.BuyOrTake"); - addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy"); - addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); - addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); + view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool"); + view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects"); + view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects"); + view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding"); + view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection"); + view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius"); + view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts"); + view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY"); + view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid"); + view_listener_t::addMenu(new LLToolsLink(), "Tools.Link"); + view_listener_t::addMenu(new LLToolsUnlink(), "Tools.Unlink"); + view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations"); + view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys"); + view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys"); + view_listener_t::addMenu(new LLToolsLookAtSelection(), "Tools.LookAtSelection"); + view_listener_t::addMenu(new LLToolsBuyOrTake(), "Tools.BuyOrTake"); + view_listener_t::addMenu(new LLToolsTakeCopy(), "Tools.TakeCopy"); + view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory"); + view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction"); - addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); - addMenu(new LLToolsEnableLink(), "Tools.EnableLink"); - addMenu(new LLToolsEnableUnlink(), "Tools.EnableUnlink"); - addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); - addMenu(new LLToolsEnableTakeCopy(), "Tools.EnableTakeCopy"); - addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); + view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie"); + view_listener_t::addMenu(new LLToolsEnableLink(), "Tools.EnableLink"); + view_listener_t::addMenu(new LLToolsEnableUnlink(), "Tools.EnableUnlink"); + view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake"); + view_listener_t::addMenu(new LLToolsEnableTakeCopy(), "Tools.EnableTakeCopy"); + view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory"); + view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory"); - /*addMenu(new LLToolsVisibleBuyObject(), "Tools.VisibleBuyObject"); - addMenu(new LLToolsVisibleTakeObject(), "Tools.VisibleTakeObject");*/ + /*view_listener_t::addMenu(new LLToolsVisibleBuyObject(), "Tools.VisibleBuyObject"); + view_listener_t::addMenu(new LLToolsVisibleTakeObject(), "Tools.VisibleTakeObject");*/ // Help menu // most items use the ShowFloater method - // Self pie menu - addMenu(new LLSelfStandUp(), "Self.StandUp"); - addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); + // Advance menu + view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole"); + view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole"); + view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole"); + // Advanced > HUD Info + view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo"); + view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo"); - addMenu(new LLSelfEnableStandUp(), "Self.EnableStandUp"); - addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); + // Advanced Other Settings + view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache"); + + // Advanced > Render > Types + view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType"); + view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType"); + + //// Advanced > Render > Features + view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature"); + view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature"); + // Advanced > Render > Info Displays + view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay"); + view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo"); + view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe"); + view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe"); + view_listener_t::addMenu(new LLAdvancedToggleDisableTextures(), "Advanced.ToggleDisableTextures"); + view_listener_t::addMenu(new LLAdvancedCheckDisableTextures(), "Advanced.CheckDisableTextures"); + view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion"); + view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate"); + view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame"); + view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest"); + view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest"); + view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest"); + view_listener_t::addMenu(new LLAdvancedHandleAttchedLightParticles(), "Advanced.HandleAttchedLightParticles"); + + + #ifdef TOGGLE_HACKED_GODLIKE_VIEWER + view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode"); + view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode"); + #endif + + // Advanced > World + view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera"); + view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache"); + + // Advanced > UI + view_listener_t::addMenu(new LLAdvancedWebBrowserTest(), "Advanced.WebBrowserTest"); + view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest"); + view_listener_t::addMenu(new LLAdvancedToggleEditableUI(), "Advanced.ToggleEditableUI"); + view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr"); + view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory"); + view_listener_t::addMenu(new LLAdvancedDumpFocusHolder(), "Advanced.DumpFocusHolder"); + view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo"); + view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo"); + view_listener_t::addMenu(new LLAdvancedPrintTextureMemoryStats(), "Advanced.PrintTextureMemoryStats"); + view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks"); + view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews"); + view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews"); + view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips"); + view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents"); + view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys"); + view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys"); + view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc"); + view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc"); + + + // Advanced > XUI + commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance())); + view_listener_t::addMenu(new LLAdvancedLoadUIFromXML(), "Advanced.LoadUIFromXML"); + view_listener_t::addMenu(new LLAdvancedSaveUIToXML(), "Advanced.SaveUIToXML"); + view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames"); + view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames"); + view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs"); + view_listener_t::addMenu(new LLAdvancedAvatarInspector(), "Advanced.AvatarInspector"); + + // Advanced > Character > Grab Baked Texture + view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture"); + view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture"); + + // Advanced > Character > Character Tests + view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML"); + view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry"); + + view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale"); + view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale"); + view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG"); + + // Advanced > Character (toplevel) + view_listener_t::addMenu(new LLAdvancedToggleAllowTapTapHoldRun(), "Advanced.ToggleAllowTapTapHoldRun"); + view_listener_t::addMenu(new LLAdvancedCheckAllowTapTapHoldRun(), "Advanced.CheckAllowTapTapHoldRun"); + view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault"); + view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader"); + view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo"); + view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt"); + view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt"); + view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt"); + view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates"); + view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD"); + view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD"); + view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis"); + view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments"); + view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures"); + #ifndef LL_RELEASE_FOR_DOWNLOAD + view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures"); + view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures"); + #endif + // Advanced > Network + view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog"); + view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket"); + + // Advanced > Recorder + view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot"); + view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop"); + view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop"); + + // Advanced > Debugging + view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint"); + view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror"); + view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess"); + view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop"); + view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException"); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash"); + view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDisconnectViewer"); + + // Advanced (toplevel) + view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates"); + view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage"); + view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings"); + view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions"); + view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus"); + view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus"); + + + // Admin >Object + view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf"); + view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive"); + view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete"); + view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock"); + view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs"); + + // Admin >Parcel + view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe"); + view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent"); + view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand"); + + // Admin >Region + view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData"); + // Admin top level + view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState"); + + // Self pie menu + view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp"); + view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments"); + + view_listener_t::addMenu(new LLSelfEnableStandUp(), "Self.EnableStandUp"); + view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments"); + + // we don't use boost::bind directly to delay side tray construction + view_listener_t::addMenu(new LLSelfFriends(), "Self.Friends"); + view_listener_t::addMenu(new LLSelfGroups(), "Self.Groups"); // Avatar pie menu - addMenu(new LLObjectMute(), "Avatar.Mute"); - addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); - addMenu(new LLAvatarFreeze(), "Avatar.Freeze"); - addMenu(new LLAvatarDebug(), "Avatar.Debug"); - addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); - addMenu(new LLAvatarEnableDebug(), "Avatar.EnableDebug"); - addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); - addMenu(new LLAvatarGiveCard(), "Avatar.GiveCard"); - addMenu(new LLAvatarEject(), "Avatar.Eject"); - addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); - addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); + view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute"); + view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend"); + view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact"); + view_listener_t::addMenu(new LLAvatarFreeze(), "Avatar.Freeze"); + view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug"); + view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug"); + view_listener_t::addMenu(new LLAvatarEnableDebug(), "Avatar.EnableDebug"); + view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup"); + view_listener_t::addMenu(new LLAvatarGiveCard(), "Avatar.GiveCard"); + view_listener_t::addMenu(new LLAvatarEject(), "Avatar.Eject"); + view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM"); + view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse"); - addMenu(new LLObjectEnableMute(), "Avatar.EnableMute"); - addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); - addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); + view_listener_t::addMenu(new LLObjectEnableMute(), "Avatar.EnableMute"); + view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend"); + view_listener_t::addMenu(new LLAvatarEnableFreezeEject(), "Avatar.EnableFreezeEject"); // Object pie menu - addMenu(new LLObjectOpen(), "Object.Open"); - addMenu(new LLObjectBuild(), "Object.Build"); - addMenu(new LLObjectTouch(), "Object.Touch"); - addMenu(new LLObjectSitOrStand(), "Object.SitOrStand"); - addMenu(new LLObjectDelete(), "Object.Delete"); - addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar"); - addMenu(new LLObjectReturn(), "Object.Return"); - addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); - addMenu(new LLObjectMute(), "Object.Mute"); - addMenu(new LLObjectBuy(), "Object.Buy"); - addMenu(new LLObjectEdit(), "Object.Edit"); - addMenu(new LLObjectInspect(), "Object.Inspect"); + view_listener_t::addMenu(new LLObjectBuild(), "Object.Build"); + view_listener_t::addMenu(new LLObjectTouch(), "Object.Touch"); + view_listener_t::addMenu(new LLObjectSitOrStand(), "Object.SitOrStand"); + view_listener_t::addMenu(new LLObjectDelete(), "Object.Delete"); + view_listener_t::addMenu(new LLObjectAttachToAvatar(), "Object.AttachToAvatar"); + view_listener_t::addMenu(new LLObjectReturn(), "Object.Return"); + view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse"); + view_listener_t::addMenu(new LLObjectMute(), "Object.Mute"); + view_listener_t::addMenu(new LLObjectBuy(), "Object.Buy"); + view_listener_t::addMenu(new LLObjectEdit(), "Object.Edit"); - addMenu(new LLObjectEnableOpen(), "Object.EnableOpen"); - addMenu(new LLObjectEnableTouch(), "Object.EnableTouch"); - addMenu(new LLObjectEnableSitOrStand(), "Object.EnableSitOrStand"); - addMenu(new LLObjectEnableDelete(), "Object.EnableDelete"); - addMenu(new LLObjectEnableWear(), "Object.EnableWear"); - addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); - addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); - addMenu(new LLObjectEnableMute(), "Object.EnableMute"); - addMenu(new LLObjectEnableBuy(), "Object.EnableBuy"); + view_listener_t::addMenu(new LLObjectEnableOpen(), "Object.EnableOpen"); + view_listener_t::addMenu(new LLObjectEnableTouch(), "Object.EnableTouch"); + view_listener_t::addMenu(new LLObjectEnableSitOrStand(), "Object.EnableSitOrStand"); + view_listener_t::addMenu(new LLObjectEnableDelete(), "Object.EnableDelete"); + view_listener_t::addMenu(new LLObjectEnableWear(), "Object.EnableWear"); + view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn"); + view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse"); + view_listener_t::addMenu(new LLObjectEnableMute(), "Object.EnableMute"); + view_listener_t::addMenu(new LLObjectEnableBuy(), "Object.EnableBuy"); - /*addMenu(new LLObjectVisibleTouch(), "Object.VisibleTouch"); - addMenu(new LLObjectVisibleCustomTouch(), "Object.VisibleCustomTouch"); - addMenu(new LLObjectVisibleStandUp(), "Object.VisibleStandUp"); - addMenu(new LLObjectVisibleSitHere(), "Object.VisibleSitHere"); - addMenu(new LLObjectVisibleCustomSit(), "Object.VisibleCustomSit");*/ + /*view_listener_t::addMenu(new LLObjectVisibleTouch(), "Object.VisibleTouch"); + view_listener_t::addMenu(new LLObjectVisibleCustomTouch(), "Object.VisibleCustomTouch"); + view_listener_t::addMenu(new LLObjectVisibleStandUp(), "Object.VisibleStandUp"); + view_listener_t::addMenu(new LLObjectVisibleSitHere(), "Object.VisibleSitHere"); + view_listener_t::addMenu(new LLObjectVisibleCustomSit(), "Object.VisibleCustomSit");*/ // Attachment pie menu - addMenu(new LLAttachmentDrop(), "Attachment.Drop"); - addMenu(new LLAttachmentDetach(), "Attachment.Detach"); - - addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); - addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); + enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2)); + view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop"); + view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint"); + view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach"); + view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled"); + view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop"); + view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach"); // Land pie menu - addMenu(new LLLandBuild(), "Land.Build"); - addMenu(new LLLandSit(), "Land.Sit"); - addMenu(new LLLandBuyPass(), "Land.BuyPass"); - addMenu(new LLLandEdit(), "Land.Edit"); + view_listener_t::addMenu(new LLLandBuild(), "Land.Build"); + view_listener_t::addMenu(new LLLandSit(), "Land.Sit"); + view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass"); + view_listener_t::addMenu(new LLLandEdit(), "Land.Edit"); - addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); + view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass"); // Generic actions - addMenu(new LLShowFloater(), "ShowFloater"); - addMenu(new LLPromptShowURL(), "PromptShowURL"); - addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); - addMenu(new LLShowAgentGroups(), "ShowAgentGroups"); - addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLShowFloater(), "ShowFloater"); + view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL"); + view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile"); + view_listener_t::addMenu(new LLToggleControl(), "ToggleControl"); + view_listener_t::addMenu(new LLCheckControl(), "CheckControl"); + view_listener_t::addMenu(new LLGoToObject(), "GoToObject"); + view_listener_t::addMenu(new LLPayObject(), "PayObject"); - addMenu(new LLGoToObject(), "GoToObject"); - addMenu(new LLPayObject(), "PayObject"); + view_listener_t::addMenu(new LLEnablePayObject(), "EnablePayObject"); + view_listener_t::addMenu(new LLEnableEdit(), "EnableEdit"); - addMenu(new LLEnablePayObject(), "EnablePayObject"); - addMenu(new LLEnableEdit(), "EnableEdit"); + view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible"); + view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected"); + view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); + view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected"); + view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); - addMenu(new LLFloaterVisible(), "FloaterVisible"); - addMenu(new LLSomethingSelected(), "SomethingSelected"); - addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD"); - addMenu(new LLEditableSelected(), "EditableSelected"); - addMenu(new LLEditableSelectedMono(), "EditableSelectedMono"); } diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h index e9fedf37d8..cf482266d6 100644 --- a/indra/newview/llviewermenu.h +++ b/indra/newview/llviewermenu.h @@ -34,6 +34,7 @@ #define LL_LLVIEWERMENU_H #include "llmenugl.h" +#include "llsafehandle.h" //newview includes #include "llfilepicker.h" @@ -44,11 +45,11 @@ class LLParcelSelection; class LLObjectSelection; -void pre_init_menus(); void init_menus(); void cleanup_menus(); void show_debug_menus(); // checks for if menus should be shown first. +void toggle_debug_menus(void*); void show_context_menu( S32 x, S32 y, MASK mask ); void show_build_mode_context_menu(S32 x, S32 y, MASK mask); BOOL enable_save_into_inventory(void*); @@ -75,37 +76,30 @@ BOOL enable_deselect(void*); BOOL enable_undo(void*); BOOL enable_redo(void*); -// returns TRUE if we have a friend relationship with agent_id -BOOL is_agent_friend(const LLUUID& agent_id); BOOL is_agent_mappable(const LLUUID& agent_id); -void menu_toggle_control( void* user_data ); void confirm_replace_attachment(S32 option, void* user_data); -void handle_detach_from_avatar(void* user_data); -void attach_label(std::string& label, void* user_data); -void detach_label(std::string& label, void* user_data); -BOOL object_selected_and_point_valid(void* user_data); -BOOL object_attached(void* user_data); +void handle_detach_from_avatar(const LLSD& user_data); +void attach_label(std::string& label, const LLSD&); +void detach_label(std::string& label, const LLSD&); +BOOL object_selected_and_point_valid(const LLSD&); void handle_detach(void*); BOOL enable_god_full(void* user_data); BOOL enable_god_liaison(void* user_data); BOOL enable_god_customer_service(void* user_data); BOOL enable_god_basic(void* user_data); -void handle_show_newest_map(void*); void set_underclothes_menu_options(); void exchange_callingcard(const LLUUID& dest_id); void handle_gestures(void*); void handle_sit_down(void*); -bool toggle_build_mode(); void handle_object_build(void*); void handle_save_snapshot(void *); void handle_toggle_flycam(); bool handle_sit_or_stand(); bool handle_give_money_dialog(); -bool handle_object_open(); bool handle_go_to(); // Export to XML or Collada @@ -119,8 +113,6 @@ class LLPermissions; class LLViewerMenuHolderGL : public LLMenuHolderGL { public: - LLViewerMenuHolderGL(); - virtual BOOL hideMenus(); void setParcelSelection(LLSafeHandle selection); @@ -142,30 +134,31 @@ extern LLViewerMenuHolderGL* gMenuHolder; extern LLMenuBarGL* gLoginMenuBarView; // Pie menus -extern LLPieMenu *gPieSelf; -extern LLPieMenu *gPieAvatar; -extern LLPieMenu *gPieObject; -extern LLPieMenu *gPieAttachment; -extern LLPieMenu *gPieLand; -extern LLPieMenu* gPieRate; +extern LLContextMenu *gPieSelf; +extern LLContextMenu *gPieAvatar; +extern LLContextMenu *gPieObject; +extern LLContextMenu *gPieAttachment; + +extern LLContextMenu *gPieLand; +extern LLContextMenu *gPieRate; // Pie menus -extern LLPieMenu *gPieSelfSimple; -extern LLPieMenu *gPieAvatarSimple; -extern LLPieMenu *gPieObjectSimple; -extern LLPieMenu *gPieAttachmentSimple; -extern LLPieMenu *gPieLandSimple; +extern LLContextMenu *gPieSelfSimple; +extern LLContextMenu *gPieAvatarSimple; +extern LLContextMenu *gPieObjectSimple; +extern LLContextMenu *gPieAttachmentSimple; +extern LLContextMenu *gPieLandSimple; // Needed to build menus when attachment site list available extern LLMenuGL* gAttachSubMenu; extern LLMenuGL* gDetachSubMenu; extern LLMenuGL* gTakeOffClothes; -extern LLPieMenu* gAttachScreenPieMenu; -extern LLPieMenu* gDetachScreenPieMenu; -extern LLPieMenu* gAttachPieMenu; -extern LLPieMenu* gDetachPieMenu; -extern LLPieMenu* gAttachBodyPartPieMenus[8]; -extern LLPieMenu* gDetachBodyPartPieMenus[8]; +extern LLContextMenu* gAttachScreenPieMenu; +extern LLContextMenu* gDetachScreenPieMenu; +extern LLContextMenu* gAttachPieMenu; +extern LLContextMenu* gDetachPieMenu; +extern LLContextMenu* gAttachBodyPartPieMenus[8]; +extern LLContextMenu* gDetachBodyPartPieMenus[8]; extern LLMenuItemCallGL* gAFKMenu; extern LLMenuItemCallGL* gBusyMenu; diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index d1f50212db..1cfeec5627 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -37,62 +37,54 @@ // project includes #include "llagent.h" #include "llfilepicker.h" -#include "llfloateranimpreview.h" +#include "llfloaterreg.h" #include "llfloaterbuycurrency.h" -#include "llfloaterimagepreview.h" -#include "llfloaternamedesc.h" #include "llfloatersnapshot.h" #include "llinventorymodel.h" // gInventory #include "llresourcedata.h" #include "llfloaterperms.h" #include "llstatusbar.h" #include "llviewercontrol.h" // gSavedSettings -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "lluictrlfactory.h" +#include "llviewerinventory.h" #include "llviewermenu.h" // gMenuHolder #include "llviewerregion.h" #include "llviewerstats.h" #include "llviewerwindow.h" #include "llappviewer.h" #include "lluploaddialog.h" +#include "lltrans.h" // linden libraries #include "llassetuploadresponders.h" #include "lleconomy.h" #include "llhttpclient.h" -#include "llmemberlistener.h" #include "llsdserialize.h" #include "llstring.h" #include "lltransactiontypes.h" #include "lluuid.h" -#include "vorbisencode.h" +#include "llvorbisencode.h" // system libraries #include -using namespace LLOldEvents; - -typedef LLMemberListener view_listener_t; - - class LLFileEnableSaveAs : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = gFloaterView->getFrontmost() && gFloaterView->getFrontmost()->canSaveAs(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLFileEnableUpload : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = gStatusBar && LLGlobalEconomy::Singleton::getInstance() && (gStatusBar->getBalance() >= LLGlobalEconomy::Singleton::getInstance()->getPriceUpload()); - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; @@ -255,13 +247,12 @@ const std::string upload_pick(void* data) class LLFileUploadImage : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_IMAGE); if (!filename.empty()) { - LLFloaterImagePreview* floaterp = new LLFloaterImagePreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_image_preview.xml"); + LLFloaterReg::showInstance("upload_image", LLSD(filename)); } return TRUE; } @@ -269,14 +260,12 @@ class LLFileUploadImage : public view_listener_t class LLFileUploadSound : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_WAV); if (!filename.empty()) { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_sound_preview.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); + LLFloaterReg::showInstance("upload_sound", LLSD(filename)); } return true; } @@ -284,13 +273,12 @@ class LLFileUploadSound : public view_listener_t class LLFileUploadAnim : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { const std::string filename = upload_pick((void*)LLFilePicker::FFLOAD_ANIM); if (!filename.empty()) { - LLFloaterAnimPreview* floaterp = new LLFloaterAnimPreview(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_animation_preview.xml"); + LLFloaterReg::showInstance("upload_anim", LLSD(filename)); } return true; } @@ -298,7 +286,7 @@ class LLFileUploadAnim : public view_listener_t class LLFileUploadBulk : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { if( gAgent.cameraMouselook() ) { @@ -360,19 +348,16 @@ void upload_error(const std::string& error_message, const std::string& label, co class LLFileEnableCloseWindow : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool new_value = NULL != LLFloater::getClosableFloaterFromFocus(); - - // horrendously opaque, this code - gMenuHolder->findControl(userdata["control"].asString())->setValue(new_value); - return true; + return new_value; } }; class LLFileCloseWindow : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLFloater::closeFocusedFloater(); @@ -382,17 +367,16 @@ class LLFileCloseWindow : public view_listener_t class LLFileEnableCloseAllWindows : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool open_children = gFloaterView->allChildrenClosed(); - gMenuHolder->findControl(userdata["control"].asString())->setValue(!open_children); - return true; + return !open_children; } }; class LLFileCloseAllWindows : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { bool app_quitting = false; gFloaterView->closeAllChildren(app_quitting); @@ -403,7 +387,7 @@ class LLFileCloseAllWindows : public view_listener_t class LLFileSaveTexture : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLFloater* top = gFloaterView->getFrontmost(); if (top) @@ -414,18 +398,9 @@ class LLFileSaveTexture : public view_listener_t } }; -class LLFileTakeSnapshot : public view_listener_t -{ - bool handleEvent(LLPointer event, const LLSD& userdata) - { - LLFloaterSnapshot::show(NULL); - return true; - } -}; - class LLFileTakeSnapshotToDisk : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLPointer raw = new LLImageRaw; @@ -477,23 +452,13 @@ class LLFileTakeSnapshotToDisk : public view_listener_t class LLFileQuit : public view_listener_t { - bool handleEvent(LLPointer event, const LLSD& userdata) + bool handleEvent(const LLSD& userdata) { LLAppViewer::instance()->userQuit(); return true; } }; -void handle_upload(void* data) -{ - const std::string filename = upload_pick(data); - if (!filename.empty()) - { - LLFloaterNameDesc* floaterp = new LLFloaterNameDesc(filename); - LLUICtrlFactory::getInstance()->buildFloater(floaterp, "floater_name_description.xml"); - floaterp->childSetLabelArg("ok_btn", "[AMOUNT]", llformat("%d", LLGlobalEconomy::Singleton::getInstance()->getPriceUpload() )); - } -} void handle_compress_image(void*) { @@ -510,7 +475,7 @@ void handle_compress_image(void*) BOOL success; - success = LLViewerImageList::createUploadFile(infile, outfile, IMG_CODEC_TGA); + success = LLViewerTextureList::createUploadFile(infile, outfile, IMG_CODEC_TGA); if (success) { @@ -566,7 +531,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, else if( exten == "bmp") { asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerImageList::createUploadFile(src_filename, + if (!LLViewerTextureList::createUploadFile(src_filename, filename, IMG_CODEC_BMP )) { @@ -581,7 +546,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, else if( exten == "tga") { asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerImageList::createUploadFile(src_filename, + if (!LLViewerTextureList::createUploadFile(src_filename, filename, IMG_CODEC_TGA )) { @@ -596,7 +561,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, else if( exten == "jpg" || exten == "jpeg") { asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerImageList::createUploadFile(src_filename, + if (!LLViewerTextureList::createUploadFile(src_filename, filename, IMG_CODEC_JPEG )) { @@ -611,7 +576,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, else if( exten == "png") { asset_type = LLAssetType::AT_TEXTURE; - if (!LLViewerImageList::createUploadFile(src_filename, + if (!LLViewerTextureList::createUploadFile(src_filename, filename, IMG_CODEC_PNG )) { @@ -777,8 +742,7 @@ void upload_new_resource(const std::string& src_filename, std::string name, else { // Unknown extension - // *TODO: Translate? - error_message = llformat("Unknown file extension .%s\nExpected .wav, .tga, .bmp, .jpg, .jpeg, or .bvh", exten.c_str()); + error_message = llformat(LLTrans::getString("UnknownFileExtension").c_str(), exten.c_str()); error = TRUE;; } @@ -858,9 +822,9 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt if(!(can_afford_transaction(expected_upload_cost))) { LLFloaterBuyCurrency::buyCurrency( - llformat("Uploading %s costs", - data->mAssetInfo.getName().c_str()), // *TODO: Translate - expected_upload_cost); + llformat(LLTrans::getString("UploadingCosts").c_str(), + data->mAssetInfo.getName().c_str()), + expected_upload_cost); is_balance_sufficient = FALSE; } else if(region) @@ -1075,22 +1039,20 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty } } - void init_menu_file() { - (new LLFileUploadImage())->registerListener(gMenuHolder, "File.UploadImage"); - (new LLFileUploadSound())->registerListener(gMenuHolder, "File.UploadSound"); - (new LLFileUploadAnim())->registerListener(gMenuHolder, "File.UploadAnim"); - (new LLFileUploadBulk())->registerListener(gMenuHolder, "File.UploadBulk"); - (new LLFileCloseWindow())->registerListener(gMenuHolder, "File.CloseWindow"); - (new LLFileCloseAllWindows())->registerListener(gMenuHolder, "File.CloseAllWindows"); - (new LLFileEnableCloseWindow())->registerListener(gMenuHolder, "File.EnableCloseWindow"); - (new LLFileEnableCloseAllWindows())->registerListener(gMenuHolder, "File.EnableCloseAllWindows"); - (new LLFileSaveTexture())->registerListener(gMenuHolder, "File.SaveTexture"); - (new LLFileTakeSnapshot())->registerListener(gMenuHolder, "File.TakeSnapshot"); - (new LLFileTakeSnapshotToDisk())->registerListener(gMenuHolder, "File.TakeSnapshotToDisk"); - (new LLFileQuit())->registerListener(gMenuHolder, "File.Quit"); + view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage"); + view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound"); + view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim"); + view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk"); + view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow"); + view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows"); + view_listener_t::addEnable(new LLFileEnableCloseWindow(), "File.EnableCloseWindow"); + view_listener_t::addEnable(new LLFileEnableCloseAllWindows(), "File.EnableCloseAllWindows"); + view_listener_t::addCommit(new LLFileSaveTexture(), "File.SaveTexture"); + view_listener_t::addCommit(new LLFileTakeSnapshotToDisk(), "File.TakeSnapshotToDisk"); + view_listener_t::addCommit(new LLFileQuit(), "File.Quit"); - (new LLFileEnableUpload())->registerListener(gMenuHolder, "File.EnableUpload"); - (new LLFileEnableSaveAs())->registerListener(gMenuHolder, "File.EnableSaveAs"); + view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload"); + view_listener_t::addEnable(new LLFileEnableSaveAs(), "File.EnableSaveAs"); } diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 7664d7ee07..28e20d92d0 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -37,7 +37,7 @@ #include -#include "audioengine.h" +#include "llaudioengine.h" #include "indra_constants.h" #include "lscript_byteformat.h" #include "mean_collision_data.h" @@ -48,6 +48,7 @@ #include "lldbstrings.h" #include "lleconomy.h" #include "llfilepicker.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" #include "llfollowcamparams.h" #include "llinstantmessage.h" @@ -77,7 +78,6 @@ #include "llfloaterbuycurrency.h" #include "llfloaterbuyland.h" #include "llfloaterchat.h" -#include "llfloatergroupinfo.h" #include "llfloaterimagepreview.h" #include "llfloaterland.h" #include "llfloaterregioninfo.h" @@ -93,13 +93,15 @@ #include "llhudmanager.h" #include "llimpanel.h" #include "llinventorymodel.h" -#include "llinventoryview.h" +#include "llfloaterinventory.h" #include "llmenugl.h" +#include "llmoveview.h" #include "llmutelist.h" #include "llnotifications.h" #include "llnotify.h" #include "llpanelgrouplandmoney.h" #include "llselectmgr.h" +#include "llsidetray.h" #include "llstartup.h" #include "llsky.h" #include "llstatenums.h" @@ -125,7 +127,7 @@ #include "llviewerthrottle.h" #include "llviewerwindow.h" #include "llvlmanager.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvotextbubble.h" #include "llweb.h" #include "llworld.h" @@ -134,13 +136,19 @@ #include "llfloaterworldmap.h" #include "llviewerdisplay.h" #include "llkeythrottle.h" +#include "llgroupactions.h" +#include "llagentui.h" #include +#include #if LL_WINDOWS // For Windows specific error handler #include "llwindebug.h" // For the invalid message handler #endif +//#include "llnearbychathistory.h" +#include "llnotificationmanager.h" + // // Constants // @@ -160,7 +168,7 @@ void open_offer(const std::vector& items, const std::string& from_name); bool check_offer_throttle(const std::string& from_name, bool check_only); void callbackCacheEstateOwnerName(const LLUUID& id, const std::string& first, const std::string& last, - BOOL is_group, void*); + BOOL is_group); //inventory offer throttle globals LLFrameTimer gThrottleTimer; @@ -204,6 +212,10 @@ bool friendship_offer_callback(const LLSD& notification, const LLSD& response) LLUUID fid; LLMessageSystem* msg = gMessageSystem; const LLSD& payload = notification["payload"]; + + // add friend to recent people list + LLRecentPeople::instance().add(payload["from_id"]); + switch(option) { case 0: @@ -630,7 +642,7 @@ bool join_group_response(const LLSD& notification, const LLSD& response) if (option == 2 && !group_id.isNull()) { - LLFloaterGroupInfo::showFromUUID(group_id); + LLGroupActions::show(group_id); LLSD args; args["MESSAGE"] = message; LLNotifications::instance().add("JoinGroup", args, notification["payload"]); @@ -867,13 +879,14 @@ void open_offer(const std::vector& items, const std::string& from_name) LLInventoryItem* item; for(; it != end; ++it) { - item = gInventory.getItem(*it); + const LLUUID& id = *it; + item = gInventory.getItem(id); if(!item) { - LL_WARNS("Messaging") << "Unable to show inventory item: " << *it << LL_ENDL; + LL_WARNS("Messaging") << "Unable to show inventory item: " << id << LL_ENDL; continue; } - if(gInventory.isObjectDescendentOf(*it, trash_id)) + if(gInventory.isObjectDescendentOf(id, trash_id)) { continue; } @@ -882,40 +895,55 @@ void open_offer(const std::vector& items, const std::string& from_name) //if we are throttled, don't display them if (check_offer_throttle(from_name, false)) { - // I'm not sure this is a good idea. - bool show_keep_discard = item->getPermissions().getCreator() != gAgent.getID(); - //bool show_keep_discard = true; + // If we opened this ourselves, focus it + BOOL take_focus = from_name.empty() ? TAKE_FOCUS_YES : TAKE_FOCUS_NO; switch(asset_type) { - case LLAssetType::AT_NOTECARD: - open_notecard((LLViewerInventoryItem*)item, std::string("Note: ") + item->getName(), LLUUID::null, show_keep_discard, LLUUID::null, FALSE); + case LLAssetType::AT_NOTECARD: + LLFloaterReg::showInstance("preview_notecard", LLSD(id), take_focus); break; - case LLAssetType::AT_LANDMARK: - open_landmark((LLViewerInventoryItem*)item, std::string("Landmark: ") + item->getName(), show_keep_discard, LLUUID::null, FALSE); + case LLAssetType::AT_LANDMARK: + { + LLInventoryCategory* parent_folder = gInventory.getCategory(item->getParentUUID()); + LLSD args; + args["LANDMARK_NAME"] = item->getName(); + args["FOLDER_NAME"] = std::string(parent_folder ? parent_folder->getName() : "unnkown"); + LLNotifications::instance().add("LandmarkCreated", args); + + // Open new landmark for editing in Places panel. + LLSD key; + key["type"] = "landmark"; + key["id"] = item->getUUID(); + LLSideTray::getInstance()->showPanel("panel_places", key); + } break; - case LLAssetType::AT_TEXTURE: - open_texture(*it, std::string("Texture: ") + item->getName(), show_keep_discard, LLUUID::null, FALSE); + case LLAssetType::AT_TEXTURE: + LLFloaterReg::showInstance("preview_texture", LLSD(id), take_focus); break; - default: + default: break; } } //highlight item, if it's not in the trash or lost+found // Don't auto-open the inventory floater - LLInventoryView* view = LLInventoryView::getActiveInventory(); - if(!view) - { - return; - } - + LLFloaterInventory* view = NULL; if(gSavedSettings.getBOOL("ShowInInventory") && asset_type != LLAssetType::AT_CALLINGCARD && item->getInventoryType() != LLInventoryType::IT_ATTACHMENT && !from_name.empty()) { - LLInventoryView::showAgentInventory(TRUE); + view = LLFloaterInventory::showAgentInventory(); } + else + { + view = LLFloaterInventory::getActiveInventory(); + } + if(!view) + { + return; + } + //Trash Check LLUUID trash_id; trash_id = gInventory.findCategoryUUIDForType(LLAssetType::AT_TRASH); @@ -941,17 +969,19 @@ void open_offer(const std::vector& items, const std::string& from_name) LL_DEBUGS("Messaging") << "Highlighting" << item->getUUID() << LL_ENDL; //highlight item - LLUICtrl* focus_ctrl = gFocusMgr.getKeyboardFocus(); - view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); - gFocusMgr.setKeyboardFocus(focus_ctrl); + if (view->getPanel()) + { + LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus(); + view->getPanel()->setSelection(item->getUUID(), TAKE_FOCUS_NO); + gFocusMgr.setKeyboardFocus(focus_ctrl); + } } } void inventory_offer_mute_callback(const LLUUID& blocked_id, const std::string& first_name, const std::string& last_name, - BOOL is_group, - void* user_data) + BOOL is_group) { std::string from_name; LLMute::EType type; @@ -970,8 +1000,9 @@ void inventory_offer_mute_callback(const LLUUID& blocked_id, LLMute mute(blocked_id, from_name, type); if (LLMuteList::getInstance()->add(mute)) { - LLFloaterMute::showInstance(); - LLFloaterMute::getInstance()->selectMute(blocked_id); + LLFloaterReg::showInstance("mute"); + LLFloaterMute* mute_instance = LLFloaterReg::getTypedInstance("mute"); + if(mute_instance) mute_instance->selectMute(blocked_id); } // purge the message queue of any previously queued inventory offers from the same source. @@ -1040,7 +1071,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // * we can't build two messages at once. if (2 == button) { - gCacheName->getNameFromUUID(mFromID, mFromGroup, inventory_offer_mute_callback, this); + gCacheName->get(mFromID, mFromGroup, &inventory_offer_mute_callback); } LLMessageSystem* msg = gMessageSystem; @@ -1055,7 +1086,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& msg->addUUIDFast(_PREHASH_ID, mTransactionID); msg->addU32Fast(_PREHASH_Timestamp, NO_TIMESTAMP); // no timestamp necessary std::string name; - gAgent.buildFullname(name); + LLAgentUI::buildFullname(name); msg->addStringFast(_PREHASH_FromAgentName, name); msg->addStringFast(_PREHASH_Message, ""); msg->addU32Fast(_PREHASH_ParentEstateID, 0); @@ -1070,7 +1101,6 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& itemp = (LLViewerInventoryItem*)gInventory.getItem(mObjectID); } - // *TODO:translate std::string from_string; // Used in the pop-up. std::string chatHistory_string; // Used in chat history. if (mFromObject == TRUE) @@ -1080,13 +1110,18 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& std::string group_name; if (gCacheName->getGroupName(mFromID, group_name)) { - from_string = std::string("An object named '") + mFromName + "' owned by the group '" + group_name + "'"; - chatHistory_string = mFromName + " owned by the group '" + group_name + "'"; + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName + LLTrans::getString("'") +" " + LLTrans::getString("InvOfferOwnedByGroup") + + " "+ "'" + group_name + "'"; + + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByGroup") + + " " + group_name + "'"; } else { - from_string = std::string("An object named '") + mFromName + "' owned by an unknown group"; - chatHistory_string = mFromName + " owned by an unknown group"; + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+"'" + + mFromName +"'"+ " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownGroup"); } } else @@ -1094,13 +1129,15 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& std::string first_name, last_name; if (gCacheName->getName(mFromID, first_name, last_name)) { - from_string = std::string("An object named '") + mFromName + "' owned by " + first_name + " " + last_name; - chatHistory_string = mFromName + " owned by " + first_name + " " + last_name; + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+ LLTrans::getString("'") + mFromName + + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedBy") + first_name + " " + last_name; + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedBy") + " " + first_name + " " + last_name; } else { - from_string = std::string("An object named '") + mFromName + "' owned by an unknown user"; - chatHistory_string = mFromName + " owned by an unknown user"; + from_string = LLTrans::getString("InvOfferAnObjectNamed") + " "+LLTrans::getString("'") + + mFromName + LLTrans::getString("'")+" " + LLTrans::getString("InvOfferOwnedByUnknownUser"); + chatHistory_string = mFromName + " " + LLTrans::getString("InvOfferOwnedByUnknownUser"); } } } @@ -1128,7 +1165,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& //don't spam them if they are getting flooded if (check_offer_throttle(mFromName, true)) { - log_message = chatHistory_string + " gave you " + mDesc + "."; + log_message = chatHistory_string + " " + LLTrans::getString("InvOfferGaveYou") + " " + mDesc + LLTrans::getString("."); chat.mText = log_message; LLFloaterChat::addChatHistory(chat); } @@ -1191,7 +1228,7 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& // send the message msg->sendReliable(mHost); - log_message = "You decline " + mDesc + " from " + mFromName + "."; + log_message = LLTrans::getString("InvOfferYouDecline") + " " + mDesc + " " + LLTrans::getString("InvOfferFrom") + " " + mFromName +"."; chat.mText = log_message; if( LLMuteList::getInstance()->isMuted(mFromID ) && ! LLMuteList::getInstance()->isLinden(mFromName) ) // muting for SL-42269 { @@ -1227,15 +1264,17 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD& break; } + if(IM_INVENTORY_OFFERED == mIM) + { + // add buddy to recent people list + LLRecentPeople::instance().add(mFromID); + } + if(opener) { gInventory.addObserver(opener); } - // Allow these to stack up, but once you deal with one, reset the - // position. - gFloaterView->resetStartingFloaterPosition(); - delete this; return false; } @@ -1329,7 +1368,7 @@ void inventory_offer_handler(LLOfferInfo* info, BOOL from_task) args["NAME"] = info->mFromName; LLNotification::Params p("ObjectGiveItem"); - p.substitutions(args).payload(payload).functor(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); + p.substitutions(args).payload(payload).functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, info, _1, _2)); if (from_task) { @@ -1415,7 +1454,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLChat chat; std::string buffer; - // *TODO:translate - need to fix the full name to first/last (maybe) + // *TODO: Translate - need to fix the full name to first/last (maybe) msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, from_id); msg->getBOOLFast(_PREHASH_MessageBlock, _PREHASH_FromGroup, from_group); msg->getUUIDFast(_PREHASH_MessageBlock, _PREHASH_ToAgentID, to_id); @@ -1437,6 +1476,8 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) BOOL is_muted = LLMuteList::getInstance()->isMuted(from_id, name, LLMute::flagTextChat); BOOL is_linden = LLMuteList::getInstance()->isLinden(name); BOOL is_owned_by_me = FALSE; + BOOL is_friend = (LLAvatarTracker::instance().getBuddyInfo(from_id) == NULL) ? false : true; + BOOL accept_im_from_only_friend = gSavedSettings.getBOOL("VoiceCallsFriendsOnly"); chat.mMuted = is_muted && !is_linden; chat.mFromID = from_id; @@ -1466,7 +1507,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_CONSOLE_AND_CHAT_HISTORY: // These are used for system messages, hence don't need the name, // as it is always "Second Life". - // *TODO:translate + // *TODO: Translate args["MESSAGE"] = message; // Note: don't put the message in the IM history, even though was sent @@ -1492,7 +1533,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // if there is not a panel for this conversation (i.e. it is a new IM conversation // initiated by the other party) then... std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2"); pack_instant_message( gMessageSystem, @@ -1510,7 +1551,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // now store incoming IM in chat history - buffer = separator_string + message.substr(message_offset); + buffer = message.substr(message_offset); LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; @@ -1560,11 +1601,16 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); } - buffer = separator_string + saved + message.substr(message_offset); + buffer = saved + message.substr(message_offset); LL_INFOS("Messaging") << "process_improved_im: session_id( " << session_id << " ), from_id( " << from_id << " )" << LL_ENDL; - if (!is_muted || is_linden) + bool mute_im = is_muted; + if(accept_im_from_only_friend&&!is_friend) + { + mute_im = true; + } + if (!mute_im || is_linden) { gIMMgr->addMessage( session_id, @@ -1611,7 +1657,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) case IM_MESSAGEBOX: { // This is a block, modeless dialog. - //*TODO:translate + //*TODO: Translate args["MESSAGE"] = message; LLNotifications::instance().add("SystemMessage", args); } @@ -1698,13 +1744,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) LLSD args; args["SUBJECT"] = subj; args["MESSAGE"] = mes; - LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).timestamp(timestamp)); + LLNotifications::instance().add(LLNotification::Params("GroupNotice").substitutions(args).payload(payload).time_stamp(timestamp)); } // Also send down the old path for now. if (IM_GROUP_NOTICE_REQUESTED == dialog) { - LLFloaterGroupInfo::showNotice(subj,mes,group_id,has_inventory,item_name,info); + + LLPanelGroup::showNotice(subj,mes,group_id,has_inventory,item_name,info); } } break; @@ -1755,7 +1802,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) // Someone has offered us some inventory. { LLOfferInfo* info = new LLOfferInfo; - + bool mute_im = false; if (IM_INVENTORY_OFFERED == dialog) { struct offer_agent_bucket_t @@ -1772,6 +1819,11 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) bucketp = (struct offer_agent_bucket_t*) &binary_bucket[0]; info->mType = (LLAssetType::EType) bucketp->asset_type; info->mObjectID = bucketp->object_id; + + if(accept_im_from_only_friend&&!is_friend) + { + mute_im = true; + } } else { @@ -1802,7 +1854,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) info->mDesc = message; info->mHost = msg->getSender(); //if (((is_busy && !is_owned_by_me) || is_muted)) - if ( is_muted ) + if ( is_muted || mute_im) { // Same as closing window info->forceResponse(IOR_DECLINE); @@ -1859,7 +1911,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) { saved = llformat("(Saved %s) ", formatted_time(timestamp).c_str()); } - buffer = separator_string + saved + message.substr(message_offset); + buffer = saved + message.substr(message_offset); BOOL is_this_agent = FALSE; if(from_id == gAgentID) { @@ -1969,7 +2021,7 @@ void process_improved_im(LLMessageSystem *msg, void **user_data) else { LLSD args; - // *TODO:translate -> [FIRST] [LAST] (maybe) + // *TODO: Translate -> [FIRST] [LAST] (maybe) args["NAME"] = name; args["MESSAGE"] = message; LLSD payload; @@ -2086,7 +2138,7 @@ void busy_message (LLMessageSystem* msg, LLUUID from_id) if (gAgent.getBusy()) { std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); std::string response = gSavedPerAccountSettings.getString("BusyModeResponse2"); pack_instant_message( gMessageSystem, @@ -2352,15 +2404,15 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) switch(chat.mChatType) { case CHAT_TYPE_WHISPER: - verb = " " + LLTrans::getString("whisper") + " "; + verb = "(" + LLTrans::getString("whisper") + ")"; break; case CHAT_TYPE_DEBUG_MSG: case CHAT_TYPE_OWNER: case CHAT_TYPE_NORMAL: - verb = ": "; + verb = ""; break; case CHAT_TYPE_SHOUT: - verb = " " + LLTrans::getString("shout") + " "; + verb = "(" + LLTrans::getString("shout") + ")"; break; case CHAT_TYPE_START: case CHAT_TYPE_STOP: @@ -2368,12 +2420,12 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) break; default: LL_WARNS("Messaging") << "Unknown type " << chat.mChatType << " in chat!" << LL_ENDL; - verb = " say, "; + verb = ""; break; } - chat.mText = from_name; + chat.mText = ""; chat.mText += verb; chat.mText += mesg; } @@ -2396,17 +2448,24 @@ void process_chat_from_simulator(LLMessageSystem *msg, void **user_data) // T * * * F Yes Yes chat.mMuted = is_muted && !is_linden; - - + if (!visible_in_chat_bubble && (is_linden || !is_busy || is_owned_by_me)) { // show on screen and add to history + LLNotificationsUI::LLNotificationManager::instance().onChat( + chat, LLNotificationsUI::NT_NEARBYCHAT); + + // adding temporarily so that communications window chat bar + // works until the new chat window is ready + chat.mText = from_name + ": " + chat.mText; LLFloaterChat::addChat(chat, FALSE, FALSE); } else { - // just add to chat history + LLNotificationsUI::LLNotificationManager::instance().onChat( + chat, LLNotificationsUI::NT_NEARBYCHAT); + // adding temporarily LLFloaterChat::addChatHistory(chat); } } @@ -2430,7 +2489,7 @@ void process_teleport_start(LLMessageSystem *msg, void**) } else { - gViewerWindow->setProgressCancelButtonVisible(TRUE, std::string("Cancel")); // *TODO: Translate + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); } // Freeze the UI and show progress bar @@ -2465,7 +2524,7 @@ void process_teleport_progress(LLMessageSystem* msg, void**) } else { - gViewerWindow->setProgressCancelButtonVisible(TRUE, std::string("Cancel")); //TODO: Translate + gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Cancel")); } std::string buffer; msg->getString("Info", "Message", buffer); @@ -2880,12 +2939,45 @@ void process_agent_movement_complete(LLMessageSystem* msg, void**) { LLSD payload; payload["message"] = version_channel; - LLNotifications::instance().add("ServerVersionChanged", LLSD(), payload); + LLNotifications::instance().add("ServerVersionChanged", LLSD(), payload, server_version_changed_callback); } gLastVersionChannel = version_channel; } +bool server_version_changed_callback(const LLSD& notification, const LLSD& response) +{ + if(notification["payload"]["message"].asString() =="") + return false; + std::string url ="http://wiki.secondlife.com/wiki/Release_Notes/"; + //parse the msg string + std::string server_version = notification["payload"]["message"].asString(); + std::vector s_vect; + boost::algorithm::split(s_vect, server_version, isspace); + for(U32 i = 0; i < s_vect.size(); i++) + { + if (i != (s_vect.size() - 1)) + { + if(i != (s_vect.size() - 2)) + { + url += s_vect[i] + "_"; + } + else + { + url += s_vect[i] + "/"; + } + } + else + { + url += s_vect[i].substr(0,4); + } + } + + LLWeb::loadURL(url); + return false; +} + + void process_crossed_region(LLMessageSystem* msg, void**) { LLUUID agent_id; @@ -3217,11 +3309,12 @@ void process_terse_object_update_improved(LLMessageSystem *mesgsys, void **user_ gObjectList.processCompressedObjectUpdate(mesgsys, user_data, OUT_TERSE_IMPROVED); } +static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); void process_kill_object(LLMessageSystem *mesgsys, void **user_data) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS); + LLFastTimer t(FTM_PROCESS_OBJECTS); LLUUID id; U32 local_id; @@ -3782,13 +3875,13 @@ void process_avatar_sit_response(LLMessageSystem *mesgsys, void **user_data) gAgent.setSitCamera(sitObjectID, camera_eye, camera_at); } - gAgent.mForceMouselook = force_mouselook; + gAgent.setForceMouselook(force_mouselook); LLViewerObject* object = gObjectList.findObject(sitObjectID); if (object) { LLVector3 sit_spot = object->getPositionAgent() + (sitPosition * object->getRotation()); - if (!use_autopilot || (avatar && avatar->mIsSitting && avatar->getRoot() == object->getRoot())) + if (!use_autopilot || (avatar && avatar->isSitting() && avatar->getRoot() == object->getRoot())) { //we're already sitting on this object, so don't autopilot } @@ -4094,7 +4187,7 @@ void process_money_balance_reply( LLMessageSystem* msg, void** ) { // Make the user confirm the transaction, since they might // have missed something during an event. - // *TODO:translate + // *TODO: Translate LLSD args; args["MESSAGE"] = desc; LLNotifications::instance().add("SystemMessage", args); @@ -4170,7 +4263,7 @@ bool handle_special_notification(std::string notificationID, LLSD& llsdBlock) bool attempt_standard_notification(LLMessageSystem* msgsystem) { // if we have additional alert data - if (msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) + if (msgsystem->has(_PREHASH_AlertInfo) && msgsystem->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) { // notification was specified using the new mechanism, so we can just handle it here std::string notificationID; @@ -4316,23 +4409,23 @@ void process_alert_core(const std::string& message, BOOL modal) } else { - // *TODO:translate - args["MESSAGE"] = text; + std::string new_msg =LLNotifications::instance().getGlobalString(text); + args["MESSAGE"] = new_msg; LLNotifications::instance().add("SystemMessage", args); } } else if (modal) { - // *TODO:translate LLSD args; - args["ERROR_MESSAGE"] = message; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + args["ERROR_MESSAGE"] = new_msg; LLNotifications::instance().add("ErrorMessage", args); } else { - // *TODO:translate LLSD args; - args["MESSAGE"] = message; + std::string new_msg =LLNotifications::instance().getGlobalString(message); + args["MESSAGE"] = new_msg; LLNotifications::instance().add("SystemMessageTip", args); } } @@ -4346,11 +4439,11 @@ void handle_show_mean_events(void *) { return; } - - LLFloaterBump::show(NULL); + LLFloaterReg::showInstance("bumps"); + //LLFloaterBump::showInstance(); } -void mean_name_callback(const LLUUID &id, const std::string& first, const std::string& last, BOOL always_false, void* data) +void mean_name_callback(const LLUUID &id, const std::string& first, const std::string& last, BOOL always_false) { if (gNoRender) { @@ -4428,7 +4521,7 @@ void process_mean_collision_alert_message(LLMessageSystem *msgsystem, void **use LLMeanCollisionData *mcd = new LLMeanCollisionData(gAgentID, perp, time, type, mag); gMeanCollisionList.push_front(mcd); const BOOL is_group = FALSE; - gCacheName->getNameFromUUID(perp, is_group, mean_name_callback); + gCacheName->get(perp, is_group, &mean_name_callback); } } } @@ -4460,9 +4553,6 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/) LL_INFOS_ONCE("Messaging") << "EconomyData message arrived; upload cost is L$" << upload_cost << LL_ENDL; - LLFloaterImagePreview::setUploadAmount(upload_cost); - LLFloaterAnimPreview::setUploadAmount(upload_cost); - gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost)); gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost)); @@ -4480,7 +4570,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp // located in [REGIONNAME] at [REGIONPOS], // has been permission to: [PERMISSIONS]." - LLUIString notice(LLFloaterChat::getInstance()->getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); + LLUIString notice(LLTrans::getString(granted ? "ScriptQuestionCautionChatGranted" : "ScriptQuestionCautionChatDenied")); // always include the object name and owner name notice.setArg("[OBJECTNAME]", notification["payload"]["object_name"].asString()); @@ -4534,7 +4624,7 @@ void notify_cautioned_script_question(const LLSD& notification, const LLSD& resp perms.append(", "); } - perms.append(LLFloaterChat::getInstance()->getString(SCRIPT_QUESTIONS[i])); + perms.append(LLTrans::getString(SCRIPT_QUESTIONS[i])); } } @@ -4628,7 +4718,7 @@ static LLNotificationFunctorRegistration script_question_cb_reg_2("ScriptQuestio void process_script_question(LLMessageSystem *msg, void **user_data) { - // *TODO:translate owner name -> [FIRST] [LAST] + // *TODO: Translate owner name -> [FIRST] [LAST] LLHost sender = msg->getSender(); @@ -4652,7 +4742,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) // so we'll reuse the same namespace for both throttle types. std::string throttle_name = owner_name; std::string self_name; - gAgent.getName( self_name ); + LLAgentUI::buildName( self_name ); if( owner_name == self_name ) { throttle_name = taskid.getString(); @@ -4696,7 +4786,7 @@ void process_script_question(LLMessageSystem *msg, void **user_data) if (questions & LSCRIPTRunTimePermissionBits[i]) { count++; - script_question += " " + LLFloaterChat::getInstance()->getString(SCRIPT_QUESTIONS[i]) + "\n"; + script_question += " " + LLTrans::getString(SCRIPT_QUESTIONS[i]) + "\n"; // check whether permission question should cause special caution dialog caution |= (SCRIPT_QUESTION_IS_CAUTION[i]); @@ -4744,15 +4834,15 @@ void container_inventory_arrived(LLViewerObject* object, gAgent.changeCameraToDefault(); } - LLInventoryView* view = LLInventoryView::getActiveInventory(); + LLFloaterInventory* view = LLFloaterInventory::getActiveInventory(); if (inventory->size() > 2) { // create a new inventory category to put this in LLUUID cat_id; - cat_id = gInventory.createNewCategory(gAgent.getInventoryRootID(), + cat_id = gInventory.createNewCategory(gInventory.getRootFolderID(), LLAssetType::AT_NONE, - std::string("Acquired Items")); //TODO: Translate + LLTrans::getString("AcquiredItems")); InventoryObjectList::const_iterator it = inventory->begin(); InventoryObjectList::const_iterator end = inventory->end(); @@ -4846,10 +4936,18 @@ void container_inventory_arrived(LLViewerObject* object, // method to format the time. std::string formatted_time(const time_t& the_time) { - char buffer[30]; /* Flawfinder: ignore */ - LLStringUtil::copy(buffer, ctime(&the_time), 30); - buffer[24] = '\0'; - return std::string(buffer); + std::string dateStr = "["+LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; + + LLSD substitution; + substitution["datetime"] = (S32) the_time; + LLStringUtil::format (dateStr, substitution); + return dateStr; } @@ -4860,7 +4958,7 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLSD args; // if we have additional alert data - if (msg->getNumberOfBlocksFast(_PREHASH_AlertInfo) > 0) + if (msg->has(_PREHASH_AlertInfo) && msg->getSizeFast(_PREHASH_AlertInfo, _PREHASH_Message) > 0) { // Get the message ID msg->getStringFast(_PREHASH_AlertInfo, _PREHASH_Message, reason); @@ -4917,6 +5015,9 @@ void process_teleport_failed(LLMessageSystem *msg, void**) LLNotifications::instance().add("CouldNotTeleportReason", args); + // Let the interested parties know that teleport failed. + LLViewerParcelMgr::getInstance()->onTeleportFailed(); + if( gAgent.getTeleportState() != LLAgent::TELEPORT_NONE ) { gAgent.setTeleportState( LLAgent::TELEPORT_NONE ); @@ -4966,6 +5067,11 @@ void process_teleport_local(LLMessageSystem *msg,void**) gAgent.updateCamera(); send_agent_update(TRUE, TRUE); + + // Let the interested parties know we've teleported. + // Vadim *HACK: Agent position seems to get reset (to render position?) + // on each frame, so we have to pass the new position manually. + LLViewerParcelMgr::getInstance()->onTeleportFinished(true, gAgent.getPosGlobalFromAgent(pos)); } void send_simple_im(const LLUUID& to_id, @@ -4974,7 +5080,7 @@ void send_simple_im(const LLUUID& to_id, const LLUUID& id) { std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); send_improved_im(to_id, my_name, message, @@ -4995,7 +5101,7 @@ void send_group_notice(const LLUUID& group_id, // This will mean converting the item to a binary bucket, // and the subject/message into a single field. std::string my_name; - gAgent.buildFullname(my_name); + LLAgentUI::buildFullname(my_name); // Combine subject + message into a single string. std::ostringstream subject_and_message; @@ -5073,13 +5179,13 @@ void handle_lure(const LLUUID& invitee) } // Prompt for a message to the invited user. -void handle_lure(LLDynamicArray& ids) +void handle_lure(const std::vector& ids) { LLSD edit_args; edit_args["REGION"] = gAgent.getRegion()->getName(); LLSD payload; - for (LLDynamicArray::iterator it = ids.begin(); + for (LLDynamicArray::const_iterator it = ids.begin(); it != ids.end(); ++it) { @@ -5298,7 +5404,7 @@ static LLNotificationFunctorRegistration callback_load_url_reg("LoadWebPage", ca // We've got the name of the person who owns the object hurling the url. // Display confirmation dialog. -void callback_load_url_name(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* data) +void callback_load_url_name(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) { std::vector::iterator it; for (it = gLoadUrlList.begin(); it != gLoadUrlList.end(); ) @@ -5311,7 +5417,7 @@ void callback_load_url_name(const LLUUID& id, const std::string& first, const st std::string owner_name; if (is_group) { - owner_name = first + " (group)"; + owner_name = first + LLTrans::getString("Group"); } else { @@ -5375,7 +5481,7 @@ void process_load_url(LLMessageSystem* msg, void**) // Add to list of pending name lookups gLoadUrlList.push_back(payload); - gCacheName->getNameFromUUID(owner_id, owner_is_group, callback_load_url_name); + gCacheName->get(owner_id, owner_is_group, &callback_load_url_name); } @@ -5431,12 +5537,17 @@ void process_script_teleport_request(LLMessageSystem* msg, void**) msg->getVector3("Data", "SimPosition", pos); msg->getVector3("Data", "LookAt", look_at); - gFloaterWorldMap->trackURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); - LLFloaterWorldMap::show(NULL, TRUE); - + LLFloaterWorldMap* instance = LLFloaterWorldMap::getInstance(); + if(instance) + { + instance->trackURL( + sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]); + LLFloaterReg::showInstance("world_map", "center"); + } + // remove above two lines and replace with below line // to re-enable parcel browser for llMapDestination() - // LLURLDispatcher::dispatch(LLURLDispatcher::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); + // LLURLDispatcher::dispatch(LLSLURL::buildSLURL(sim_name, (S32)pos.mV[VX], (S32)pos.mV[VY], (S32)pos.mV[VZ]), FALSE); } @@ -5458,18 +5569,28 @@ void process_covenant_reply(LLMessageSystem* msg, void**) std::string last_modified; if (covenant_timestamp == 0) { - last_modified = LLTrans::getString("covenant_never_modified"); + last_modified = LLTrans::getString("covenant_last_modified")+LLTrans::getString("never_text"); } else { - last_modified = LLTrans::getString("covenant_modified") + " " + formatted_time((time_t)covenant_timestamp); + last_modified = LLTrans::getString("covenant_last_modified")+"[" + +LLTrans::getString("LTimeWeek")+"] [" + +LLTrans::getString("LTimeMonth")+"] [" + +LLTrans::getString("LTimeDay")+"] [" + +LLTrans::getString("LTimeHour")+"]:[" + +LLTrans::getString("LTimeMin")+"]:[" + +LLTrans::getString("LTimeSec")+"] [" + +LLTrans::getString("LTimeYear")+"]"; + LLSD substitution; + substitution["datetime"] = (S32) covenant_timestamp; + LLStringUtil::format (last_modified, substitution); } LLPanelEstateCovenant::updateLastModified(last_modified); LLPanelLandCovenant::updateLastModified(last_modified); LLFloaterBuyLand::updateLastModified(last_modified); - // Estates can't be owned by groups + gCacheName->get(estate_owner_id, false, &callbackCacheEstateOwnerName); BOOL is_group = FALSE; gCacheName->getNameFromUUID(estate_owner_id, is_group, callbackCacheEstateOwnerName); @@ -5493,11 +5614,11 @@ void process_covenant_reply(LLMessageSystem* msg, void**) if (estate_owner_id.isNull()) { // mainland - covenant_text = "There is no Covenant provided for this Estate."; + covenant_text = LLTrans::getString("RegionNoCovenant"); } else { - covenant_text = "There is no Covenant provided for this Estate. The land on this estate is being sold by the Estate owner, not Linden Lab. Please contact the Estate Owner for sales details."; + covenant_text = LLTrans::getString("RegionNoCovenantOtherOwner"); } LLPanelEstateCovenant::updateCovenantText(covenant_text, covenant_id); LLPanelLandCovenant::updateCovenantText(covenant_text); @@ -5507,13 +5628,13 @@ void process_covenant_reply(LLMessageSystem* msg, void**) void callbackCacheEstateOwnerName(const LLUUID& id, const std::string& first, const std::string& last, - BOOL is_group, void*) + BOOL is_group) { std::string name; if (id.isNull()) { - name = "(none)"; + name = LLTrans::getString("none_text"); } else { @@ -5544,10 +5665,10 @@ void onCovenantLoadComplete(LLVFS *vfs, if( (file_length > 19) && !strncmp( &buffer[0], "Linden text version", 19 ) ) { - LLViewerTextEditor* editor = - new LLViewerTextEditor(std::string("temp"), - LLRect(0,0,0,0), - file_length+1); + LLViewerTextEditor::Params params; + params.name("temp"); + params.max_text_length(file_length+1); + LLViewerTextEditor * editor = LLUICtrlFactory::create (params); if( !editor->importBuffer( &buffer[0], file_length+1 ) ) { LL_WARNS("Messaging") << "Problem importing estate covenant." << LL_ENDL; @@ -5622,6 +5743,6 @@ void invalid_message_callback(LLMessageSystem* msg, void LLOfferInfo::forceResponse(InventoryOfferResponse response) { LLNotification::Params params("UserGiveItem"); - params.functor(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); + params.functor.function(boost::bind(&LLOfferInfo::inventory_offer_callback, this, _1, _2)); LLNotifications::instance().forceResponse(params, response); } diff --git a/indra/newview/llviewermessage.h b/indra/newview/llviewermessage.h index e7a4303a8e..c15e5df675 100644 --- a/indra/newview/llviewermessage.h +++ b/indra/newview/llviewermessage.h @@ -34,6 +34,7 @@ #define LL_LLVIEWERMESSAGE_H #include "llinstantmessage.h" +#include "llpointer.h" #include "lltransactiontypes.h" #include "lluuid.h" #include "stdenums.h" @@ -42,10 +43,11 @@ // Forward declarations // class LLColor4; -class LLViewerObject; class LLInventoryObject; class LLInventoryItem; +class LLMeanCollisionData; class LLMessageSystem; +class LLViewerObject; class LLViewerRegion; // @@ -130,6 +132,7 @@ void container_inventory_arrived(LLViewerObject* object, // agent movement void send_complete_agent_movement(const LLHost& sim_host); void process_agent_movement_complete(LLMessageSystem* msg, void**); +bool server_version_changed_callback(const LLSD& notification, const LLSD& response); void process_crossed_region(LLMessageSystem* msg, void**); void process_teleport_start(LLMessageSystem* msg, void**); void process_teleport_progress(LLMessageSystem* msg, void**); @@ -151,7 +154,7 @@ void send_group_notice(const LLUUID& group_id, const LLInventoryItem* item); void handle_lure(const LLUUID& invitee); -void handle_lure(LLDynamicArray& ids); +void handle_lure(const std::vector& ids); // always from gAgent and // routes through the gAgent's current simulator diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp index 8719557cbc..918b15ef09 100644 --- a/indra/newview/llviewernetwork.cpp +++ b/indra/newview/llviewernetwork.cpp @@ -218,7 +218,7 @@ void LLViewerLogin::setGridChoice(const std::string& grid_name) void LLViewerLogin::resetURIs() { // Clear URIs when picking a new server - gSavedSettings.setValue("CmdLineLoginURI", LLSD::emptyArray()); + gSavedSettings.setLLSD("CmdLineLoginURI", LLSD::emptyArray()); gSavedSettings.setString("CmdLineHelperURI", ""); } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 6591cd3b19..1594a68f36 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -34,7 +34,7 @@ #include "llviewerobject.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "imageids.h" #include "indra_constants.h" #include "llmath.h" @@ -42,6 +42,7 @@ #include "llviewercontrol.h" #include "lldatapacker.h" #include "llfasttimer.h" +#include "llfloaterreg.h" #include "llfontgl.h" #include "llframetimer.h" #include "llinventory.h" @@ -70,7 +71,7 @@ #include "llrendersphere.h" #include "lltooldraganddrop.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" @@ -79,6 +80,7 @@ #include "llviewertextureanim.h" #include "llviewerwindow.h" // For getSpinAxis #include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvoclouds.h" #include "llvograss.h" #include "llvoground.h" @@ -97,6 +99,7 @@ #include "llviewernetwork.h" #include "llvowlsky.h" #include "llmanip.h" +#include "lltrans.h" //#define DEBUG_UPDATE_TYPE @@ -112,18 +115,31 @@ S32 LLViewerObject::sAxisArrowLength(50); BOOL LLViewerObject::sPulseEnabled(FALSE); BOOL LLViewerObject::sUseSharedDrawables(FALSE); // TRUE +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); + // static LLViewerObject *LLViewerObject::createObject(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) { LLViewerObject *res = NULL; - LLFastTimer t1(LLFastTimer::FTM_CREATE_OBJECT); + LLFastTimer t1(FTM_CREATE_OBJECT); switch (pcode) { case LL_PCODE_VOLUME: res = new LLVOVolume(id, pcode, regionp); break; case LL_PCODE_LEGACY_AVATAR: - res = new LLVOAvatar(id, pcode, regionp); break; + { + if (id == gAgentID) + { + res = new LLVOAvatarSelf(id, pcode, regionp); + } + else + { + res = new LLVOAvatar(id, pcode, regionp); + } + static_cast(res)->initInstance(); + break; + } case LL_PCODE_LEGACY_GRASS: res = new LLVOGrass(id, pcode, regionp); break; case LL_PCODE_LEGACY_PART_SYS: @@ -499,15 +515,24 @@ BOOL LLViewerObject::isOverGroupOwnedLand() const && mRegionp->getParcelOverlay()->isOwnedGroup(getPositionRegion()); } -void LLViewerObject::setParent(LLViewerObject* parent) +BOOL LLViewerObject::setParent(LLViewerObject* parent) { - LLPrimitive::setParent(parent); + if(mParent != parent) + { + LLViewerObject* old_parent = (LLViewerObject*)mParent ; + BOOL ret = LLPrimitive::setParent(parent); + if(ret && old_parent && parent) + { + old_parent->removeChild(this) ; + } + return ret ; + } + + return FALSE ; } void LLViewerObject::addChild(LLViewerObject *childp) { - BOOL result = TRUE; - for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i) { if (*i == childp) @@ -522,18 +547,9 @@ void LLViewerObject::addChild(LLViewerObject *childp) childp->mbCanSelect = mbCanSelect; } - childp->setParent(this); - mChildList.push_back(childp); - - if (!result) + if(childp->setParent(this)) { - llwarns << "Failed to attach child " << childp->getID() << " to object " << getID() << llendl; - removeChild(childp); - if (mJointInfo) - { - delete mJointInfo; - mJointInfo = NULL; - } + mChildList.push_back(childp); } } @@ -549,7 +565,11 @@ void LLViewerObject::removeChild(LLViewerObject *childp) } mChildList.erase(i); - childp->setParent(NULL); + + if(childp->getParent() == this) + { + childp->setParent(NULL); + } break; } } @@ -631,11 +651,14 @@ BOOL LLViewerObject::setDrawableParent(LLDrawable* parentp) return FALSE; } - LLDrawable* old_parent = mDrawable->mParent; - - mDrawable->mParent = parentp; - BOOL ret = mDrawable->mXform.setParent(parentp ? &parentp->mXform : NULL); + if(!ret) + { + return FALSE ; + } + LLDrawable* old_parent = mDrawable->mParent; + mDrawable->mParent = parentp; + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); if( old_parent != parentp && old_parent || (parentp && parentp->isActive())) @@ -2461,7 +2484,7 @@ void LLViewerObject::processTaskInv(LLMessageSystem* msg, void** user_data) LLPointer obj; obj = new LLInventoryObject(object->mID, LLUUID::null, LLAssetType::AT_CATEGORY, - std::string("Contents")); + LLTrans::getString("ViewerObjectContents").c_str()); object->mInventory->push_front(obj); object->doInventoryCallback(); delete ft; @@ -2528,6 +2551,7 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename) { LLPointer inv = new LLInventoryObject; inv->importLegacyStream(ifs); + inv->rename(LLTrans::getString("ViewerObjectContents").c_str()); mInventory->push_front(inv); } else @@ -2574,7 +2598,7 @@ void LLViewerObject::doInventoryCallback() void LLViewerObject::removeInventory(const LLUUID& item_id) { // close any associated floater properties - LLFloaterProperties::closeByID(item_id, mID); + LLFloaterReg::hideInstance("properties", item_id); LLMessageSystem* msg = gMessageSystem; msg->newMessageFast(_PREHASH_RemoveTaskInventory); @@ -2587,11 +2611,6 @@ void LLViewerObject::removeInventory(const LLUUID& item_id) msg->sendReliable(mRegionp->getHost()); deleteInventoryItem(item_id); ++mInventorySerialNum; - - // The viewer object should not refresh UI since this is a utility - // function. The UI functionality that called this method should - // refresh the views if necessary. - //gBuildView->refresh(); } void LLViewerObject::updateInventory( @@ -2903,14 +2922,14 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */) S32 tex_count = getNumTEs(); for (i = 0; i < tex_count; i++) { - getTEImage(i)->setBoostLevel(LLViewerImage::BOOST_SELECTED); + getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); } if (isSculpted()) { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); LLUUID sculpt_id = sculpt_params->getSculptTexture(); - gImageList.getImage(sculpt_id)->setBoostLevel(LLViewerImage::BOOST_SELECTED); + LLViewerTextureManager::getFetchedTexture(sculpt_id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE)->setBoostLevel(LLViewerTexture::BOOST_SELECTED); } if (boost_children) @@ -3538,8 +3557,8 @@ void LLViewerObject::setNumTEs(const U8 num_tes) { if (num_tes) { - LLPointer *new_images; - new_images = new LLPointer[num_tes]; + LLPointer *new_images; + new_images = new LLPointer[num_tes]; for (i = 0; i < num_tes; i++) { if (i < getNumTEs()) @@ -3673,11 +3692,11 @@ void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry) // if (mDrawable.notNull() && mDrawable->isVisible()) // { const LLUUID& image_id = getTE(te)->getID(); - mTEImages[te] = gImageList.getImage(image_id); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); // } } -void LLViewerObject::setTEImage(const U8 te, LLViewerImage *imagep) +void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep) { if (mTEImages[te] != imagep) { @@ -3699,7 +3718,7 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost hos uuid == LLUUID::null) { retval = LLPrimitive::setTETexture(te, uuid); - mTEImages[te] = gImageList.getImageFromHost(uuid, host); + mTEImages[te] = LLViewerTextureManager::getFetchedTexture(uuid, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); setChanged(TEXTURE); if (mDrawable.notNull()) { @@ -3710,6 +3729,18 @@ S32 LLViewerObject::setTETextureCore(const U8 te, const LLUUID& uuid, LLHost hos } +void LLViewerObject::changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) +{ + U32 end = getNumTEs() ; + for (U32 face = 0 ; face < end ; face++) + { + if(old_image == mTEImages[face]) + { + mTEImages[face] = new_image ; + } + } +} + S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid) { // Invalid host == get from the agent's sim @@ -3954,20 +3985,20 @@ S32 LLViewerObject::setTERotation(const U8 te, const F32 r) } -LLViewerImage *LLViewerObject::getTEImage(const U8 face) const +LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const { // llassert(mTEImages); if (face < getNumTEs()) { - LLViewerImage* image = mTEImages[face]; + LLViewerTexture* image = mTEImages[face]; if (image) { return image; } else { - return (LLViewerImage*)((LLImageGL*)LLViewerImage::sDefaultImagep); + return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep); } } @@ -4088,7 +4119,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text) updateText(); } -void LLViewerObject::setIcon(LLViewerImage* icon_image) +void LLViewerObject::setIcon(LLViewerTexture* icon_image) { if (!mIcon) { @@ -4178,14 +4209,14 @@ void LLViewerObject::setParticleSource(const LLPartSysData& particle_parameters, if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) { - LLViewerImage* image; + LLViewerTexture* image; if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) { - image = gImageList.getImageFromFile("pixiesmall.tga"); + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.tga"); } else { - image = gImageList.getImage(mPartSourcep->mPartSysData.mPartImageID); + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); } mPartSourcep->setImage(image); } @@ -4227,14 +4258,14 @@ void LLViewerObject::unpackParticleSource(const S32 block_num, const LLUUID& own { if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) { - LLViewerImage* image; + LLViewerTexture* image; if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) { - image = gImageList.getImageFromFile("pixiesmall.j2c"); + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); } else { - image = gImageList.getImage(mPartSourcep->mPartSysData.mPartImageID); + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); } mPartSourcep->setImage(image); } @@ -4274,14 +4305,14 @@ void LLViewerObject::unpackParticleSource(LLDataPacker &dp, const LLUUID& owner_ { if (mPartSourcep->getImage()->getID() != mPartSourcep->mPartSysData.mPartImageID) { - LLViewerImage* image; + LLViewerTexture* image; if (mPartSourcep->mPartSysData.mPartImageID == LLUUID::null) { - image = gImageList.getImageFromFile("pixiesmall.j2c"); + image = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); } else { - image = gImageList.getImage(mPartSourcep->mPartSysData.mPartImageID); + image = LLViewerTextureManager::getFetchedTexture(mPartSourcep->mPartSysData.mPartImageID); } mPartSourcep->setImage(image); } diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index db69399383..cda2c5114f 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -40,7 +40,7 @@ #include "llhudtext.h" #include "llhudicon.h" #include "llinventory.h" -#include "llmemory.h" +#include "llrefcount.h" #include "llmemtype.h" #include "llprimitive.h" #include "lluuid.h" @@ -64,10 +64,11 @@ class LLWorld; class LLNameValue; class LLNetMap; class LLMessageSystem; +class LLPartSysData; class LLPrimitive; class LLPipeline; class LLTextureEntry; -class LLViewerImage; +class LLViewerTexture; class LLViewerInventoryItem; class LLViewerObject; class LLViewerPartSourceScript; @@ -236,7 +237,7 @@ public: BOOL isProbablyModifiable() const; */ - virtual void setParent(LLViewerObject* parent); + virtual BOOL setParent(LLViewerObject* parent); virtual void addChild(LLViewerObject *childp); virtual void removeChild(LLViewerObject *childp); const_child_list_t& getChildren() const { return mChildList; } @@ -311,8 +312,9 @@ public: /*virtual*/ S32 setTEMediaFlags(const U8 te, const U8 media_flags ); /*virtual*/ S32 setTEGlow(const U8 te, const F32 glow); /*virtual*/ BOOL setMaterial(const U8 material); - virtual void setTEImage(const U8 te, LLViewerImage *imagep); // Not derived from LLPrimitive - LLViewerImage *getTEImage(const U8 te) const; + virtual void setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive + void changeTEImage(const LLViewerTexture* old_image, LLViewerTexture* new_image) ; + LLViewerTexture *getTEImage(const U8 te) const; void fitFaceTexture(const U8 face); void sendTEUpdate() const; // Sends packed representation of all texture entry information @@ -353,7 +355,7 @@ public: void setCanSelect(BOOL canSelect); void setDebugText(const std::string &utf8text); - void setIcon(LLViewerImage* icon_image); + void setIcon(LLViewerTexture* icon_image); void clearIcon(); void markForUpdate(BOOL priority); @@ -526,7 +528,7 @@ public: // Last total CRC received from sim, used for caching U32 mTotalCRC; - LLPointer *mTEImages; + LLPointer *mTEImages; // Selection, picking and rendering variables U32 mGLName; // GL "name" used by selection code diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp index e0741e7233..a8232e9a9d 100644 --- a/indra/newview/llviewerobjectlist.cpp +++ b/indra/newview/llviewerobjectlist.cpp @@ -38,6 +38,7 @@ #include "timing.h" #include "llfasttimer.h" #include "llrender.h" +#include "llwindow.h" // decBusyCount() #include "llviewercontrol.h" #include "llface.h" @@ -60,11 +61,12 @@ #include "llresmgr.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llvoavatarself.h" #include "lltoolmgr.h" #include "lltoolpie.h" #include "llkeyboard.h" #include "u64.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "lldatapacker.h" #ifdef LL_STANDALONE #include @@ -210,6 +212,7 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, LLDataPacker* dpp, BOOL just_created) { + LLMemType mt(LLMemType::MTYPE_OBJECT_PROCESS_UPDATE_CORE); LLMessageSystem* msg = gMessageSystem; // ignore returned flags @@ -251,16 +254,19 @@ void LLViewerObjectList::processUpdateCore(LLViewerObject* objectp, objectp->mCreateSelected = false; gViewerWindow->getWindow()->decBusyCount(); - gViewerWindow->getWindow()->setCursor( UI_CURSOR_ARROW ); + gViewerWindow->setCursor( UI_CURSOR_ARROW ); } } +static LLFastTimer::DeclareTimer FTM_PROCESS_OBJECTS("Process Objects"); + void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys, void **user_data, const EObjectUpdateType update_type, bool cached, bool compressed) { - LLFastTimer t(LLFastTimer::FTM_PROCESS_OBJECTS); + LLMemType mt(LLMemType::MTYPE_OBJECT_PROCESS_UPDATE); + LLFastTimer t(FTM_PROCESS_OBJECTS); LLVector3d camera_global = gAgent.getCameraPositionGlobal(); LLViewerObject *objectp; @@ -554,7 +560,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent) { num_updates = mObjects.count() - mCurLazyUpdateIndex; max_value = mObjects.count(); - gImageList.setUpdateStats(TRUE); + gTextureList.setUpdateStats(TRUE); } else { @@ -768,10 +774,10 @@ void LLViewerObjectList::update(LLAgent &agent, LLWorld &world) } */ - mNumObjectsStat.addValue(mObjects.count()); - mNumActiveObjectsStat.addValue(num_active_objects); - mNumSizeCulledStat.addValue(mNumSizeCulled); - mNumVisCulledStat.addValue(mNumVisCulled); + LLViewerStats::getInstance()->mNumObjectsStat.addValue(mObjects.count()); + LLViewerStats::getInstance()->mNumActiveObjectsStat.addValue(num_active_objects); + LLViewerStats::getInstance()->mNumSizeCulledStat.addValue(mNumSizeCulled); + LLViewerStats::getInstance()->mNumVisCulledStat.addValue(mNumVisCulled); } void LLViewerObjectList::clearDebugText() @@ -1016,16 +1022,16 @@ void LLViewerObjectList::shiftObjects(const LLVector3 &offset) void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap) { - LLColor4 above_water_color = gColors.getColor( "NetMapOtherOwnAboveWater" ); - LLColor4 below_water_color = gColors.getColor( "NetMapOtherOwnBelowWater" ); + LLColor4 above_water_color = LLUIColorTable::instance().getColor( "NetMapOtherOwnAboveWater" ); + LLColor4 below_water_color = LLUIColorTable::instance().getColor( "NetMapOtherOwnBelowWater" ); LLColor4 you_own_above_water_color = - gColors.getColor( "NetMapYouOwnAboveWater" ); + LLUIColorTable::instance().getColor( "NetMapYouOwnAboveWater" ); LLColor4 you_own_below_water_color = - gColors.getColor( "NetMapYouOwnBelowWater" ); + LLUIColorTable::instance().getColor( "NetMapYouOwnBelowWater" ); LLColor4 group_own_above_water_color = - gColors.getColor( "NetMapGroupOwnAboveWater" ); + LLUIColorTable::instance().getColor( "NetMapGroupOwnAboveWater" ); LLColor4 group_own_below_water_color = - gColors.getColor( "NetMapGroupOwnBelowWater" ); + LLUIColorTable::instance().getColor( "NetMapGroupOwnBelowWater" ); for (S32 i = 0; i < mMapObjects.count(); i++) @@ -1300,12 +1306,13 @@ LLViewerObject *LLViewerObjectList::createObjectViewer(const LLPCode pcode, LLVi } +static LLFastTimer::DeclareTimer FTM_CREATE_OBJECT("Create Object"); LLViewerObject *LLViewerObjectList::createObject(const LLPCode pcode, LLViewerRegion *regionp, const LLUUID &uuid, const U32 local_id, const LLHost &sender) { LLMemType mt(LLMemType::MTYPE_OBJECT); - LLFastTimer t(LLFastTimer::FTM_CREATE_OBJECT); + LLFastTimer t(FTM_CREATE_OBJECT); LLUUID fullid; if (uuid == LLUUID::null) diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h index ba31f70c3d..ace5c5038e 100644 --- a/indra/newview/llviewerobjectlist.h +++ b/indra/newview/llviewerobjectlist.h @@ -39,11 +39,13 @@ // common includes #include "llstat.h" #include "lldarrayptr.h" +#include "llmap.h" // *TODO: switch to std::map #include "llstring.h" // project includes #include "llviewerobject.h" +class LLCamera; class LLNetMap; class LLDebugBeacon; @@ -150,19 +152,8 @@ public: U32 mCurBin; // Current bin we're working on... - ////////////////////// - // - // Statistics data - // - // - LLStat mNumObjectsStat; - LLStat mNumActiveObjectsStat; - LLStat mNumNewObjectsStat; - LLStat mNumSizeCulledStat; - LLStat mNumVisCulledStat; - + // Statistics data (see also LLViewerStats) S32 mNumNewObjects; - S32 mNumSizeCulled; S32 mNumVisCulled; diff --git a/indra/newview/llviewerparcelmedia.cpp b/indra/newview/llviewerparcelmedia.cpp index b98f418d49..cb233085e5 100644 --- a/indra/newview/llviewerparcelmedia.cpp +++ b/indra/newview/llviewerparcelmedia.cpp @@ -41,47 +41,22 @@ #include "llviewerparcelmgr.h" #include "lluuid.h" #include "message.h" +#include "llviewermediafocus.h" #include "llviewerparcelmediaautoplay.h" #include "llviewerwindow.h" #include "llfirstuse.h" +#include "llpluginclassmedia.h" // Static Variables S32 LLViewerParcelMedia::sMediaParcelLocalID = 0; LLUUID LLViewerParcelMedia::sMediaRegionID; +viewer_media_t LLViewerParcelMedia::sMediaImpl; + // Local functions bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel); -// Move this to its own file. -// helper class that tries to download a URL from a web site and calls a method -// on the Panel Land Media and to discover the MIME type -class LLMimeDiscoveryResponder : public LLHTTPClient::Responder -{ -public: - LLMimeDiscoveryResponder( ) - {} - - - - virtual void completedHeader(U32 status, const std::string& reason, const LLSD& content) - { - std::string media_type = content["content-type"].asString(); - std::string::size_type idx1 = media_type.find_first_of(";"); - std::string mime_type = media_type.substr(0, idx1); - completeAny(status, mime_type); - } - - virtual void error( U32 status, const std::string& reason ) - { - completeAny(status, "none/none"); - } - - void completeAny(U32 status, const std::string& mime_type) - { - LLViewerMedia::setMimeType(mime_type); - } -}; // static void LLViewerParcelMedia::initClass() @@ -92,6 +67,13 @@ void LLViewerParcelMedia::initClass() LLViewerParcelMediaAutoPlay::initClass(); } +//static +void LLViewerParcelMedia::cleanupClass() +{ + // This needs to be destroyed before global destructor time. + sMediaImpl = NULL; +} + ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::update(LLParcel* parcel) @@ -105,6 +87,7 @@ void LLViewerParcelMedia::update(LLParcel* parcel) { sMediaRegionID = LLUUID() ; stop() ; + LL_DEBUGS("Media") << "no agent region, bailing out." << LL_ENDL; return ; } @@ -115,64 +98,54 @@ void LLViewerParcelMedia::update(LLParcel* parcel) LLUUID regionid = gAgent.getRegion()->getRegionID(); if (parcelid != sMediaParcelLocalID || regionid != sMediaRegionID) { + LL_DEBUGS("Media") << "New parcel, parcel id = " << parcelid << ", region id = " << regionid << LL_ENDL; sMediaParcelLocalID = parcelid; sMediaRegionID = regionid; new_parcel = true; } std::string mediaUrl = std::string ( parcel->getMediaURL () ); - LLStringUtil::trim(mediaUrl); + std::string mediaCurrentUrl = std::string( parcel->getMediaCurrentURL()); - // has something changed? - if ( ( LLViewerMedia::getMediaURL() != mediaUrl ) - || ( LLViewerMedia::getMediaTextureID() != parcel->getMediaID () ) ) + // First use warning + if( ! mediaUrl.empty() && gWarningSettings.getBOOL("FirstStreamingVideo") ) { - bool video_was_playing = FALSE; - bool same_media_id = LLViewerMedia::getMediaTextureID() == parcel->getMediaID (); + LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), + boost::bind(callback_play_media, _1, _2, parcel)); + return; - if (LLViewerMedia::isMediaPlaying()) + } + + // if we have a current (link sharing) url, use it instead + if (mediaCurrentUrl != "" && parcel->getMediaType() == "text/html") + { + mediaUrl = mediaCurrentUrl; + } + + LLStringUtil::trim(mediaUrl); + + // If no parcel media is playing, nothing left to do + if(sMediaImpl.isNull()) + + { + return; + } + + // Media is playing...has something changed? + else if (( sMediaImpl->getMediaURL() != mediaUrl ) + || ( sMediaImpl->getMediaTextureID() != parcel->getMediaID() ) + || ( sMediaImpl->getMimeType() != parcel->getMediaType() )) + { + // Only play if the media types are the same. + if(sMediaImpl->getMimeType() == parcel->getMediaType()) { - video_was_playing = TRUE; + play(parcel); } - if ( !mediaUrl.empty() && same_media_id && ! new_parcel) - { - // Someone has "changed the channel", changing the URL of a video - // you were already watching. Automatically play provided the texture ID is the same - if (video_was_playing) - { - // Poke the mime type in before calling play. - // This is necessary because in this instance we are not waiting - // for the results of a header curl. In order to change the channel - // a mime type MUST be provided. - LLViewerMedia::setMimeType(parcel->getMediaType()); - play(parcel); - } - } else { stop(); } - - // Discover the MIME type - // Disabled for the time being. Get the mime type from the parcel. - if(gSavedSettings.getBOOL("AutoMimeDiscovery")) - { - LLHTTPClient::getHeaderOnly( mediaUrl, new LLMimeDiscoveryResponder()); - } - else - { - LLViewerMedia::setMimeType(parcel->getMediaType()); - } - - // First use warning - if( gSavedSettings.getWarning("FirstStreamingVideo") ) - { - LLNotifications::instance().add("ParcelCanPlayMedia", LLSD(), LLSD(), - boost::bind(callback_play_media, _1, _2, parcel)); - - } - } } else @@ -183,15 +156,15 @@ void LLViewerParcelMedia::update(LLParcel* parcel) /* else { - // no audio player, do a first use dialog if their is media here + // no audio player, do a first use dialog if there is media here if (parcel) { std::string mediaUrl = std::string ( parcel->getMediaURL () ); if (!mediaUrl.empty ()) { - if (gSavedSettings.getWarning("QuickTimeInstalled")) + if (gWarningSettings.getBOOL("QuickTimeInstalled")) { - gSavedSettings.setWarning("QuickTimeInstalled", FALSE); + gWarningSettings.setBOOL("QuickTimeInstalled", FALSE); LLNotifications::instance().add("NoQuickTime" ); }; @@ -208,19 +181,57 @@ void LLViewerParcelMedia::play(LLParcel* parcel) if (!parcel) return; - if (!gSavedSettings.getBOOL("AudioStreamingVideo")) + if (!gSavedSettings.getBOOL("AudioSteamingMedia") || !gSavedSettings.getBOOL("AudioStreamingVideo")) return; std::string media_url = parcel->getMediaURL(); + std::string media_current_url = parcel->getMediaCurrentURL(); std::string mime_type = parcel->getMediaType(); LLUUID placeholder_texture_id = parcel->getMediaID(); U8 media_auto_scale = parcel->getMediaAutoScale(); U8 media_loop = parcel->getMediaLoop(); S32 media_width = parcel->getMediaWidth(); S32 media_height = parcel->getMediaHeight(); - LLViewerMedia::play(media_url, mime_type, placeholder_texture_id, - media_width, media_height, media_auto_scale, - media_loop); + + if(sMediaImpl) + { + // If the url and mime type are the same, call play again + if(sMediaImpl->getMediaURL() == media_url + && sMediaImpl->getMimeType() == mime_type + && sMediaImpl->getMediaTextureID() == placeholder_texture_id) + { + LL_DEBUGS("Media") << "playing with existing url " << media_url << LL_ENDL; + + sMediaImpl->play(); + } + // Else if the texture id's are the same, navigate and rediscover type + // MBW -- This causes other state from the previous parcel (texture size, autoscale, and looping) to get re-used incorrectly. + // It's also not really necessary -- just creating a new instance is fine. +// else if(sMediaImpl->getMediaTextureID() == placeholder_texture_id) +// { +// sMediaImpl->navigateTo(media_url, mime_type, true); +// } + else + { + // Since the texture id is different, we need to generate a new impl + LL_DEBUGS("Media") << "new media impl with mime type " << mime_type << ", url " << media_url << LL_ENDL; + + // Delete the old one first so they don't fight over the texture. + sMediaImpl->stop(); + + sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, + media_width, media_height, media_auto_scale, + media_loop); + } + } + else + { + // There is no media impl, make a new one + sMediaImpl = LLViewerMedia::newMediaImpl(media_url, placeholder_texture_id, + media_width, media_height, media_auto_scale, + media_loop); + } + LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); @@ -229,20 +240,38 @@ void LLViewerParcelMedia::play(LLParcel* parcel) // static void LLViewerParcelMedia::stop() { + if(sMediaImpl.isNull()) + { + return; + } + + // We need to remove the media HUD if it is up. + LLViewerMediaFocus::getInstance()->clearFocus(); - LLViewerMedia::stop(); + // This will kill the media instance. + sMediaImpl->stop(); + sMediaImpl = NULL; } // static void LLViewerParcelMedia::pause() { - LLViewerMedia::pause(); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->pause(); } // static void LLViewerParcelMedia::start() { - LLViewerMedia::start(); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->start(); + LLFirstUse::useMedia(); LLViewerParcelMediaAutoPlay::playStarted(); @@ -251,16 +280,41 @@ void LLViewerParcelMedia::start() // static void LLViewerParcelMedia::seek(F32 time) { - LLViewerMedia::seek(time); + if(sMediaImpl.isNull()) + { + return; + } + sMediaImpl->seek(time); } - // static -LLMediaBase::EStatus LLViewerParcelMedia::getStatus() +void LLViewerParcelMedia::focus(bool focus) { - return LLViewerMedia::getStatus(); + sMediaImpl->focus(focus); } +// static +LLPluginClassMediaOwner::EMediaStatus LLViewerParcelMedia::getStatus() +{ + LLPluginClassMediaOwner::EMediaStatus result = LLPluginClassMediaOwner::MEDIA_NONE; + + if(sMediaImpl.notNull() && sMediaImpl->hasMedia()) + { + result = sMediaImpl->getMediaPlugin()->getStatus(); + } + + return result; +} + +// static +std::string LLViewerParcelMedia::getMimeType() +{ + return sMediaImpl.notNull() ? sMediaImpl->getMimeType() : "none/none"; +} +viewer_media_t LLViewerParcelMedia::getParcelMedia() +{ + return sMediaImpl; +} ////////////////////////////////////////////////////////////////////////////////////////// // static void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ) @@ -298,7 +352,7 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if(( command == PARCEL_MEDIA_COMMAND_PLAY ) || ( command == PARCEL_MEDIA_COMMAND_LOOP )) { - if (LLViewerMedia::isMediaPaused()) + if (getStatus() == LLViewerMediaImpl::MEDIA_PAUSED) { start(); } @@ -318,7 +372,7 @@ void LLViewerParcelMedia::processParcelMediaCommandMessage( LLMessageSystem *msg if (flags & (1<getAgentParcel(); play(parcel); @@ -382,6 +436,107 @@ void LLViewerParcelMedia::processParcelMediaUpdate( LLMessageSystem *msg, void * } } } +// Static +///////////////////////////////////////////////////////////////////////////////////////// +void LLViewerParcelMedia::sendMediaNavigateMessage(const std::string& url) +{ + std::string region_url = gAgent.getRegion()->getCapability("ParcelNavigateMedia"); + if (!region_url.empty()) + { + // send navigate event to sim for link sharing + LLSD body; + body["agent-id"] = gAgent.getID(); + body["local-id"] = LLViewerParcelMgr::getInstance()->getAgentParcel()->getLocalID(); + body["url"] = url; + LLHTTPClient::post(region_url, body, new LLHTTPClient::Responder); + } + else + { + llwarns << "can't get ParcelNavigateMedia capability" << llendl; + } + +} + +///////////////////////////////////////////////////////////////////////////////////////// +// inherited from LLViewerMediaObserver +// virtual +void LLViewerParcelMedia::handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event) +{ + switch(event) + { + case MEDIA_EVENT_CONTENT_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CONTENT_UPDATED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_TIME_DURATION_UPDATED: + { + // LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_TIME_DURATION_UPDATED, time is " << self->getCurrentTime() << " of " << self->getDuration() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_SIZE_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_SIZE_CHANGED " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CURSOR_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CURSOR_CHANGED, new cursor is " << self->getCursorName() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAVIGATE_BEGIN: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_BEGIN " << LL_ENDL; + }; + break; + + case MEDIA_EVENT_NAVIGATE_COMPLETE: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_NAVIGATE_COMPLETE, result string is: " << self->getNavigateResultString() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PROGRESS_UPDATED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PROGRESS_UPDATED, loading at " << self->getProgressPercent() << "%" << LL_ENDL; + }; + break; + + case MEDIA_EVENT_STATUS_TEXT_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_STATUS_TEXT_CHANGED, new status text is: " << self->getStatusText() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_LOCATION_CHANGED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_LOCATION_CHANGED, new uri is: " << self->getLocation() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_HREF: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_HREF, target is \"" << self->getClickTarget() << "\", uri is " << self->getClickURL() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_CLICK_LINK_NOFOLLOW: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_CLICK_LINK_NOFOLLOW, uri is " << self->getClickURL() << LL_ENDL; + }; + break; + + case MEDIA_EVENT_PLUGIN_FAILED: + { + LL_DEBUGS("Media") << "Media event: MEDIA_EVENT_PLUGIN_FAILED" << LL_ENDL; + }; + break; + }; +} bool callback_play_media(const LLSD& notification, const LLSD& response, LLParcel* parcel) { @@ -389,13 +544,31 @@ bool callback_play_media(const LLSD& notification, const LLSD& response, LLParce if (option == 0) { gSavedSettings.setBOOL("AudioStreamingVideo", TRUE); + if(!gSavedSettings.getBOOL("AudioSteamingMedia")) + gSavedSettings.setBOOL("AudioSteamingMedia", TRUE); LLViewerParcelMedia::play(parcel); } else { gSavedSettings.setBOOL("AudioStreamingVideo", FALSE); } - gSavedSettings.setWarning("FirstStreamingVideo", FALSE); + gWarningSettings.setBOOL("FirstStreamingVideo", FALSE); return false; } +// TODO: observer +/* +void LLViewerParcelMediaNavigationObserver::onNavigateComplete( const EventType& event_in ) +{ + std::string url = event_in.getStringValue(); + + if (mCurrentURL != url && ! mFromMessage) + { + LLViewerParcelMedia::sendMediaNavigateMessage(url); + } + + mCurrentURL = url; + mFromMessage = false; + +} +*/ diff --git a/indra/newview/llviewerparcelmedia.h b/indra/newview/llviewerparcelmedia.h index 18988704d8..3f7f898356 100644 --- a/indra/newview/llviewerparcelmedia.h +++ b/indra/newview/llviewerparcelmedia.h @@ -33,18 +33,22 @@ #ifndef LLVIEWERPARCELMEDIA_H #define LLVIEWERPARCELMEDIA_H -#include "llmediabase.h" +#include "llviewermedia.h" class LLMessageSystem; class LLParcel; +class LLViewerParcelMediaNavigationObserver; + // This class understands land parcels, network traffic, LSL media // transport commands, and talks to the LLViewerMedia class to actually // do playback. It allows us to remove code from LLViewerParcelMgr. -class LLViewerParcelMedia +class LLViewerParcelMedia : public LLViewerMediaObserver { + LOG_CLASS(LLViewerParcelMedia); public: static void initClass(); + static void cleanupClass(); static void update(LLParcel* parcel); // called when the agent's parcel has a new URL, or the agent has @@ -60,17 +64,38 @@ class LLViewerParcelMedia static void start(); // restart after pause - no need for all the setup + static void focus(bool focus); + static void seek(F32 time); // jump to timecode time - static LLMediaBase::EStatus getStatus(); + static LLPluginClassMediaOwner::EMediaStatus getStatus(); + static std::string getMimeType(); + static viewer_media_t getParcelMedia(); static void processParcelMediaCommandMessage( LLMessageSystem *msg, void ** ); static void processParcelMediaUpdate( LLMessageSystem *msg, void ** ); + static void sendMediaNavigateMessage(const std::string& url); + + // inherited from LLViewerMediaObserver + virtual void handleMediaEvent(LLPluginClassMedia* self, EMediaEvent event); public: static S32 sMediaParcelLocalID; static LLUUID sMediaRegionID; + // HACK: this will change with Media on a Prim + static viewer_media_t sMediaImpl; +}; + + +class LLViewerParcelMediaNavigationObserver +{ +public: + std::string mCurrentURL; + bool mFromMessage; + + // void onNavigateComplete( const EventType& event_in ); + }; #endif diff --git a/indra/newview/llviewerparcelmediaautoplay.cpp b/indra/newview/llviewerparcelmediaautoplay.cpp index dbb9c32008..1b79b47905 100644 --- a/indra/newview/llviewerparcelmediaautoplay.cpp +++ b/indra/newview/llviewerparcelmediaautoplay.cpp @@ -39,7 +39,7 @@ #include "llviewerparcelmgr.h" #include "lluuid.h" #include "message.h" -#include "llviewerimagelist.h" // for texture stats +#include "llviewertexturelist.h" // for texture stats #include "llagent.h" const F32 AUTOPLAY_TIME = 5; // how many seconds before we autoplay @@ -109,17 +109,17 @@ BOOL LLViewerParcelMediaAutoPlay::tick() if ((!mPlayed) && // if we've never played (mTimeInParcel > AUTOPLAY_TIME) && // and if we've been here for so many seconds (this_media_url.size() != 0) && // and if the parcel has media - (!LLViewerMedia::isMediaPlaying())) // and if the media is not already playing + (LLViewerParcelMedia::sMediaImpl.isNull())) // and if the media is not already playing { if (this_media_texture_id.notNull()) // and if the media texture is good { - LLViewerImage *image = gImageList.getImage(this_media_texture_id, FALSE); + LLViewerMediaTexture *image = LLViewerTextureManager::getMediaTexture(this_media_texture_id, FALSE) ; F32 image_size = 0; if (image) { - image_size = image->mMaxVirtualSize; + image_size = image->getMaxVirtualSize() ; } if (gAgent.getVelocity().magVec() < AUTOPLAY_SPEED) // and if the agent is stopped (slow enough) diff --git a/indra/newview/llviewerparcelmediaautoplay.h b/indra/newview/llviewerparcelmediaautoplay.h index cc2e70b1b9..16279e7f1f 100644 --- a/indra/newview/llviewerparcelmediaautoplay.h +++ b/indra/newview/llviewerparcelmediaautoplay.h @@ -33,7 +33,6 @@ #ifndef LLVIEWERPARCELMEDIAAUTOPLAY_H #define LLVIEWERPARCELMEDIAAUTOPLAY_H -#include "llmediabase.h" #include "lltimer.h" // timer to automatically play media diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 193dfaae96..ca3061e083 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -35,7 +35,7 @@ #include "llviewerparcelmgr.h" // Library includes -#include "audioengine.h" +#include "llaudioengine.h" #include "indra_constants.h" #include "llcachename.h" #include "llgl.h" @@ -45,7 +45,6 @@ // Viewer includes #include "llagent.h" -#include "llfloatergroupinfo.h" #include "llviewerwindow.h" #include "llviewercontrol.h" #include "llfirstuse.h" @@ -60,8 +59,8 @@ #include "llsdutil.h" #include "llstatusbar.h" #include "llui.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewermenu.h" #include "llviewerparcelmedia.h" #include "llviewerparceloverlay.h" @@ -80,8 +79,8 @@ U8* LLViewerParcelMgr::sPackedOverlay = NULL; LLUUID gCurrentMovieID = LLUUID::null; -LLPointer sBlockedImage; -LLPointer sPassImage; +LLPointer sBlockedImage; +LLPointer sPassImage; // Local functions void optionally_start_music(const std::string& music_url); @@ -143,8 +142,11 @@ LLViewerParcelMgr::LLViewerParcelMgr() mCollisionSegments = new U8[(mParcelsPerEdge+1)*(mParcelsPerEdge+1)]; resetSegments(mCollisionSegments); - mBlockedImage = gImageList.getImageFromFile("noentrylines.j2c"); - mPassImage = gImageList.getImageFromFile("noentrypasslines.j2c"); + // JC: Resolved a merge conflict here, eliminated + // mBlockedImage->setAddressMode(LLTexUnit::TAM_WRAP); + // because it is done in llviewertexturelist.cpp + mBlockedImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png"); + mPassImage = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png"); S32 overlay_size = mParcelsPerEdge * mParcelsPerEdge / PARCEL_OVERLAY_CHUNKS; sPackedOverlay = new U8[overlay_size]; @@ -155,6 +157,8 @@ LLViewerParcelMgr::LLViewerParcelMgr() { mAgentParcelOverlay[i] = 0; } + + mTeleportInProgress = TRUE; // the initial parcel update is treated like teleport } @@ -646,7 +650,7 @@ LLParcel *LLViewerParcelMgr::getAgentParcel() const } // Return whether the agent can build on the land they are on -BOOL LLViewerParcelMgr::agentCanBuild() const +bool LLViewerParcelMgr::agentCanBuild() const { if (mAgentParcel) { @@ -760,13 +764,17 @@ BOOL LLViewerParcelMgr::canHearSound(const LLVector3d &pos_global) const BOOL LLViewerParcelMgr::inAgentParcel(const LLVector3d &pos_global) const { LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal(pos_global); - if (region != gAgent.getRegion()) + LLViewerRegion* agent_region = gAgent.getRegion(); + if (!region || !agent_region) + return FALSE; + + if (region != agent_region) { // Can't be in the agent parcel if you're not in the same region. return FALSE; } - LLVector3 pos_region = gAgent.getRegion()->getPosRegionFromGlobal(pos_global); + LLVector3 pos_region = agent_region->getPosRegionFromGlobal(pos_global); S32 row = S32(pos_region.mV[VY] / PARCEL_GRID_STEP_METERS); S32 column = S32(pos_region.mV[VX] / PARCEL_GRID_STEP_METERS); @@ -938,7 +946,7 @@ void LLViewerParcelMgr::sendParcelGodForceOwner(const LLUUID& owner_id) payload["parcel_local_id"] = mCurrentParcel->getLocalID(); payload["region_host"] = region->getHost().getIPandPort(); LLNotification::Params params("ForceOwnerAuctionWarning"); - params.payload(payload).functor(callback_god_force_owner); + params.payload(payload).functor.function(callback_god_force_owner); if(mCurrentParcel->getAuctionID()) { @@ -1513,6 +1521,17 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use LLViewerParcelMgr::getInstance()->writeAgentParcelFromBitmap(bitmap); delete[] bitmap; + + // Let interesting parties know about agent parcel change. + LLViewerParcelMgr* instance = LLViewerParcelMgr::getInstance(); + + instance->mAgentParcelChangedSignal(); + + if (instance->mTeleportInProgress) + { + instance->mTeleportInProgress = FALSE; + instance->mTeleportFinishedSignal(gAgent.getPositionGlobal()); + } } } @@ -1584,6 +1603,9 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // Request access list information for this land LLViewerParcelMgr::getInstance()->sendParcelAccessListRequest(AL_ACCESS | AL_BAN); + // Request the media url filter list for this land + LLViewerParcelMgr::getInstance()->requestParcelMediaURLFilter(); + // Request dwell for this land, if it's not public land. LLViewerParcelMgr::getInstance()->mSelectedDwell = 0.f; if (0 != local_id) @@ -1697,7 +1719,7 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use void optionally_start_music(const std::string& music_url) { - if (gSavedSettings.getBOOL("AudioStreamingMusic")) + if (gSavedSettings.getBOOL("AudioStreamingMusic") && gSavedSettings.getBOOL("AudioSteamingMedia")) { // Make the user click the start button on the overlay bar. JC // llinfos << "Starting parcel music " << music_url << llendl; @@ -1907,6 +1929,66 @@ void LLViewerParcelMgr::sendParcelAccessListUpdate(U32 which) } } +class LLParcelMediaURLFilterResponder : public LLHTTPClient::Responder +{ + virtual void result(const LLSD& content) + { + LLViewerParcelMgr::getInstance()->receiveParcelMediaURLFilter(content); + } +}; + +void LLViewerParcelMgr::requestParcelMediaURLFilter() +{ + if (!mSelected) + { + return; + } + + LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( mWestSouth ); + if (!region) + { + return; + } + + LLParcel* parcel = mCurrentParcel; + if (!parcel) + { + llwarns << "no parcel" << llendl; + return; + } + + LLSD body; + body["local-id"] = parcel->getLocalID(); + body["list"] = parcel->getMediaURLFilterList(); + + std::string url = region->getCapability("ParcelMediaURLFilterList"); + if (!url.empty()) + { + LLHTTPClient::post(url, body, new LLParcelMediaURLFilterResponder); + } + else + { + llwarns << "can't get ParcelMediaURLFilterList cap" << llendl; + } +} + + +void LLViewerParcelMgr::receiveParcelMediaURLFilter(const LLSD &content) +{ + if (content.has("list")) + { + LLParcel* parcel = LLViewerParcelMgr::getInstance()->mCurrentParcel; + if (!parcel) return; + + if (content["local-id"].asInteger() == parcel->getLocalID()) + { + parcel->setMediaURLFilterList(content["list"]); + + LLViewerParcelMgr::getInstance()->notifyObservers(); + } + } +} + void LLViewerParcelMgr::deedLandToGroup() { @@ -2369,12 +2451,60 @@ void LLViewerParcelMgr::cleanupGlobals() LLParcelSelection::sNullSelection = NULL; } -LLViewerImage* LLViewerParcelMgr::getBlockedImage() const +LLViewerTexture* LLViewerParcelMgr::getBlockedImage() const { return sBlockedImage; } -LLViewerImage* LLViewerParcelMgr::getPassImage() const +LLViewerTexture* LLViewerParcelMgr::getPassImage() const { return sPassImage; } + +boost::signals2::connection LLViewerParcelMgr::addAgentParcelChangedCallback(parcel_changed_callback_t cb) +{ + return mAgentParcelChangedSignal.connect(cb); +} +/* + * Set finish teleport callback. You can use it to observe all teleport events. + * NOTE: + * After local( in one region) teleports we + * cannot rely on gAgent.getPositionGlobal(), + * so the new position gets passed explicitly. + * Use args of this callback to get global position of avatar after teleport event. + */ +boost::signals2::connection LLViewerParcelMgr::setTeleportFinishedCallback(teleport_finished_callback_t cb) +{ + return mTeleportFinishedSignal.connect(cb); +} + +boost::signals2::connection LLViewerParcelMgr::setTeleportFailedCallback(parcel_changed_callback_t cb) +{ + return mTeleportFailedSignal.connect(cb); +} + +/* Ok, we're notified that teleport has been finished. + * We should now propagate the notification via mTeleportFinishedSignal + * to all interested parties. + */ +void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos) +{ + if (local) + { + // Local teleport. We already have the agent parcel data. + // Emit the signal immediately. + getInstance()->mTeleportFinishedSignal(new_pos); + } + else + { + // Non-local teleport. + // The agent parcel data has not been updated yet. + // Let's wait for the update and then emit the signal. + mTeleportInProgress = TRUE; + } +} + +void LLViewerParcelMgr::onTeleportFailed() +{ + mTeleportFailedSignal(); +} diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 9f762a186c..7373366cd7 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -36,14 +36,17 @@ #include "v3dmath.h" #include "lldarray.h" #include "llframetimer.h" -#include "llmemory.h" +#include "llsingleton.h" #include "llparcelselection.h" #include "llui.h" +#include +#include + class LLUUID; class LLMessageSystem; class LLParcel; -class LLViewerImage; +class LLViewerTexture; class LLViewerRegion; // Constants for sendLandOwner @@ -79,6 +82,11 @@ class LLViewerParcelMgr : public LLSingleton { public: + typedef boost::function teleport_finished_callback_t; + typedef boost::signals2::signal teleport_finished_signal_t; + typedef boost::function parcel_changed_callback_t; + typedef boost::signals2::signal parcel_changed_signal_t; + LLViewerParcelMgr(); ~LLViewerParcelMgr(); @@ -163,7 +171,7 @@ public: BOOL agentCanTakeDamage() const; BOOL agentCanFly() const; F32 agentDrawDistance() const; - BOOL agentCanBuild() const; + bool agentCanBuild() const; F32 getHoverParcelWidth() const { return F32(mHoverEastNorth.mdV[VX] - mHoverWestSouth.mdV[VX]); } @@ -198,6 +206,11 @@ public: // Takes an Access List flag, like AL_ACCESS or AL_BAN void sendParcelAccessListRequest(U32 flags); + // asks for the parcel's media url filter list + void requestParcelMediaURLFilter(); + // receive the response + void receiveParcelMediaURLFilter(const LLSD &content); + // Dwell is not part of the usual parcel update information because the // simulator doesn't actually know the per-parcel dwell. Ack! We have // to get it out of the database. @@ -256,6 +269,12 @@ public: // the agent is banned or not in the allowed group BOOL isCollisionBanned(); + boost::signals2::connection addAgentParcelChangedCallback(parcel_changed_callback_t cb); + boost::signals2::connection setTeleportFinishedCallback(teleport_finished_callback_t cb); + boost::signals2::connection setTeleportFailedCallback(parcel_changed_callback_t cb); + void onTeleportFinished(bool local, const LLVector3d& new_pos); + void onTeleportFailed(); + static BOOL isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power); static BOOL isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); @@ -279,8 +298,8 @@ private: static bool callbackJoinLand(const LLSD& notification, const LLSD& response); //void finishClaim(BOOL user_to_user_sale, U32 join); - LLViewerImage* getBlockedImage() const; - LLViewerImage* getPassImage() const; + LLViewerTexture* getBlockedImage() const; + LLViewerTexture* getPassImage() const; private: BOOL mSelected; @@ -303,6 +322,11 @@ private: LLDynamicArray mObservers; + BOOL mTeleportInProgress; + teleport_finished_signal_t mTeleportFinishedSignal; + parcel_changed_signal_t mTeleportFailedSignal; + parcel_changed_signal_t mAgentParcelChangedSignal; + // Array of pieces of parcel edges to potentially draw // Has (parcels_per_edge + 1) * (parcels_per_edge + 1) elements so // we can represent edges of the grid. @@ -324,8 +348,8 @@ private: BOOL mRenderSelection; S32 mCollisionBanned; LLFrameTimer mCollisionTimer; - LLImageGL* mBlockedImage; - LLImageGL* mPassImage; + LLViewerTexture* mBlockedImage; + LLViewerTexture* mPassImage; // Media S32 mMediaParcelId; diff --git a/indra/newview/llviewerparceloverlay.cpp b/indra/newview/llviewerparceloverlay.cpp index 866c2a91eb..1a91240abb 100644 --- a/indra/newview/llviewerparceloverlay.cpp +++ b/indra/newview/llviewerparceloverlay.cpp @@ -36,19 +36,20 @@ // indra includes #include "llparcel.h" +#include "llfloaterreg.h" #include "llgl.h" #include "llrender.h" #include "v4color.h" #include "v2math.h" // newview includes -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llviewercontrol.h" #include "llsurface.h" #include "llviewerregion.h" #include "llagent.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llselectmgr.h" #include "llfloatertools.h" #include "llglheaders.h" @@ -68,10 +69,9 @@ LLViewerParcelOverlay::LLViewerParcelOverlay(LLViewerRegion* region, F32 region_ { // Create a texture to hold color information. // 4 components - // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges - mTexture = new LLImageGL(FALSE); + // Use mipmaps = FALSE, clamped, NEAREST filter, for sharp edges mImageRaw = new LLImageRaw(mParcelGridsPerEdge, mParcelGridsPerEdge, OVERLAY_IMG_COMPONENTS); - mTexture->createGLTexture(0, mImageRaw); + mTexture = LLViewerTextureManager::getLocalTexture(mImageRaw.get(), FALSE); gGL.getTexUnit(0)->activate(); gGL.getTexUnit(0)->bind(mTexture); mTexture->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -205,13 +205,12 @@ void LLViewerParcelOverlay::updateOverlayTexture() { return; } - // Can do this because gColors are actually stored as LLColor4U - const LLColor4U avail = gColors.getColor4U("PropertyColorAvail"); - const LLColor4U owned = gColors.getColor4U("PropertyColorOther"); - const LLColor4U group = gColors.getColor4U("PropertyColorGroup"); - const LLColor4U self = gColors.getColor4U("PropertyColorSelf"); - const LLColor4U for_sale = gColors.getColor4U("PropertyColorForSale"); - const LLColor4U auction = gColors.getColor4U("PropertyColorAuction"); + const LLColor4U avail = LLUIColorTable::instance().getColor("PropertyColorAvail").get(); + const LLColor4U owned = LLUIColorTable::instance().getColor("PropertyColorOther").get(); + const LLColor4U group = LLUIColorTable::instance().getColor("PropertyColorGroup").get(); + const LLColor4U self = LLUIColorTable::instance().getColor("PropertyColorSelf").get(); + const LLColor4U for_sale = LLUIColorTable::instance().getColor("PropertyColorForSale").get(); + const LLColor4U auction = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); // Create the base texture. U8 *raw = mImageRaw->getData(); @@ -224,7 +223,7 @@ void LLViewerParcelOverlay::updateOverlayTexture() { U8 ownership = mOwnership[i]; - U8 r,g,b,a; + F32 r,g,b,a; // Color stored in low three bits switch( ownership & 0x7 ) @@ -273,10 +272,10 @@ void LLViewerParcelOverlay::updateOverlayTexture() break; } - raw[pixel_index + 0] = r; - raw[pixel_index + 1] = g; - raw[pixel_index + 2] = b; - raw[pixel_index + 3] = a; + raw[pixel_index + 0] = (U8)r; + raw[pixel_index + 1] = (U8)g; + raw[pixel_index + 2] = (U8)b; + raw[pixel_index + 3] = (U8)a; pixel_index += OVERLAY_IMG_COMPONENTS; } @@ -314,12 +313,11 @@ void LLViewerParcelOverlay::updatePropertyLines() S32 row, col; - // Can do this because gColors are actually stored as LLColor4U - const LLColor4U self_coloru = gColors.getColor4U("PropertyColorSelf"); - const LLColor4U other_coloru = gColors.getColor4U("PropertyColorOther"); - const LLColor4U group_coloru = gColors.getColor4U("PropertyColorGroup"); - const LLColor4U for_sale_coloru = gColors.getColor4U("PropertyColorForSale"); - const LLColor4U auction_coloru = gColors.getColor4U("PropertyColorAuction"); + const LLColor4U self_coloru = LLUIColorTable::instance().getColor("PropertyColorSelf").get(); + const LLColor4U other_coloru = LLUIColorTable::instance().getColor("PropertyColorOther").get(); + const LLColor4U group_coloru = LLUIColorTable::instance().getColor("PropertyColorGroup").get(); + const LLColor4U for_sale_coloru = LLUIColorTable::instance().getColor("PropertyColorForSale").get(); + const LLColor4U auction_coloru = LLUIColorTable::instance().getColor("PropertyColorAuction").get(); // Build into dynamic arrays, then copy into static arrays. LLDynamicArray new_vertex_array; @@ -713,6 +711,7 @@ void LLViewerParcelOverlay::setDirty() void LLViewerParcelOverlay::idleUpdate(bool force_update) { + LLMemType mt_iup(LLMemType::MTYPE_IDLE_UPDATE_PARCEL_OVERLAY); if (gGLManager.mIsDisabled) { return; @@ -841,8 +840,8 @@ S32 LLViewerParcelOverlay::renderPropertyLines () drawn += vertex_per_edge; gGL.end(); - - if (LLSelectMgr::sRenderHiddenSelections && gFloaterTools && gFloaterTools->getVisible()) + + if (LLSelectMgr::sRenderHiddenSelections && LLFloaterReg::instanceVisible("build")) { LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_GREATER); diff --git a/indra/newview/llviewerparceloverlay.h b/indra/newview/llviewerparceloverlay.h index 9bed1dde34..e673b811ed 100644 --- a/indra/newview/llviewerparceloverlay.h +++ b/indra/newview/llviewerparceloverlay.h @@ -39,7 +39,7 @@ #include "lldarray.h" #include "llframetimer.h" #include "lluuid.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLViewerRegion; class LLVector3; @@ -53,7 +53,7 @@ public: ~LLViewerParcelOverlay(); // ACCESS - LLImageGL* getTexture() const { return mTexture; } + LLViewerTexture* getTexture() const { return mTexture; } BOOL isOwned(const LLVector3& pos) const; BOOL isOwnedSelf(const LLVector3& pos) const; @@ -99,7 +99,7 @@ private: S32 mParcelGridsPerEdge; - LLPointer mTexture; + LLPointer mTexture; LLPointer mImageRaw; // Size: mParcelGridsPerEdge * mParcelGridsPerEdge diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index b74f9e9f2c..cfb8340462 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -98,7 +98,7 @@ LLViewerPart::~LLViewerPart() --LLViewerPartSim::sParticleCount2 ; } -void LLViewerPart::init(LLPointer sourcep, LLViewerImage *imagep, LLVPCallback cb) +void LLViewerPart::init(LLPointer sourcep, LLViewerTexture *imagep, LLVPCallback cb) { LLMemType mt(LLMemType::MTYPE_PARTICLES); mPartID = LLViewerPart::sNextPartID; @@ -631,6 +631,8 @@ void LLViewerPartSim::shift(const LLVector3 &offset) } } +static LLFastTimer::DeclareTimer FTM_SIMULATE_PARTICLES("Simulate Particles"); + void LLViewerPartSim::updateSimulation() { LLMemType mt(LLMemType::MTYPE_PARTICLES); @@ -644,7 +646,7 @@ void LLViewerPartSim::updateSimulation() return; } - LLFastTimer ftm(LLFastTimer::FTM_SIMULATE_PARTICLES); + LLFastTimer ftm(FTM_SIMULATE_PARTICLES); // Start at a random particle system so the same // particle system doesn't always get first pick at the diff --git a/indra/newview/llviewerpartsim.h b/indra/newview/llviewerpartsim.h index 21bc37f891..8f1f72518a 100644 --- a/indra/newview/llviewerpartsim.h +++ b/indra/newview/llviewerpartsim.h @@ -35,14 +35,14 @@ #include "lldarrayptr.h" #include "llframetimer.h" -#include "llmemory.h" +#include "llpointer.h" #include "llpartdata.h" #include "llviewerpartsource.h" -class LLViewerImage; +class LLViewerTexture; class LLViewerPart; class LLViewerRegion; -class LLViewerImage; +class LLViewerTexture; class LLVOPartGroup; typedef void (*LLVPCallback)(LLViewerPart &part, const F32 dt); @@ -60,7 +60,7 @@ public: public: LLViewerPart(); - void init(LLPointer sourcep, LLViewerImage *imagep, LLVPCallback cb); + void init(LLPointer sourcep, LLViewerTexture *imagep, LLVPCallback cb); U32 mPartID; // Particle ID used primarily for moving between groups @@ -72,7 +72,7 @@ public: // Current particle state (possibly used for rendering) - LLPointer mImagep; + LLPointer mImagep; LLVector3 mPosAgent; LLVector3 mVelocity; LLVector3 mAccel; diff --git a/indra/newview/llviewerpartsource.cpp b/indra/newview/llviewerpartsource.cpp index 38c75a84d1..a8cbcd86c6 100644 --- a/indra/newview/llviewerpartsource.cpp +++ b/indra/newview/llviewerpartsource.cpp @@ -39,7 +39,7 @@ #include "llagent.h" #include "lldrawable.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llvoavatar.h" @@ -78,7 +78,7 @@ void LLViewerPartSource::update(const F32 dt) LLUUID LLViewerPartSource::getImageUUID() const { - LLViewerImage* imagep = mImagep; + LLViewerTexture* imagep = mImagep; if(imagep) { return imagep->getID(); @@ -100,8 +100,8 @@ LLViewerPartSourceScript::LLViewerPartSourceScript(LLViewerObject *source_objp) llassert(source_objp); mSourceObjectp = source_objp; mPosAgent = mSourceObjectp->getPositionAgent(); - mImagep = gImageList.getImageFromFile("pixiesmall.j2c"); - gGL.getTexUnit(0)->bind(mImagep.get()); + mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); + gGL.getTexUnit(0)->bind(mImagep); mImagep->setAddressMode(LLTexUnit::TAM_CLAMP); } @@ -491,7 +491,7 @@ LLPointer LLViewerPartSourceScript::createPSS(LLViewer } -void LLViewerPartSourceScript::setImage(LLViewerImage *imagep) +void LLViewerPartSourceScript::setImage(LLViewerTexture *imagep) { LLMemType mt(LLMemType::MTYPE_PARTICLES); mImagep = imagep; @@ -551,7 +551,7 @@ void LLViewerPartSourceSpiral::update(const F32 dt) LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!mImagep) { - mImagep = gImageList.getImageFromFile("pixiesmall.j2c"); + mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); } const F32 RATE = 0.025f; @@ -720,7 +720,7 @@ void LLViewerPartSourceBeam::update(const F32 dt) if (!mImagep) { - mImagep = gImageList.getImageFromFile("pixiesmall.j2c"); + mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); } LLViewerPart* part = new LLViewerPart(); @@ -806,7 +806,7 @@ void LLViewerPartSourceChat::update(const F32 dt) LLMemType mt(LLMemType::MTYPE_PARTICLES); if (!mImagep) { - mImagep = gImageList.getImageFromFile("pixiesmall.j2c"); + mImagep = LLViewerTextureManager::getFetchedTextureFromFile("pixiesmall.j2c"); } diff --git a/indra/newview/llviewerpartsource.h b/indra/newview/llviewerpartsource.h index 4258b9170f..540e30eb19 100644 --- a/indra/newview/llviewerpartsource.h +++ b/indra/newview/llviewerpartsource.h @@ -33,8 +33,9 @@ #ifndef LL_LLVIEWERPARTSOURCE_H #define LL_LLVIEWERPARTSOURCE_H -#include "llmemory.h" +#include "llrefcount.h" #include "llpartdata.h" +#include "llpointer.h" #include "llquaternion.h" #include "v3math.h" @@ -44,7 +45,7 @@ // // -class LLViewerImage; +class LLViewerTexture; class LLViewerObject; class LLViewerPart; @@ -89,7 +90,7 @@ protected: F32 mLastUpdateTime; F32 mLastPartTime; LLUUID mOwnerUUID; - LLPointer mImagep; + LLPointer mImagep; // Particle information U32 mPartFlags; // Flags for the particle @@ -122,8 +123,8 @@ public: static LLPointer unpackPSS(LLViewerObject *source_objp, LLPointer pssp, LLDataPacker &dp); static LLPointer createPSS(LLViewerObject *source_objp, const LLPartSysData& particle_parameters); - LLViewerImage *getImage() const { return mImagep; } - void setImage(LLViewerImage *imagep); + LLViewerTexture *getImage() const { return mImagep; } + void setImage(LLViewerTexture *imagep); LLPartSysData mPartSysData; void setTargetObject(LLViewerObject *objp); diff --git a/indra/newview/llviewerprecompiledheaders.h b/indra/newview/llviewerprecompiledheaders.h index 49319b13b1..8bf7364714 100644 --- a/indra/newview/llviewerprecompiledheaders.h +++ b/indra/newview/llviewerprecompiledheaders.h @@ -69,31 +69,37 @@ // Library headers from llcommon project: #include "bitpack.h" +#include "lldeleteutils.h" #include "imageids.h" #include "indra_constants.h" //#include "linden_common.h" //#include "llpreprocessor.h" +#include "llallocator.h" #include "llapp.h" #include "llapr.h" #include "llcriticaldamp.h" -#include "lldarray.h" -#include "lldarrayptr.h" +//#include "lldarray.h" +//#include "lldarrayptr.h" #include "lldefs.h" #include "lldepthstack.h" -#include "lldqueueptr.h" +//#include "lldqueueptr.h" #include "llendianswizzle.h" #include "llerror.h" #include "llfasttimer.h" -#include "llfixedbuffer.h" #include "llframetimer.h" #include "llhash.h" #include "lllocalidhashmap.h" #include "llmap.h" -#include "llmemory.h" +//#include "llmemory.h" #include "llnametable.h" +#include "llpointer.h" #include "llpriqueuemap.h" #include "llprocessor.h" +#include "llrefcount.h" +#include "llsafehandle.h" //#include "llsecondlifeurls.h" +#include "llsd.h" +#include "llsingleton.h" #include "llstack.h" #include "llstat.h" #include "llstl.h" @@ -114,20 +120,13 @@ #include "u64.h" // Library includes from llimage -//#include "kdc_flow_control.h" -//#include "kde_flow_control.h" -//#include "kdu_image.h" -//#include "kdu_image_local.h" //#include "llblockdata.h" -//#include "llblockdecoder.h" -//#include "llblockencoder.h" #include "llimage.h" #include "llimagebmp.h" #include "llimagepng.h" #include "llimagej2c.h" #include "llimagejpeg.h" #include "llimagetga.h" -//#include "llkdumem.h" #include "llmapimagetype.h" // Library includes from llmath project @@ -220,9 +219,6 @@ #include "llvolumemgr.h" #include "material_codes.h" -// Library includes from llxml -#include "llxmlnode.h" - // Library includes from llvfs #include "llassettype.h" #include "lldir.h" @@ -232,4 +228,8 @@ #include "llvfile.h" #include "llvfs.h" +// Library includes from llui +// In skinning-7, llui.h dependencies are changing too often. +//#include "llui.h" + #endif diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index d4ee7a7e50..2c68a106c3 100644 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -35,6 +35,7 @@ #include "llviewerregion.h" #include "indra_constants.h" +#include "llfloaterreg.h" #include "llmath.h" #include "llhttpclient.h" #include "llregionflags.h" @@ -638,6 +639,7 @@ void LLViewerRegion::dirtyHeights() BOOL LLViewerRegion::idleUpdate(F32 max_update_time) { + LLMemType mt_ivr(LLMemType::MTYPE_IDLE_UPDATE_VIEWER_REGION); // did_update returns TRUE if we did at least one significant update BOOL did_update = mLandp->idleUpdate(max_update_time); @@ -779,11 +781,6 @@ void LLViewerRegion::calculateCameraDistance() mCameraDistanceSquared = (F32)(gAgent.getCameraPositionGlobal() - getCenterGlobal()).magVecSquared(); } -U32 LLViewerRegion::getNetDetailsForLCD() -{ - return mPingDelay; -} - std::ostream& operator<<(std::ostream &s, const LLViewerRegion ®ion) { s << "{ "; @@ -1439,6 +1436,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url) capabilityNames.append("MapLayerGod"); capabilityNames.append("NewFileAgentInventory"); capabilityNames.append("ParcelPropertiesUpdate"); + capabilityNames.append("ParcelMediaURLFilterList"); + capabilityNames.append("ParcelNavigateMedia"); capabilityNames.append("ParcelVoiceInfoRequest"); capabilityNames.append("ProductInfoRequest"); capabilityNames.append("ProvisionVoiceAccountRequest"); diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h index 4d345c811a..49d0900f2a 100644 --- a/indra/newview/llviewerregion.h +++ b/indra/newview/llviewerregion.h @@ -51,6 +51,7 @@ #include "llweb.h" #include "llcapabilityprovider.h" #include "llcapabilitylistener.h" +#include "m4math.h" // LLMatrix4 // Surface id's #define LAND 1 @@ -288,9 +289,6 @@ public: /// implements LLCapabilityProvider virtual std::string getDescription() const; - // used by LCD to get details for debug screen - U32 getNetDetailsForLCD(); - LLSpatialPartition* getSpatialPartition(U32 type); public: struct CompareDistance diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 5f83cddf5b..994fbd8475 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -36,6 +36,8 @@ #include "llviewerthrottle.h" #include "message.h" +#include "llfloaterreg.h" +#include "llmemory.h" #include "lltimer.h" #include "llappviewer.h" @@ -43,8 +45,9 @@ #include "pipeline.h" #include "lltexturefetch.h" #include "llviewerobjectlist.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "lltexlayer.h" +#include "lltexlayerparams.h" #include "llsurface.h" #include "llvlmanager.h" #include "llagent.h" @@ -55,14 +58,11 @@ #include "llfasttimerview.h" #include "llviewerregion.h" #include "llvoavatar.h" -#include "llfloaterhtml.h" +#include "llvoavatarself.h" #include "llviewerwindow.h" // *TODO: remove, only used for width/height #include "llworld.h" #include "llfeaturemanager.h" #include "llviewernetwork.h" -#if LL_LCD_COMPILE -#include "lllcd.h" -#endif class StatAttributes @@ -199,16 +199,76 @@ const StatAttributes STAT_INFO[LLViewerStats::ST_COUNT] = // ST_TEX_BAKES StatAttributes("Texture Bakes", FALSE, FALSE), // ST_TEX_REBAKES - StatAttributes("Texture Rebakes", FALSE, FALSE), - - // ST_LOGITECH_KEYBOARD - StatAttributes("Logitech LCD", FALSE, FALSE) + StatAttributes("Texture Rebakes", FALSE, FALSE) }; -LLViewerStats::LLViewerStats() - : mPacketsLostPercentStat(64), - mLastTimeDiff(0.0) +LLViewerStats::LLViewerStats() : + mKBitStat("kbitstat"), + mLayersKBitStat("layerskbitstat"), + mObjectKBitStat("objectkbitstat"), + mAssetKBitStat("assetkbitstat"), + mTextureKBitStat("texturekbitstat"), + mVFSPendingOperations("vfspendingoperations"), + mObjectsDrawnStat("objectsdrawnstat"), + mObjectsCulledStat("objectsculledstat"), + mObjectsTestedStat("objectstestedstat"), + mObjectsComparedStat("objectscomparedstat"), + mObjectsOccludedStat("objectsoccludedstat"), + mFPSStat("fpsstat"), + mPacketsInStat("packetsinstat"), + mPacketsLostStat("packetsloststat"), + mPacketsOutStat("packetsoutstat"), + mPacketsLostPercentStat("packetslostpercentstat", 64), + mTexturePacketsStat("texturepacketsstat"), + mActualInKBitStat("actualinkbitstat"), + mActualOutKBitStat("actualoutkbitstat"), + mTrianglesDrawnStat("trianglesdrawnstat"), + mSimTimeDilation("simtimedilation"), + mSimFPS("simfps"), + mSimPhysicsFPS("simphysicsfps"), + mSimAgentUPS("simagentups"), + mSimScriptEPS("simscripteps"), + mSimFrameMsec("simframemsec"), + mSimNetMsec("simnetmsec"), + mSimSimOtherMsec("simsimothermsec"), + mSimSimPhysicsMsec("simsimphysicsmsec"), + mSimSimPhysicsStepMsec("simsimphysicsstepmsec"), + mSimSimPhysicsShapeUpdateMsec("simsimphysicsshapeupdatemsec"), + mSimSimPhysicsOtherMsec("simsimphysicsothermsec"), + mSimAgentMsec("simagentmsec"), + mSimImagesMsec("simimagesmsec"), + mSimScriptMsec("simscriptmsec"), + mSimSpareMsec("simsparemsec"), + mSimSleepMsec("simsleepmsec"), + mSimPumpIOMsec("simpumpiomsec"), + mSimMainAgents("simmainagents"), + mSimChildAgents("simchildagents"), + mSimObjects("simobjects"), + mSimActiveObjects("simactiveobjects"), + mSimActiveScripts("simactivescripts"), + mSimInPPS("siminpps"), + mSimOutPPS("simoutpps"), + mSimPendingDownloads("simpendingdownloads"), + mSimPendingUploads("simpendinguploads"), + mSimPendingLocalUploads("simpendinglocaluploads"), + mSimTotalUnackedBytes("simtotalunackedbytes"), + mPhysicsPinnedTasks("physicspinnedtasks"), + mPhysicsLODTasks("physicslodtasks"), + mPhysicsMemoryAllocated("physicsmemoryallocated"), + mSimPingStat("simpingstat"), + mNumImagesStat("numimagesstat", 32, TRUE), + mNumRawImagesStat("numrawimagesstat", 32, TRUE), + mGLTexMemStat("gltexmemstat", 32, TRUE), + mGLBoundMemStat("glboundmemstat", 32, TRUE), + mRawMemStat("rawmemstat", 32, TRUE), + mFormattedMemStat("formattedmemstat", 32, TRUE), + mNumObjectsStat("numobjectsstat"), + mNumActiveObjectsStat("numactiveobjectsstat"), + mNumNewObjectsStat("numnewobjectsstat"), + mNumSizeCulledStat("numsizeculledstat"), + mNumVisCulledStat("numvisculledstat"), + mLastTimeDiff(0.0) { for (S32 i = 0; i < ST_COUNT; i++) { @@ -353,7 +413,6 @@ void reset_statistics() { if (LLSurface::sTextureUpdateTime) { - LLSurface::sTexelsUpdatedPerSecStat.addValue(0.001f*(LLSurface::sTexelsUpdated / LLSurface::sTextureUpdateTime)); LLSurface::sTexelsUpdated = 0; LLSurface::sTextureUpdateTime = 0.f; } @@ -364,7 +423,7 @@ void output_statistics(void*) { llinfos << "Number of orphans: " << gObjectList.getOrphanCount() << llendl; llinfos << "Number of dead objects: " << gObjectList.mNumDeadObjects << llendl; - llinfos << "Num images: " << gImageList.getNumImages() << llendl; + llinfos << "Num images: " << gTextureList.getNumImages() << llendl; llinfos << "Texture usage: " << LLImageGL::sGlobalTextureMemoryInBytes << llendl; llinfos << "Texture working set: " << LLImageGL::sBoundTextureMemoryInBytes << llendl; llinfos << "Raw usage: " << LLImageRaw::sGlobalRawMemory << llendl; @@ -449,10 +508,10 @@ void output_statistics(void*) llinfos << "--------------------------------" << llendl; llinfos << "Avatar Memory (partly overlaps with above stats):" << llendl; - gTexStaticImageList.dumpByteCount(); - LLVOAvatar::dumpScratchTextureByteCount(); + LLTexLayerStaticImageList::getInstance()->dumpByteCount(); + LLVOAvatarSelf::dumpScratchTextureByteCount(); LLTexLayerSetBuffer::dumpTotalByteCount(); - LLVOAvatar::dumpTotalLocalTextureByteCount(); + LLVOAvatarSelf::dumpTotalLocalTextureByteCount(); LLTexLayerParamAlpha::dumpCacheByteCount(); LLVOAvatar::dumpBakedStatus(); @@ -507,7 +566,7 @@ void update_statistics(U32 frame_count) { gTotalWorldBytes += gVLManager.getTotalBytes(); gTotalObjectBytes += gObjectBits / 8; - gTotalTextureBytes += LLViewerImageList::sTextureBits / 8; + gTotalTextureBytes += gTextureList.mTextureBits / 8; // make sure we have a valid time delta for this frame if (gFrameIntervalSeconds > 0.f) @@ -520,7 +579,7 @@ void update_statistics(U32 frame_count) { LLViewerStats::getInstance()->incStat(LLViewerStats::ST_AVATAR_EDIT_SECONDS, gFrameIntervalSeconds); } - else if (gFloaterTools && gFloaterTools->getVisible()) + else if (LLFloaterReg::instanceVisible("build")) { LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TOOLBOX_SECONDS, gFrameIntervalSeconds); } @@ -534,14 +593,14 @@ void update_statistics(U32 frame_count) LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_AVATAR, (F64)gSavedSettings.getBOOL("VertexShaderLevelAvatar")); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_SHADER_ENVIRONMENT, (F64)gSavedSettings.getBOOL("VertexShaderLevelEnvironment")); #endif - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_FRAME)); - F64 idle_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IDLE); - F64 network_secs = gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_NETWORK); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_FRAME_SECS, gDebugView->mFastTimerView->getTime("Frame")); + F64 idle_secs = gDebugView->mFastTimerView->getTime("Idle"); + F64 network_secs = gDebugView->mFastTimerView->getTime("Network"); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_UPDATE_SECS, idle_secs - network_secs); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_NETWORK_SECS, network_secs); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_IMAGE_UPDATE)); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_STATESORT )); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime(LLFastTimer::FTM_RENDER_GEOMETRY)); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_IMAGE_SECS, gDebugView->mFastTimerView->getTime("Update Images")); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_REBUILD_SECS, gDebugView->mFastTimerView->getTime("Sort Draw State")); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_RENDER_SECS, gDebugView->mFastTimerView->getTime("Geometry")); LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit(gAgent.getRegion()->getHost()); if (cdp) @@ -559,7 +618,7 @@ void update_statistics(U32 frame_count) F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits()); LLViewerStats::getInstance()->mLayersKBitStat.addValue(layer_bits/1024.f); LLViewerStats::getInstance()->mObjectKBitStat.addValue(gObjectBits/1024.f); - LLViewerStats::getInstance()->mTextureKBitStat.addValue(LLViewerImageList::sTextureBits/1024.f); + LLViewerStats::getInstance()->mTextureKBitStat.addValue(gTextureList.mTextureBits/1024.f); LLViewerStats::getInstance()->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending()); LLViewerStats::getInstance()->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f); gTransferManager.resetTransferBitsIn(LLTCT_ASSET); @@ -573,7 +632,7 @@ void update_statistics(U32 frame_count) gDebugTimers[0].unpause(); } - LLViewerStats::getInstance()->mTexturePacketsStat.addValue(LLViewerImageList::sTexturePackets); + LLViewerStats::getInstance()->mTexturePacketsStat.addValue(gTextureList.mTexturePackets); { static F32 visible_avatar_frames = 0.f; @@ -594,15 +653,9 @@ void update_statistics(U32 frame_count) gObjectBits = 0; // gDecodedBits = 0; - LLViewerImageList::sTextureBits = 0; - LLViewerImageList::sTexturePackets = 0; + gTextureList.mTextureBits = 0; + gTextureList.mTexturePackets = 0; -#if LL_LCD_COMPILE - bool LCDenabled = gLcdScreen->Enabled(); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LOGITECH_LCD, LCDenabled); -#else - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LOGITECH_LCD, false); -#endif } class ViewerStatsResponder : public LLHTTPClient::Responder @@ -692,7 +745,7 @@ void send_stats() agent["ping"] = gAvgSimPing; agent["meters_traveled"] = gAgent.getDistanceTraveled(); agent["regions_visited"] = gAgent.getRegionsVisited(); - agent["mem_use"] = getCurrentRSS() / 1024.0; + agent["mem_use"] = LLMemory::getCurrentRSS() / 1024.0; LLSD &system = body["system"]; diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h index d3fd4f2466..ba89fbf02a 100644 --- a/indra/newview/llviewerstats.h +++ b/indra/newview/llviewerstats.h @@ -57,6 +57,7 @@ public: LLStat mTexturePacketsStat; LLStat mActualInKBitStat; // From the packet ring (when faking a bad connection) LLStat mActualOutKBitStat; // From the packet ring (when faking a bad connection) + LLStat mTrianglesDrawnStat; // Simulator stats LLStat mSimTimeDilation; @@ -98,15 +99,22 @@ public: LLStat mPhysicsPinnedTasks; LLStat mPhysicsLODTasks; LLStat mPhysicsMemoryAllocated; - /* - LLStat mSimCPUUsageStat; - LLStat mSimMemTotalStat; - LLStat mSimMemRSSStat; - */ - LLStat mSimPingStat; + LLStat mNumImagesStat; + LLStat mNumRawImagesStat; + LLStat mGLTexMemStat; + LLStat mGLBoundMemStat; + LLStat mRawMemStat; + LLStat mFormattedMemStat; + + LLStat mNumObjectsStat; + LLStat mNumActiveObjectsStat; + LLStat mNumNewObjectsStat; + LLStat mNumSizeCulledStat; + LLStat mNumVisCulledStat; + void resetStats(); public: // If you change this, please also add a corresponding text label @@ -171,9 +179,8 @@ public: ST_WINDOW_HEIGHT = 55, ST_TEX_BAKES = 56, ST_TEX_REBAKES = 57, - ST_LOGITECH_LCD = 58, - ST_COUNT = 59 + ST_COUNT = 58 }; diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index d64700b523..de01e79803 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -32,37 +32,41 @@ #include "llviewerprecompiledheaders.h" +#include "llfloaterreg.h" #include "llfocusmgr.h" -#include "audioengine.h" +#include "llaudioengine.h" #include "llagent.h" #include "llinventory.h" +#include "llinventorybridge.h" #include "llinventorymodel.h" -#include "llinventoryview.h" -#include "llinventorybridge.h" // for landmark prefix string #include "llviewertexteditor.h" #include "llfloaterchat.h" #include "llfloaterworldmap.h" #include "llnotify.h" +#include "llpanelplaces.h" #include "llpreview.h" #include "llpreviewtexture.h" #include "llpreviewnotecard.h" -#include "llpreviewlandmark.h" #include "llscrollbar.h" +#include "llsidetray.h" #include "lltooldraganddrop.h" +#include "lltrans.h" #include "llviewercontrol.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerwindow.h" #include "llviewerinventory.h" #include "lluictrlfactory.h" #include "llnotecard.h" #include "llmemorystream.h" #include "llmenugl.h" +#include "llscrollcontainer.h" +#include "llavataractions.h" #include "llappviewer.h" // for gPacificDaylightTime -static LLRegisterWidget r("text_editor"); +static LLDefaultChildRegistry::Register r("text_editor"); ///---------------------------------------------------------------------------- /// Class LLEmbeddedNotecardOpener @@ -96,36 +100,113 @@ public: } else { - // See if we can bring an existing preview to the front - if(!LLPreview::show(item->getUUID(), true)) + if(!gSavedSettings.getBOOL("ShowNewInventory")) { - if(!gSavedSettings.getBOOL("ShowNewInventory")) - { - // There isn't one, so make a new preview - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("NotecardEditorRect"); - rect.translate(left - rect.mLeft, top - rect.mTop); - LLPreviewNotecard* preview; - preview = new LLPreviewNotecard("preview notecard", - rect, - std::string("Embedded Note: ") + item->getName(), - item->getUUID(), - LLUUID::null, - item->getAssetUUID(), - true, - (LLViewerInventoryItem*)item); - preview->setSourceID(LLUUID::null); - preview->setFocus(TRUE); - - // Force to be entirely onscreen. - gFloaterView->adjustToFitScreen(preview, FALSE); - } + LLFloaterReg::showInstance("preview_notecard", LLSD(item->getUUID()), TAKE_FOCUS_YES); } } } }; +// +// class LLEmbeddedItemSegment +// + +const S32 EMBEDDED_ITEM_LABEL_PADDING = 2; + +class LLEmbeddedItemSegment : public LLTextSegment +{ +public: + LLEmbeddedItemSegment(S32 pos, LLUIImagePtr image, LLPointer inv_item, LLTextEditor& editor) + : LLTextSegment(pos, pos + 1), + mImage(image), + mLabel(utf8str_to_wstring(inv_item->getName())), + mItem(inv_item), + mEditor(editor), + mHasMouseHover(false) + { + + mStyle = new LLStyle(LLStyle::Params().font(LLFontGL::getFontSansSerif())); + mToolTip = inv_item->getName() + '\n' + inv_item->getDescription(); + } + + /*virtual*/ S32 getWidth(S32 first_char, S32 num_chars) const + { + if (num_chars == 0) + { + return 0; + } + else + { + return EMBEDDED_ITEM_LABEL_PADDING + mImage->getWidth() + mStyle->getFont()->getWidth(mLabel.c_str()); + } + + } + //virtual S32 getOffset(S32 segment_local_x_coord, S32 start_offset, S32 num_chars, bool round) const; + //virtual void updateLayout(const class LLTextEditor& editor); + + /*virtual*/ S32 getNumChars(S32 num_pixels, S32 segment_offset, S32 line_offset, S32 max_chars) const + { + return 1; + } + /*virtual*/ F32 draw(S32 start, S32 end, S32 selection_start, S32 selection_end, const LLRect& draw_rect) + { + LLRect image_rect = draw_rect; + image_rect.mRight = image_rect.mLeft + mImage->getWidth(); + image_rect.mTop = image_rect.mBottom + mImage->getHeight(); + mImage->draw(image_rect); + + LLColor4 color; + if (mEditor.getReadOnly()) + { + color = LLUIColorTable::instance().getColor("TextEmbeddedItemReadOnlyColor"); + } + else + { + color = LLUIColorTable::instance().getColor("TextEmbeddedItemColor"); + } + + F32 right_x; + mStyle->getFont()->render(mLabel, 0, image_rect.mRight + EMBEDDED_ITEM_LABEL_PADDING, draw_rect.mBottom, color, LLFontGL::LEFT, LLFontGL::BOTTOM, mHasMouseHover ? LLFontGL::UNDERLINE : 0, LLFontGL::NO_SHADOW, mLabel.length(), S32_MAX, &right_x); + return right_x; + } + + /*virtual*/ S32 getMaxHeight() const + { + return llmax(mImage->getHeight(), llceil(mStyle->getFont()->getLineHeight())); + } + /*virtual*/ bool canEdit() const { return false; } + //virtual void unlinkFromDocument(class LLTextEditor* editor); + //virtual void linkToDocument(class LLTextEditor* editor); + + virtual void setHasMouseHover(bool hover) + { + mHasMouseHover = hover; + } + //virtual const LLColor4& getColor() const; + //virtual void setColor(const LLColor4 &color); + //virtual void setStyle(const LLStyleSP &style); + virtual BOOL getToolTip( std::string& msg ) const + { + msg = mToolTip; + return TRUE; + } + + /*virtual*/ const LLStyleSP getStyle() const { return mStyle; } + +private: + LLUIImagePtr mImage; + LLWString mLabel; + LLStyleSP mStyle; + std::string mToolTip; + LLPointer mItem; + LLTextEditor& mEditor; + bool mHasMouseHover; + +}; + + + //////////////////////////////////////////////////////////// // LLEmbeddedItems // @@ -148,13 +229,11 @@ public: // return true if there are no embedded items. bool empty(); - void bindEmbeddedChars(const LLFontGL* font) const; - void unbindEmbeddedChars(const LLFontGL* font) const; - BOOL insertEmbeddedItem(LLInventoryItem* item, llwchar* value, bool is_new); BOOL removeEmbeddedItem( llwchar ext_char ); BOOL hasEmbeddedItem(llwchar ext_char); // returns TRUE if /this/ editor has an entry for this item + LLUIImagePtr getItemImage(llwchar ext_char) const; void getEmbeddedItemList( std::vector >& items ); void addItems(const std::vector >& items); @@ -369,88 +448,77 @@ BOOL LLEmbeddedItems::hasEmbeddedItem(llwchar ext_char) return FALSE; } -void LLEmbeddedItems::bindEmbeddedChars( const LLFontGL* font ) const -{ - if( sEntries.empty() ) - { - return; - } - for (std::set::const_iterator iter1 = mEmbeddedUsedChars.begin(); iter1 != mEmbeddedUsedChars.end(); ++iter1) +LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const +{ + LLInventoryItem* item = getEmbeddedItem(ext_char); + if (item) { - llwchar wch = *iter1; - item_map_t::iterator iter2 = sEntries.find(wch); - if (iter2 == sEntries.end()) - { - continue; - } - LLInventoryItem* item = iter2->second.mItem; - if (!item) - { - continue; - } - const char* img_name; + const char* img_name = ""; switch( item->getType() ) { - case LLAssetType::AT_TEXTURE: - if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT) - { - img_name = "inv_item_snapshot.tga"; - } - else - { - img_name = "inv_item_texture.tga"; - } + case LLAssetType::AT_TEXTURE: + if(item->getInventoryType() == LLInventoryType::IT_SNAPSHOT) + { + img_name = "inv_item_snapshot.tga"; + } + else + { + img_name = "inv_item_texture.tga"; + } - break; - case LLAssetType::AT_SOUND: img_name = "inv_item_sound.tga"; break; - case LLAssetType::AT_LANDMARK: - if (item->getFlags() & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) + break; + case LLAssetType::AT_SOUND: img_name = "inv_item_sound.tga"; break; + case LLAssetType::AT_LANDMARK: + if (item->getFlags() & LLInventoryItem::II_FLAGS_LANDMARK_VISITED) + { + img_name = "inv_item_landmark_visited.tga"; + } + else + { + img_name = "inv_item_landmark.tga"; + } + break; + case LLAssetType::AT_CALLINGCARD: { - img_name = "inv_item_landmark_visited.tga"; + BOOL online; + online = LLAvatarTracker::instance().isBuddyOnline(item->getCreatorUUID()); + if (online) + { + img_name = "inv_item_callingcard_online.tga"; break; + } + else + { + img_name = "inv_item_callingcard_offline.tga"; break; + } + break; } - else - { - img_name = "inv_item_landmark.tga"; - } - break; - case LLAssetType::AT_CLOTHING: img_name = "inv_item_clothing.tga"; break; - case LLAssetType::AT_OBJECT: - if (item->getFlags() & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS) - { - img_name = "inv_item_object_multi.tga"; - } - else - { - img_name = "inv_item_object.tga"; - } - break; - case LLAssetType::AT_NOTECARD: img_name = "inv_item_notecard.tga"; break; - case LLAssetType::AT_LSL_TEXT: img_name = "inv_item_script.tga"; break; - case LLAssetType::AT_BODYPART: img_name = "inv_item_skin.tga"; break; - case LLAssetType::AT_ANIMATION: img_name = "inv_item_animation.tga";break; - case LLAssetType::AT_GESTURE: img_name = "inv_item_gesture.tga"; break; - default: llassert(0); continue; + case LLAssetType::AT_CLOTHING: img_name = "inv_item_clothing.tga"; break; + case LLAssetType::AT_OBJECT: + if (item->getFlags() & LLInventoryItem::II_FLAGS_OBJECT_HAS_MULTIPLE_ITEMS) + { + img_name = "inv_item_object_multi.tga"; + } + else + { + img_name = "inv_item_object.tga"; + } + break; + case LLAssetType::AT_NOTECARD: img_name = "inv_item_notecard.tga"; break; + case LLAssetType::AT_LSL_TEXT: img_name = "inv_item_script.tga"; break; + case LLAssetType::AT_BODYPART: img_name = "inv_item_skin.tga"; break; + case LLAssetType::AT_ANIMATION: img_name = "inv_item_animation.tga";break; + case LLAssetType::AT_GESTURE: img_name = "inv_item_gesture.tga"; break; + //TODO need img_name + case LLAssetType::AT_FAVORITE: img_name = "inv_item_landmark.tga"; break; + default: llassert(0); } - LLUIImagePtr image = LLUI::getUIImage(img_name); - - font->addEmbeddedChar( wch, image->getImage(), item->getName() ); + return LLUI::getUIImage(img_name); } + return LLUIImagePtr(); } -void LLEmbeddedItems::unbindEmbeddedChars( const LLFontGL* font ) const -{ - if( sEntries.empty() ) - { - return; - } - - for (std::set::const_iterator iter1 = mEmbeddedUsedChars.begin(); iter1 != mEmbeddedUsedChars.end(); ++iter1) - { - font->removeEmbeddedChar(*iter1); - } -} void LLEmbeddedItems::addItems(const std::vector >& items) { @@ -561,33 +629,15 @@ struct LLNotecardCopyInfo // // Member functions // - -LLViewerTextEditor::LLViewerTextEditor(const std::string& name, - const LLRect& rect, - S32 max_length, - const std::string& default_text, - const LLFontGL* font, - BOOL allow_embedded_items) - : LLTextEditor(name, rect, max_length, default_text, font, allow_embedded_items), - mDragItemChar(0), - mDragItemSaved(FALSE), - mInventoryCallback(new LLEmbeddedNotecardOpener) +LLViewerTextEditor::LLViewerTextEditor(const LLViewerTextEditor::Params& p) +: LLTextEditor(p), + mDragItemChar(0), + mDragItemSaved(FALSE), + mInventoryCallback(new LLEmbeddedNotecardOpener) { + mParseHTML = p.allow_html; mEmbeddedItemList = new LLEmbeddedItems(this); mInventoryCallback->setEditor(this); - - // *TODO: Add right click menus for SLURLs - // Build the right click menu - // make the popup menu available - - //LLMenuGL* menu = LLUICtrlFactory::getInstance()->buildMenu("menu_slurl.xml", this); - //if (!menu) - //{ - // menu = new LLMenuGL(LLStringUtil::null); - //} - //menu->setBackgroundColor(gColors.getColor("MenuPopupBgColor")); - //// menu->setVisible(FALSE); - //mPopupMenuHandle = menu->getHandle(); } LLViewerTextEditor::~LLViewerTextEditor() @@ -633,30 +683,16 @@ BOOL LLViewerTextEditor::handleToolTip(S32 x, S32 y, std::string& msg, LLRect* s } const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) + if( cur_segment && cur_segment->getToolTip( msg ) ) { - BOOL has_tool_tip = FALSE; - if( cur_segment->getStyle()->getIsEmbeddedItem() ) - { - LLWString wtip; - has_tool_tip = getEmbeddedItemToolTipAtPos(cur_segment->getStart(), wtip); - msg = wstring_to_utf8str(wtip); - } - else - { - has_tool_tip = cur_segment->getToolTip( msg ); - } - if( has_tool_tip ) - { - // Just use a slop area around the cursor - // Convert rect local to screen coordinates - S32 SLOP = 8; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; - sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; - } + // Just use a slop area around the cursor + // Convert rect local to screen coordinates + S32 SLOP = 8; + localPointToScreen( + x - SLOP, y - SLOP, + &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); + sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; + sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; } return TRUE; } @@ -668,21 +704,8 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) // Let scrollbar have first dibs handled = LLView::childrenHandleMouseDown(x, y, mask) != NULL; - // enable I Agree checkbox if the user scrolled through entire text - BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()); - if (mOnScrollEndCallback && was_scrolled_to_bottom) + if( !handled) { - mOnScrollEndCallback(mOnScrollEndData); - } - - if( !handled && mTakesNonScrollClicks) - { - if (!(mask & MASK_SHIFT)) - { - deselect(); - } - - BOOL start_select = TRUE; if( allowsEmbeddedItems() ) { setCursorAtLocalPos( x, y, FALSE ); @@ -705,7 +728,12 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) localPointToScreen(x, y, &screen_x, &screen_y ); LLToolDragAndDrop::getInstance()->setDragStart( screen_x, screen_y ); - start_select = FALSE; + if (hasTabStop()) + { + setFocus( TRUE ); + } + + handled = TRUE; } else { @@ -713,183 +741,42 @@ BOOL LLViewerTextEditor::handleMouseDown(S32 x, S32 y, MASK mask) } } - if( start_select ) + if (!handled) { - // If we're not scrolling (handled by child), then we're selecting - if (mask & MASK_SHIFT) - { - S32 old_cursor_pos = mCursorPos; - setCursorAtLocalPos( x, y, TRUE ); - - if (hasSelection()) - { - /* Mac-like behavior - extend selection towards the cursor - if (mCursorPos < mSelectionStart - && mCursorPos < mSelectionEnd) - { - // ...left of selection - mSelectionStart = llmax(mSelectionStart, mSelectionEnd); - mSelectionEnd = mCursorPos; - } - else if (mCursorPos > mSelectionStart - && mCursorPos > mSelectionEnd) - { - // ...right of selection - mSelectionStart = llmin(mSelectionStart, mSelectionEnd); - mSelectionEnd = mCursorPos; - } - else - { - mSelectionEnd = mCursorPos; - } - */ - // Windows behavior - mSelectionEnd = mCursorPos; - } - else - { - mSelectionStart = old_cursor_pos; - mSelectionEnd = mCursorPos; - } - // assume we're starting a drag select - mIsSelecting = TRUE; - - } - else - { - setCursorAtLocalPos( x, y, TRUE ); - startSelection(); - } - gFocusMgr.setMouseCapture( this ); + handled = LLTextEditor::handleMouseDown(x, y, mask); } - - handled = TRUE; } - if (hasTabStop()) - { - setFocus(TRUE); - handled = TRUE; - } - - // Delay cursor flashing - resetKeystrokeTimer(); - return handled; } BOOL LLViewerTextEditor::handleHover(S32 x, S32 y, MASK mask) { - BOOL handled = FALSE; + BOOL handled = LLTextEditor::handleHover(x, y, mask); - if (!mDragItem) + if(hasMouseCapture() && mDragItem) { - // leave hover segment active during drag and drop - mHoverSegment = NULL; - } - if(hasMouseCapture() ) - { - if( mIsSelecting ) + S32 screen_x; + S32 screen_y; + localPointToScreen(x, y, &screen_x, &screen_y ); + + mScroller->autoScroll(x, y); + + if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) { - if (x != mLastSelectionX || y != mLastSelectionY) - { - mLastSelectionX = x; - mLastSelectionY = y; - } + LLToolDragAndDrop::getInstance()->beginDrag( + LLAssetType::lookupDragAndDropType( mDragItem->getType() ), + mDragItem->getUUID(), + LLToolDragAndDrop::SOURCE_NOTECARD, + mPreviewID, mObjectID); - if( y > getTextRect().mTop ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() - 1 ); - } - else - if( y < getTextRect().mBottom ) - { - mScrollbar->setDocPos( mScrollbar->getDocPos() + 1 ); - } - - setCursorAtLocalPos( x, y, TRUE ); - mSelectionEnd = mCursorPos; - - updateScrollFromCursor(); - getWindow()->setCursor(UI_CURSOR_IBEAM); + return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); } - else if( mDragItem ) - { - S32 screen_x; - S32 screen_y; - localPointToScreen(x, y, &screen_x, &screen_y ); - if( LLToolDragAndDrop::getInstance()->isOverThreshold( screen_x, screen_y ) ) - { - LLToolDragAndDrop::getInstance()->beginDrag( - LLAssetType::lookupDragAndDropType( mDragItem->getType() ), - mDragItem->getUUID(), - LLToolDragAndDrop::SOURCE_NOTECARD, - getSourceID(), mObjectID); - - return LLToolDragAndDrop::getInstance()->handleHover( x, y, mask ); - } - getWindow()->setCursor(UI_CURSOR_HAND); - } - - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (active)" << llendl; + getWindow()->setCursor(UI_CURSOR_HAND); handled = TRUE; } - if( !handled ) - { - // Pass to children - handled = LLView::childrenHandleHover(x, y, mask) != NULL; - } - - if( handled ) - { - // Delay cursor flashing - resetKeystrokeTimer(); - } - - // Opaque - if( !handled && mTakesNonScrollClicks) - { - // Check to see if we're over an HTML-style link - if( !mSegments.empty() ) - { - const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment ) - { - if(cur_segment->getStyle()->isLink()) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over link, inactive)" << llendl; - getWindow()->setCursor(UI_CURSOR_HAND); - handled = TRUE; - } - else - if(cur_segment->getStyle()->getIsEmbeddedItem()) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (over embedded item, inactive)" << llendl; - getWindow()->setCursor(UI_CURSOR_HAND); - //getWindow()->setCursor(UI_CURSOR_ARROW); - handled = TRUE; - } - mHoverSegment = cur_segment; - } - } - - if( !handled ) - { - lldebugst(LLERR_USER_INPUT) << "hover handled by " << getName() << " (inactive)" << llendl; - if (!mScrollbar->getVisible() || x < getRect().getWidth() - SCROLLBAR_SIZE) - { - getWindow()->setCursor(UI_CURSOR_IBEAM); - } - else - { - getWindow()->setCursor(UI_CURSOR_ARROW); - } - handled = TRUE; - } - } - return handled; } @@ -922,13 +809,6 @@ BOOL LLViewerTextEditor::handleMouseUp(S32 x, S32 y, MASK mask) handled = LLTextEditor::handleMouseUp(x,y,mask); - // Used to enable I Agree checkbox if the user scrolled through entire text - BOOL was_scrolled_to_bottom = (mScrollbar->getDocPos() == mScrollbar->getDocPosMax()); - if (mOnScrollEndCallback && was_scrolled_to_bottom) - { - mOnScrollEndCallback(mOnScrollEndData); - } - return handled; } @@ -968,24 +848,6 @@ BOOL LLViewerTextEditor::handleRightMouseDown(S32 x, S32 y, MASK mask) return handled; } -BOOL LLViewerTextEditor::handleMiddleMouseDown(S32 x, S32 y, MASK mask) -{ - BOOL handled = FALSE; - handled = childrenHandleMiddleMouseDown(x, y, mask) != NULL; - if (!handled) - { - handled = LLTextEditor::handleMiddleMouseDown(x, y, mask); - } - return handled; -} - -BOOL LLViewerTextEditor::handleMiddleMouseUp(S32 x, S32 y, MASK mask) -{ - BOOL handled = childrenHandleMiddleMouseUp(x, y, mask) != NULL; - - return handled; -} - BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) { BOOL handled = FALSE; @@ -993,14 +855,15 @@ BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) // let scrollbar have first dibs handled = LLView::childrenHandleDoubleClick(x, y, mask) != NULL; - if( !handled && mTakesNonScrollClicks) + if( !handled) { if( allowsEmbeddedItems() ) { - const LLTextSegment* cur_segment = getSegmentAtLocalPos( x, y ); - if( cur_segment && cur_segment->getStyle()->getIsEmbeddedItem() ) + S32 doc_index = getDocIndexFromLocalCoord(x, y, FALSE); + llwchar doc_char = getWText()[doc_index]; + if (mEmbeddedItemList->hasEmbeddedItem(doc_char)) { - if( openEmbeddedItemAtPos( cur_segment->getStart() ) ) + if( openEmbeddedItemAtPos( doc_index )) { deselect(); setFocus( FALSE ); @@ -1008,54 +871,12 @@ BOOL LLViewerTextEditor::handleDoubleClick(S32 x, S32 y, MASK mask) } } } - - setCursorAtLocalPos( x, y, FALSE ); - deselect(); - - const LLWString &text = getWText(); - - if( isPartOfWord( text[mCursorPos] ) ) - { - // Select word the cursor is over - while ((mCursorPos > 0) && isPartOfWord(text[mCursorPos-1])) - { - mCursorPos--; - } - startSelection(); - - while ((mCursorPos < (S32)text.length()) && isPartOfWord( text[mCursorPos] ) ) - { - mCursorPos++; - } - - mSelectionEnd = mCursorPos; - } - else if ((mCursorPos < (S32)text.length()) && !iswspace( text[mCursorPos]) ) - { - // Select the character the cursor is over - startSelection(); - mCursorPos++; - mSelectionEnd = mCursorPos; - } - - // We don't want handleMouseUp() to "finish" the selection (and thereby - // set mSelectionEnd to where the mouse is), so we finish the selection here. - mIsSelecting = FALSE; - - // delay cursor flashing - resetKeystrokeTimer(); - - // take selection to 'primary' clipboard - updatePrimary(); - - handled = TRUE; + handled = LLTextEditor::handleDoubleClick(x, y, mask); } return handled; } -// Allow calling cards to be dropped onto text fields. Append the name and -// a carriage return. // virtual BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, @@ -1072,95 +893,78 @@ BOOL LLViewerTextEditor::handleDragAndDrop(S32 x, S32 y, MASK mask, return FALSE; } - if (mTakesNonScrollClicks) + if (getEnabled() && acceptsTextInput()) { - if (getEnabled() && acceptsTextInput()) + switch( cargo_type ) { - switch( cargo_type ) + case DAD_CALLINGCARD: + case DAD_TEXTURE: + case DAD_SOUND: + case DAD_LANDMARK: + case DAD_SCRIPT: + case DAD_CLOTHING: + case DAD_OBJECT: + case DAD_NOTECARD: + case DAD_BODYPART: + case DAD_ANIMATION: + case DAD_GESTURE: { - case DAD_CALLINGCARD: - if(acceptsCallingCardNames()) + LLInventoryItem *item = (LLInventoryItem *)cargo_data; + if( item && allowsEmbeddedItems() ) { - if (drop) + U32 mask_next = item->getPermissions().getMaskNextOwner(); + if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) { - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - std::string name = item->getName(); - appendText(name, true, true); + if( drop ) + { + deselect(); + S32 old_cursor = mCursorPos; + setCursorAtLocalPos( x, y, TRUE ); + S32 insert_pos = mCursorPos; + setCursorPos(old_cursor); + BOOL inserted = insertEmbeddedItem( insert_pos, item ); + if( inserted && (old_cursor > mCursorPos) ) + { + setCursorPos(mCursorPos + 1); + } + + needsReflow(); + + } + *accept = ACCEPT_YES_COPY_MULTI; + } + else + { + *accept = ACCEPT_NO; + if (tooltip_msg.empty()) + { + // *TODO: Translate + tooltip_msg.assign("Only items with unrestricted\n" + "'next owner' permissions \n" + "can be attached to notecards."); + } } - *accept = ACCEPT_YES_COPY_SINGLE; } else { *accept = ACCEPT_NO; } break; - - case DAD_TEXTURE: - case DAD_SOUND: - case DAD_LANDMARK: - case DAD_SCRIPT: - case DAD_CLOTHING: - case DAD_OBJECT: - case DAD_NOTECARD: - case DAD_BODYPART: - case DAD_ANIMATION: - case DAD_GESTURE: - { - LLInventoryItem *item = (LLInventoryItem *)cargo_data; - if( item && allowsEmbeddedItems() ) - { - U32 mask_next = item->getPermissions().getMaskNextOwner(); - if((mask_next & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) - { - if( drop ) - { - deselect(); - S32 old_cursor = mCursorPos; - setCursorAtLocalPos( x, y, TRUE ); - S32 insert_pos = mCursorPos; - setCursorPos(old_cursor); - BOOL inserted = insertEmbeddedItem( insert_pos, item ); - if( inserted && (old_cursor > mCursorPos) ) - { - setCursorPos(mCursorPos + 1); - } - - updateLineStartList(); - } - *accept = ACCEPT_YES_COPY_MULTI; - } - else - { - *accept = ACCEPT_NO; - if (tooltip_msg.empty()) - { - tooltip_msg.assign("Only items with unrestricted\n" - "'next owner' permissions \n" - "can be attached to notecards."); - } - } - } - else - { - *accept = ACCEPT_NO; - } - break; - } - - default: - *accept = ACCEPT_NO; - break; } - } - else - { - // Not enabled - *accept = ACCEPT_NO; - } - handled = TRUE; - lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLViewerTextEditor " << getName() << llendl; + default: + *accept = ACCEPT_NO; + break; + } } + else + { + // Not enabled + *accept = ACCEPT_NO; + } + + handled = TRUE; + lldebugst(LLERR_USER_INPUT) << "dragAndDrop handled by LLViewerTextEditor " << getName() << llendl; return handled; } @@ -1246,18 +1050,16 @@ std::string LLViewerTextEditor::appendTime(bool prepend_newline) { time_t utc_time; utc_time = time_corrected(); + std::string timeStr ="[["+ LLTrans::getString("TimeHour")+"]:[" + +LLTrans::getString("TimeMin")+"]] "; - // There's only one internal tm buffer. - struct tm* timep; + LLSD substitution; - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - timep = utc_to_pacific_time(utc_time, gPacificDaylightTime); + substitution["datetime"] = (S32) utc_time; + LLStringUtil::format (timeStr, substitution); + appendColoredText(timeStr, false, prepend_newline, LLColor4::grey); - std::string text = llformat("[%d:%02d] ", timep->tm_hour, timep->tm_min); - appendColoredText(text, false, prepend_newline, LLColor4::grey); - - return text; + return timeStr; } //---------------------------------------------------------------------------- @@ -1282,33 +1084,33 @@ llwchar LLViewerTextEditor::pasteEmbeddedItem(llwchar ext_char) return LL_UNKNOWN_CHAR; // item not found or list full } -void LLViewerTextEditor::bindEmbeddedChars(const LLFontGL* font) const +void LLViewerTextEditor::onValueChange(S32 start, S32 end) { - mEmbeddedItemList->bindEmbeddedChars( font ); + updateSegments(); + findEmbeddedItemSegments(start, end); } -void LLViewerTextEditor::unbindEmbeddedChars(const LLFontGL* font) const +void LLViewerTextEditor::findEmbeddedItemSegments(S32 start, S32 end) { - mEmbeddedItemList->unbindEmbeddedChars( font ); -} + LLWString text = getWText(); -BOOL LLViewerTextEditor::getEmbeddedItemToolTipAtPos(S32 pos, LLWString &msg) const -{ - if (pos < getLength()) + LLColor4 text_color = ( mReadOnly ? mReadOnlyFgColor.get() : mFgColor.get() ); + + // Start with i just after the first embedded item + for(S32 idx = start; idx < end; idx++ ) { - LLInventoryItem* item = LLEmbeddedItems::getEmbeddedItem(getWChar(pos)); - if( item ) + llwchar embedded_char = text[idx]; + if( embedded_char >= FIRST_EMBEDDED_CHAR + && embedded_char <= LAST_EMBEDDED_CHAR + && mEmbeddedItemList->hasEmbeddedItem(embedded_char) ) { - msg = utf8str_to_wstring(item->getName()); - msg += '\n'; - msg += utf8str_to_wstring(item->getDescription()); - return TRUE; + LLInventoryItem* itemp = mEmbeddedItemList->getEmbeddedItem(embedded_char); + LLUIImagePtr image = mEmbeddedItemList->getItemImage(embedded_char); + insertSegment(new LLEmbeddedItemSegment(idx, image, itemp, *this)); } } - return FALSE; } - BOOL LLViewerTextEditor::openEmbeddedItemAtPos(S32 pos) { if( pos < getLength()) @@ -1337,32 +1139,36 @@ BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, llwchar wc) switch( item->getType() ) { - case LLAssetType::AT_TEXTURE: - openEmbeddedTexture( item, wc ); - return TRUE; + case LLAssetType::AT_TEXTURE: + openEmbeddedTexture( item, wc ); + return TRUE; - case LLAssetType::AT_SOUND: - openEmbeddedSound( item, wc ); - return TRUE; + case LLAssetType::AT_SOUND: + openEmbeddedSound( item, wc ); + return TRUE; - case LLAssetType::AT_NOTECARD: - openEmbeddedNotecard( item, wc ); - return TRUE; + case LLAssetType::AT_NOTECARD: + openEmbeddedNotecard( item, wc ); + return TRUE; - case LLAssetType::AT_LANDMARK: - openEmbeddedLandmark( item, wc ); - return TRUE; + case LLAssetType::AT_LANDMARK: + openEmbeddedLandmark( item, wc ); + return TRUE; - case LLAssetType::AT_LSL_TEXT: - case LLAssetType::AT_CLOTHING: - case LLAssetType::AT_OBJECT: - case LLAssetType::AT_BODYPART: - case LLAssetType::AT_ANIMATION: - case LLAssetType::AT_GESTURE: - showCopyToInvDialog( item, wc ); - return TRUE; - default: - return FALSE; + case LLAssetType::AT_CALLINGCARD: + openEmbeddedCallingcard( item, wc ); + return TRUE; + + case LLAssetType::AT_LSL_TEXT: + case LLAssetType::AT_CLOTHING: + case LLAssetType::AT_OBJECT: + case LLAssetType::AT_BODYPART: + case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_GESTURE: + showCopyToInvDialog( item, wc ); + return TRUE; + default: + return FALSE; } } @@ -1370,29 +1176,16 @@ BOOL LLViewerTextEditor::openEmbeddedItem(LLInventoryItem* item, llwchar wc) void LLViewerTextEditor::openEmbeddedTexture( LLInventoryItem* item, llwchar wc ) { - // See if we can bring an existing preview to the front // *NOTE: Just for embedded Texture , we should use getAssetUUID(), // not getUUID(), because LLPreviewTexture pass in AssetUUID into // LLPreview constructor ItemUUID parameter. - - if( !LLPreview::show( item->getAssetUUID() ) ) + if (!item) + return; + LLPreviewTexture* preview = LLFloaterReg::showTypedInstance("preview_texture", LLSD(item->getAssetUUID()), TAKE_FOCUS_YES); + if (preview) { - // There isn't one, so make a new preview - if(item) - { - S32 left, top; - gFloaterView->getNewFloaterPosition(&left, &top); - LLRect rect = gSavedSettings.getRect("PreviewTextureRect"); - rect.translate( left - rect.mLeft, top - rect.mTop ); - - LLPreviewTexture* preview = new LLPreviewTexture("preview texture", - rect, - item->getName(), - item->getAssetUUID(), - TRUE); - preview->setAuxItem( item ); - preview->setNotecardInfo(mNotecardInventoryID, mObjectID); - } + preview->setAuxItem( item ); + preview->setNotecardInfo(mNotecardInventoryID, mObjectID); } } @@ -1411,9 +1204,18 @@ void LLViewerTextEditor::openEmbeddedSound( LLInventoryItem* item, llwchar wc ) void LLViewerTextEditor::openEmbeddedLandmark( LLInventoryItem* item, llwchar wc ) { - std::string title = - std::string(" ") + LLLandmarkBridge::prefix() + item->getName(); - open_landmark((LLViewerInventoryItem*)item, title, FALSE, item->getUUID(), TRUE); + if (!item) + return; + + LLSD key; + key["type"] = "landmark"; + key["id"] = item->getUUID(); + + LLPanelPlaces *panel = dynamic_cast(LLSideTray::getInstance()->showPanel("panel_places", key)); + if (panel) + { + panel->setItem(item); + } } void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item, llwchar wc ) @@ -1421,6 +1223,14 @@ void LLViewerTextEditor::openEmbeddedNotecard( LLInventoryItem* item, llwchar wc copyInventory(item, gInventoryCallbacks.registerCB(mInventoryCallback)); } +void LLViewerTextEditor::openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc ) +{ + if(item && !item->getCreatorUUID().isNull()) + { + LLAvatarActions::showProfile(item->getCreatorUUID()); + } +} + void LLViewerTextEditor::showUnsavedAlertDialog( LLInventoryItem* item ) { LLSD payload; @@ -1435,9 +1245,11 @@ bool LLViewerTextEditor::onNotecardDialog(const LLSD& notification, const LLSD& S32 option = LLNotification::getSelectedOption(notification, response); if( option == 0 ) { - // itemptr is deleted by LLPreview::save - LLPointer* itemptr = new LLPointer(gInventory.getItem(notification["payload"]["item_id"].asUUID())); - LLPreview::save( notification["payload"]["notecard_id"].asUUID() , itemptr); + LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance("preview_notecard", notification["payload"]["notecard_id"]);; + if (preview) + { + preview->saveItem(); + } } return false; } @@ -1541,61 +1353,3 @@ BOOL LLViewerTextEditor::exportBuffer( std::string& buffer ) return TRUE; } -LLView* LLViewerTextEditor::fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory) -{ - std::string name("text_editor"); - node->getAttributeString("name", name); - - LLRect rect; - createRect(node, rect, parent, LLRect()); - - U32 max_text_length = 255; - node->getAttributeU32("max_length", max_text_length); - - BOOL allow_embedded_items = FALSE; - node->getAttributeBOOL("embedded_items", allow_embedded_items); - - LLFontGL* font = LLView::selectFont(node); - - // std::string text = node->getValue(); - std::string text = node->getTextContents().substr(0, max_text_length - 1); - - if (text.size() > max_text_length) - { - // Erase everything from max_text_length on. - text.erase(max_text_length); - } - - LLViewerTextEditor* text_editor = new LLViewerTextEditor(name, - rect, - max_text_length, - LLStringUtil::null, - font, - allow_embedded_items); - - BOOL ignore_tabs = text_editor->tabsToNextField(); - node->getAttributeBOOL("ignore_tab", ignore_tabs); - text_editor->setTabsToNextField(ignore_tabs); - - text_editor->setTextEditorParameters(node); - - BOOL hide_scrollbar = FALSE; - node->getAttributeBOOL("hide_scrollbar",hide_scrollbar); - text_editor->setHideScrollbarForShortDocs(hide_scrollbar); - - BOOL hide_border = !text_editor->isBorderVisible(); - node->getAttributeBOOL("hide_border", hide_border); - text_editor->setBorderVisible(!hide_border); - - BOOL parse_html = text_editor->mParseHTML; - node->getAttributeBOOL("allow_html", parse_html); - text_editor->setParseHTML(parse_html); - text_editor->setParseHighlights(TRUE); - - text_editor->initFromXML(node, parent); - - // add text after all parameters have been set - text_editor->appendStyledText(text, FALSE, FALSE); - - return text_editor; -} diff --git a/indra/newview/llviewertexteditor.h b/indra/newview/llviewertexteditor.h index f29caee602..9567bfbc48 100644 --- a/indra/newview/llviewertexteditor.h +++ b/indra/newview/llviewertexteditor.h @@ -41,26 +41,30 @@ // class LLViewerTextEditor : public LLTextEditor { - public: - LLViewerTextEditor(const std::string& name, - const LLRect& rect, - S32 max_length, - const std::string& default_text = std::string(), - const LLFontGL* glfont = NULL, - BOOL allow_embedded_items = FALSE); + struct Params : public LLInitParam::Block + { + Optional allow_html; + Params() + : allow_html("allow_html", false) + { + name = "text_editor"; + } + }; + +protected: + LLViewerTextEditor(const Params&); + friend class LLUICtrlFactory; + +public: virtual ~LLViewerTextEditor(); virtual void makePristine(); - static LLView* fromXML(LLXMLNodePtr node, LLView *parent, LLUICtrlFactory *factory); - // mousehandler overrides 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); - virtual BOOL handleMiddleMouseUp(S32 x, S32 y, MASK mask); virtual BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); virtual BOOL handleHover(S32 x, S32 y, MASK mask); virtual BOOL handleDoubleClick(S32 x, S32 y, MASK mask ); @@ -74,10 +78,13 @@ public: virtual BOOL importBuffer(const char* buffer, S32 length); virtual bool importStream(std::istream& str); virtual BOOL exportBuffer(std::string& buffer); - void setNotecardInfo(const LLUUID& notecard_item_id, const LLUUID& object_id) + virtual void onValueChange(S32 start, S32 end); + + void setNotecardInfo(const LLUUID& notecard_item_id, const LLUUID& object_id, const LLUUID& preview_id) { mNotecardInventoryID = notecard_item_id; mObjectID = object_id; + mPreviewID = preview_id; } void setASCIIEmbeddedText(const std::string& instr); @@ -99,11 +106,9 @@ public: private: // Embedded object operations + void findEmbeddedItemSegments(S32 start, S32 end); virtual llwchar pasteEmbeddedItem(llwchar ext_char); - virtual void bindEmbeddedChars(const LLFontGL* font) const; - virtual void unbindEmbeddedChars(const LLFontGL* font) const; - BOOL getEmbeddedItemToolTipAtPos(S32 pos, LLWString &wmsg) const; BOOL openEmbeddedItemAtPos( S32 pos ); BOOL openEmbeddedItem(LLInventoryItem* item, llwchar wc); @@ -113,6 +118,7 @@ private: void openEmbeddedSound( LLInventoryItem* item, llwchar wc ); void openEmbeddedLandmark( LLInventoryItem* item, llwchar wc ); void openEmbeddedNotecard( LLInventoryItem* item, llwchar wc); + void openEmbeddedCallingcard( LLInventoryItem* item, llwchar wc); void showCopyToInvDialog( LLInventoryItem* item, llwchar wc ); void showUnsavedAlertDialog( LLInventoryItem* item ); @@ -120,12 +126,14 @@ private: static bool onNotecardDialog(const LLSD& notification, const LLSD& response ); LLPointer mDragItem; + LLTextSegment* mDragSegment; llwchar mDragItemChar; BOOL mDragItemSaved; class LLEmbeddedItems* mEmbeddedItemList; LLUUID mObjectID; LLUUID mNotecardInventoryID; + LLUUID mPreviewID; LLPointer mInventoryCallback; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp new file mode 100644 index 0000000000..6ea1522b47 --- /dev/null +++ b/indra/newview/llviewertexture.cpp @@ -0,0 +1,2386 @@ +/** + * @file llviewertexture.cpp + * @brief Object which handles a received image (and associated texture(s)) + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llviewertexture.h" + +// Library includes +#include "imageids.h" +#include "llmath.h" +#include "llerror.h" +#include "llgl.h" +#include "llglheaders.h" +#include "llhost.h" +#include "llimage.h" +#include "llimagebmp.h" +#include "llimagej2c.h" +#include "llimagetga.h" +#include "llmemtype.h" +#include "llstl.h" +#include "llvfile.h" +#include "llvfs.h" +#include "message.h" +#include "lltimer.h" + +// viewer includes +#include "llimagegl.h" +#include "lldrawpool.h" +#include "lltexturefetch.h" +#include "llviewertexturelist.h" +#include "llviewercontrol.h" +#include "pipeline.h" +#include "llappviewer.h" +/////////////////////////////////////////////////////////////////////////////// + +// statics +LLPointer LLViewerTexture::sNullImagep = NULL; +LLPointer LLViewerFetchedTexture::sMissingAssetImagep = NULL; +LLPointer LLViewerFetchedTexture::sWhiteImagep = NULL; +LLPointer LLViewerFetchedTexture::sDefaultImagep = NULL; +LLPointer LLViewerFetchedTexture::sSmokeImagep = NULL; +LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap ; +LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL ; + +S32 LLViewerTexture::sImageCount = 0; +S32 LLViewerTexture::sRawCount = 0; +S32 LLViewerTexture::sAuxCount = 0; +LLTimer LLViewerTexture::sEvaluationTimer; +F32 LLViewerTexture::sDesiredDiscardBias = 0.f; +F32 LLViewerTexture::sDesiredDiscardScale = 1.1f; +S32 LLViewerTexture::sBoundTextureMemoryInBytes = 0; +S32 LLViewerTexture::sTotalTextureMemoryInBytes = 0; +S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0; +S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0; +S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ; +BOOL LLViewerTexture::sDontLoadVolumeTextures = FALSE; + +const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by +const F32 desired_discard_bias_max = 1.5f; // max number of levels to reduce image quality by + +//---------------------------------------------------------------------------------------------- +//namespace: LLViewerTextureAccess +//---------------------------------------------------------------------------------------------- +LLViewerMediaTexture* LLViewerTextureManager::createMediaTexture(const LLUUID &media_id, BOOL usemipmaps, LLImageGL* gl_image) +{ + return new LLViewerMediaTexture(media_id, usemipmaps, gl_image) ; +} + +LLViewerTexture* LLViewerTextureManager::findTexture(const LLUUID& id) +{ + LLViewerTexture* tex ; + //search fetched texture list + tex = gTextureList.findImage(id) ; + + //search media texture list + if(!tex) + { + tex = LLViewerTextureManager::findMediaTexture(id) ; + } + return tex ; +} + +LLViewerMediaTexture* LLViewerTextureManager::findMediaTexture(const LLUUID &media_id) +{ + LLViewerMediaTexture::media_map_t::iterator iter = LLViewerMediaTexture::sMediaMap.find(media_id); + if(iter == LLViewerMediaTexture::sMediaMap.end()) + return NULL; + + ((LLViewerMediaTexture*)(iter->second))->getLastReferencedTimer()->reset() ; + return iter->second; +} + +LLViewerMediaTexture* LLViewerTextureManager::getMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) +{ + LLViewerMediaTexture* tex = LLViewerTextureManager::findMediaTexture(id) ; + if(!tex) + { + tex = LLViewerTextureManager::createMediaTexture(id, usemipmaps, gl_image) ; + } + + LLViewerTexture* old_tex = tex->getOldTexture() ; + if(!old_tex) + { + //if there is a fetched texture with the same id, replace it by this media texture + old_tex = gTextureList.findImage(id) ; + if(old_tex) + { + tex->setOldTexture(old_tex) ; + } + } + + if (gSavedSettings.getBOOL("ParcelMediaAutoPlayEnable") && gSavedSettings.getBOOL("AudioStreamingVideo")) + { + if(!tex->isPlaying()) + { + if(old_tex) + { + old_tex->switchToTexture(tex) ; + } + tex->setPlaying(TRUE) ; + } + } + tex->getLastReferencedTimer()->reset() ; + + return tex ; +} + +LLViewerFetchedTexture* LLViewerTextureManager::staticCastToFetchedTexture(LLViewerTexture* tex, BOOL report_error) +{ + if(!tex) + { + return NULL ; + } + + S8 type = tex->getType() ; + if(type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + { + return static_cast(tex) ; + } + + if(report_error) + { + llerrs << "not a fetched texture type: " << type << llendl ; + } + + return NULL ; +} + +LLPointer LLViewerTextureManager::getLocalTexture(BOOL usemipmaps, BOOL generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(usemipmaps) ; + if(generate_gl_tex) + { + tex->generateGLTexture() ; + } + return tex ; +} +LLPointer LLViewerTextureManager::getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(id, usemipmaps) ; + if(generate_gl_tex) + { + tex->generateGLTexture() ; + } + return tex ; +} +LLPointer LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) +{ + LLPointer tex = new LLViewerTexture(raw, usemipmaps) ; + return tex ; +} +LLPointer LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex) +{ + LLPointer tex = new LLViewerTexture(width, height, components, usemipmaps) ; + if(generate_gl_tex) + { + tex->generateGLTexture() ; + } + return tex ; +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture( + const LLUUID &image_id, + BOOL usemipmaps, + BOOL level_immediate, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + LLHost request_from_host) +{ + return gTextureList.getImage(image_id, usemipmaps, level_immediate, texture_type, internal_format, primary_format, request_from_host) ; +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile( + const std::string& filename, + BOOL usemipmaps, + BOOL level_immediate, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + const LLUUID& force_id) +{ + return gTextureList.getImageFromFile(filename, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id) ; +} + +LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) +{ + return gTextureList.getImageFromHost(image_id, host) ; +} + +void LLViewerTextureManager::init() +{ + LLPointer raw = new LLImageRaw(1,1,3); + raw->clear(0x77, 0x77, 0x77, 0xFF); + LLViewerTexture::sNullImagep = LLViewerTextureManager::getLocalTexture(raw.get(), TRUE) ; + +#if 1 + LLPointer imagep = new LLViewerFetchedTexture(IMG_DEFAULT, TRUE); + LLViewerFetchedTexture::sDefaultImagep = imagep; + + const S32 dim = 128; + LLPointer image_raw = new LLImageRaw(dim,dim,3); + U8* data = image_raw->getData(); + for (S32 i = 0; i=(dim-border) || j>=(dim-border)) + { + *data++ = 0xff; + *data++ = 0xff; + *data++ = 0xff; + } + else +#endif + { + *data++ = 0x7f; + *data++ = 0x7f; + *data++ = 0x7f; + } + } + } + imagep->createGLTexture(0, image_raw); + image_raw = NULL; + gTextureList.addImage(imagep); + LLViewerFetchedTexture::sDefaultImagep->dontDiscard(); +#else + LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE); +#endif + + LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, TRUE, TRUE); + LLViewerFetchedTexture::sSmokeImagep->setNoDelete() ; + + LLViewerTexture::initClass() ; + + if(LLFastTimer::sMetricLog) + { + LLViewerTextureManager::sTesterp = new LLTexturePipelineTester() ; + } +} + +void LLViewerTextureManager::cleanup() +{ + stop_glerror(); + + LLImageGL::sDefaultGLTexture = NULL ; + LLViewerTexture::sNullImagep = NULL; + LLViewerFetchedTexture::sDefaultImagep = NULL; + LLViewerFetchedTexture::sSmokeImagep = NULL; + LLViewerFetchedTexture::sMissingAssetImagep = NULL; + LLViewerFetchedTexture::sWhiteImagep = NULL; + + LLViewerMediaTexture::sMediaMap.clear() ; +} + +//---------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------- +//start of LLViewerTexture +//---------------------------------------------------------------------------------------------- +// static +void LLViewerTexture::initClass() +{ + LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ; +} + +// static +void LLViewerTexture::cleanupClass() +{ +} + +// tuning params +const F32 discard_bias_delta = .05f; +const F32 discard_delta_time = 0.5f; +const S32 min_non_tex_system_mem = (128<<20); // 128 MB +// non-const (used externally +F32 texmem_lower_bound_scale = 0.85f; +F32 texmem_middle_bound_scale = 0.925f; + +//static +void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity) +{ + if(LLViewerTextureManager::sTesterp) + { + LLViewerTextureManager::sTesterp->update() ; + } + LLViewerMediaTexture::updateClass() ; + + sBoundTextureMemoryInBytes = LLImageGL::sBoundTextureMemoryInBytes;//in bytes + sTotalTextureMemoryInBytes = LLImageGL::sGlobalTextureMemoryInBytes;//in bytes + sMaxBoundTextureMemInMegaBytes = gTextureList.getMaxResidentTexMem();//in MB + sMaxTotalTextureMemInMegaBytes = gTextureList.getMaxTotalTextureMem() ;//in MB + sMaxDesiredTextureMemInBytes = MEGA_BYTES_TO_BYTES(sMaxTotalTextureMemInMegaBytes) ; //in Bytes, by default and when total used texture memory is small. + + if (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) >= sMaxBoundTextureMemInMegaBytes || + BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) >= sMaxTotalTextureMemInMegaBytes) + { + //when texture memory overflows, lower down the threashold to release the textures more aggressively. + sMaxDesiredTextureMemInBytes = llmin((S32)(sMaxDesiredTextureMemInBytes * 0.75f) , MEGA_BYTES_TO_BYTES(MAX_VIDEO_RAM_IN_MEGA_BYTES)) ;//512 MB + + // If we are using more texture memory than we should, + // scale up the desired discard level + if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time) + { + sDesiredDiscardBias += discard_bias_delta; + sEvaluationTimer.reset(); + } + } + else if (sDesiredDiscardBias > 0.0f && + BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < sMaxBoundTextureMemInMegaBytes * texmem_lower_bound_scale && + BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < sMaxTotalTextureMemInMegaBytes * texmem_lower_bound_scale) + { + // If we are using less texture memory than we should, + // scale down the desired discard level + if (sEvaluationTimer.getElapsedTimeF32() > discard_delta_time) + { + sDesiredDiscardBias -= discard_bias_delta; + sEvaluationTimer.reset(); + } + } + sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max); +} + +//end of static functions +//------------------------------------------------------------------------------------------- +const U32 LLViewerTexture::sCurrentFileVersion = 1; + +LLViewerTexture::LLViewerTexture(BOOL usemipmaps) +{ + init(true); + mUseMipMaps = usemipmaps ; + + mID.generate(); + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const LLUUID& id, BOOL usemipmaps) + : mID(id) +{ + init(true); + mUseMipMaps = usemipmaps ; + + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) +{ + init(true); + + mFullWidth = width ; + mFullHeight = height ; + mUseMipMaps = usemipmaps ; + mComponents = components ; + + mID.generate(); + sImageCount++; +} + +LLViewerTexture::LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) +{ + init(true); + mUseMipMaps = usemipmaps ; + mGLTexturep = new LLImageGL(raw, usemipmaps) ; + + // Create an empty image of the specified size and width + mID.generate(); + sImageCount++; +} + +LLViewerTexture::~LLViewerTexture() +{ + sImageCount--; +} + +void LLViewerTexture::init(bool firstinit) +{ + mBoostLevel = LLViewerTexture::BOOST_NONE; + + mFullWidth = 0; + mFullHeight = 0; + mUseMipMaps = FALSE ; + mComponents = 0 ; + + mTextureState = NO_DELETE ; + mDontDiscard = FALSE; + mMaxVirtualSize = 0.f; +} + +//virtual +S8 LLViewerTexture::getType() const +{ + return LLViewerTexture::LOCAL_TEXTURE ; +} + +void LLViewerTexture::cleanup() +{ + mFaceList.clear() ; + + if(mGLTexturep) + { + mGLTexturep->cleanup(); + } +} + +// virtual +void LLViewerTexture::dump() +{ + if(mGLTexturep) + { + mGLTexturep->dump(); + } + + llinfos << "LLViewerTexture" + << " mID " << mID + << llendl; +} + +void LLViewerTexture::setBoostLevel(S32 level) +{ + if(mBoostLevel != level) + { + mBoostLevel = level ; + if(mBoostLevel != LLViewerTexture::BOOST_NONE) + { + setNoDelete() ; + } + } +} + + +bool LLViewerTexture::bindDefaultImage(S32 stage) const +{ + if (stage < 0) return false; + + bool res = true; + if (LLViewerFetchedTexture::sDefaultImagep.notNull() && (this != LLViewerFetchedTexture::sDefaultImagep.get())) + { + // use default if we've got it + res = gGL.getTexUnit(stage)->bind(LLViewerFetchedTexture::sDefaultImagep); + } + if (!res && LLViewerTexture::sNullImagep.notNull() && (this != LLViewerTexture::sNullImagep)) + { + res = gGL.getTexUnit(stage)->bind(LLViewerTexture::sNullImagep) ; + } + if (!res) + { + llwarns << "LLViewerTexture::bindDefaultImage failed." << llendl; + } + stop_glerror(); + if(LLViewerTextureManager::sTesterp) + { + LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ; + } + return res; +} + +//virtual +BOOL LLViewerTexture::isMissingAsset()const +{ + return FALSE; +} + +//virtual +void LLViewerTexture::forceImmediateUpdate() +{ +} + +void LLViewerTexture::addTextureStats(F32 virtual_size) const +{ + if (virtual_size > mMaxVirtualSize) + { + mMaxVirtualSize = virtual_size; + } +} + +void LLViewerTexture::resetTextureStats(BOOL zero) +{ + if (zero) + { + mMaxVirtualSize = 0.0f; + } + else + { + mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update + } +} + +void LLViewerTexture::addFace(LLFace* facep) +{ + mFaceList.push_back(facep) ; +} +void LLViewerTexture::removeFace(LLFace* facep) +{ + mFaceList.remove(facep) ; +} + +void LLViewerTexture::switchToTexture(LLViewerTexture* new_texture) +{ + if(this == new_texture) + { + return ; + } + + new_texture->addTextureStats(getMaxVirtualSize()) ; + + for(ll_face_list_t::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ) + { + LLFace* facep = *iter++ ; + facep->setTexture(new_texture) ; + facep->getViewerObject()->changeTEImage(this, new_texture) ; + gPipeline.markTextured(facep->getDrawable()); + } +} + +void LLViewerTexture::forceActive() +{ + mTextureState = ACTIVE ; +} + +void LLViewerTexture::setActive() +{ + if(mTextureState != NO_DELETE) + { + mTextureState = ACTIVE ; + } +} + +//set the texture to stay in memory +void LLViewerTexture::setNoDelete() +{ + mTextureState = NO_DELETE ; +} + +void LLViewerTexture::generateGLTexture() +{ + if(mGLTexturep.isNull()) + { + mGLTexturep = new LLImageGL(mFullWidth, mFullHeight, mComponents, mUseMipMaps) ; + } +} + +LLImageGL* LLViewerTexture::getGLTexture() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep ; +} + +BOOL LLViewerTexture::createGLTexture() +{ + if(mGLTexturep.isNull()) + { + generateGLTexture() ; + } + + return mGLTexturep->createGLTexture() ; +} + +BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename) +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->createGLTexture(discard_level, imageraw, usename) ; +} + +void LLViewerTexture::setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes) +{ + llassert_always(mGLTexturep.notNull()) ; + + mGLTexturep->setExplicitFormat(internal_format, primary_format, type_format, swap_bytes) ; +} +void LLViewerTexture::setAddressMode(LLTexUnit::eTextureAddressMode mode) +{ + llassert_always(mGLTexturep.notNull()) ; + mGLTexturep->setAddressMode(mode) ; +} +void LLViewerTexture::setFilteringOption(LLTexUnit::eTextureFilterOptions option) +{ + llassert_always(mGLTexturep.notNull()) ; + mGLTexturep->setFilteringOption(option) ; +} + +//virtual +S32 LLViewerTexture::getWidth(S32 discard_level) const +{ + llassert_always(mGLTexturep.notNull()) ; + return mGLTexturep->getWidth(discard_level) ; +} + +//virtual +S32 LLViewerTexture::getHeight(S32 discard_level) const +{ + llassert_always(mGLTexturep.notNull()) ; + return mGLTexturep->getHeight(discard_level) ; +} + +S32 LLViewerTexture::getMaxDiscardLevel() const +{ + llassert_always(mGLTexturep.notNull()) ; + return mGLTexturep->getMaxDiscardLevel() ; +} +S32 LLViewerTexture::getDiscardLevel() const +{ + llassert_always(mGLTexturep.notNull()) ; + return mGLTexturep->getDiscardLevel() ; +} +S8 LLViewerTexture::getComponents() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getComponents() ; +} + +LLGLuint LLViewerTexture::getTexName() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getTexName() ; +} + +BOOL LLViewerTexture::hasValidGLTexture() const +{ + if(mGLTexturep.notNull()) + { + return mGLTexturep->getHasGLTexture() ; + } + return FALSE ; +} + +BOOL LLViewerTexture::hasGLTexture() const +{ + return mGLTexturep.notNull() ; +} + +BOOL LLViewerTexture::getBoundRecently() const +{ + if(mGLTexturep.notNull()) + { + return mGLTexturep->getBoundRecently() ; + } + return FALSE ; +} + +LLTexUnit::eTextureType LLViewerTexture::getTarget(void) const +{ + llassert_always(mGLTexturep.notNull()) ; + return mGLTexturep->getTarget() ; +} + +BOOL LLViewerTexture::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->setSubImage(imageraw, x_pos, y_pos, width, height) ; +} + +BOOL LLViewerTexture::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height) +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->setSubImage(datap, data_width, data_height, x_pos, y_pos, width, height) ; +} + +void LLViewerTexture::setGLTextureCreated (bool initialized) +{ + llassert_always(mGLTexturep.notNull()) ; + + mGLTexturep->setGLTextureCreated (initialized) ; +} + +LLTexUnit::eTextureAddressMode LLViewerTexture::getAddressMode(void) const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getAddressMode() ; +} + +S32 LLViewerTexture::getTextureMemory() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->mTextureMemory ; +} + +LLGLenum LLViewerTexture::getPrimaryFormat() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getPrimaryFormat() ; +} + +BOOL LLViewerTexture::getIsAlphaMask() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getIsAlphaMask() ; +} + +BOOL LLViewerTexture::getMask(const LLVector2 &tc) +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getMask(tc) ; +} + +F32 LLViewerTexture::getTimePassedSinceLastBound() +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getTimePassedSinceLastBound() ; +} +BOOL LLViewerTexture::getMissed() const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->getMissed() ; +} + +BOOL LLViewerTexture::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->isValidForSculpt(discard_level, image_width, image_height, ncomponents) ; +} + +BOOL LLViewerTexture::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const +{ + llassert_always(mGLTexturep.notNull()) ; + + return mGLTexturep->readBackRaw(discard_level, imageraw, compressed_ok) ; +} + +void LLViewerTexture::destroyGLTexture() +{ + if(mGLTexturep.notNull() && mGLTexturep->getHasGLTexture()) + { + mGLTexturep->destroyGLTexture() ; + mTextureState = DELETED ; + } +} + +//virtual +void LLViewerTexture::updateBindStatsForTester() +{ + if(LLViewerTextureManager::sTesterp) + { + LLViewerTextureManager::sTesterp->updateTextureBindingStats(this) ; + } +} +//---------------------------------------------------------------------------------------------- +//end of LLViewerTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLViewerFetchedTexture +//---------------------------------------------------------------------------------------------- + +//static +F32 LLViewerFetchedTexture::maxDecodePriority() +{ + return 2000000.f; +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps) + : LLViewerTexture(id, usemipmaps) +{ + init(TRUE) ; + generateGLTexture() ; +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps) + : LLViewerTexture(raw, usemipmaps) +{ + init(TRUE) ; +} + +LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps) + : LLViewerTexture(id, usemipmaps), + mLocalFileName(full_path) +{ + init(TRUE) ; + generateGLTexture() ; +} + +void LLViewerFetchedTexture::init(bool firstinit) +{ + mOrigWidth = 0; + mOrigHeight = 0; + mNeedsAux = FALSE; + mRequestedDiscardLevel = -1; + mRequestedDownloadPriority = 0.f; + mFullyLoaded = FALSE; + mDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + mMinDesiredDiscardLevel = MAX_DISCARD_LEVEL + 1; + + mDecodingAux = FALSE; + + mKnownDrawWidth = 0; + mKnownDrawHeight = 0; + + if (firstinit) + { + mDecodePriority = 0.f; + mInImageList = 0; + } + + // Only set mIsMissingAsset true when we know for certain that the database + // does not contain this image. + mIsMissingAsset = FALSE; + + mNeedsCreateTexture = FALSE; + + mIsRawImageValid = FALSE; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; + mMinDiscardLevel = 0; + + mHasFetcher = FALSE; + mIsFetching = FALSE; + mFetchState = 0; + mFetchPriority = 0; + mDownloadProgress = 0.f; + mFetchDeltaTime = 999999.f; + mDecodeFrame = 0; + mVisibleFrame = 0; + mForSculpt = FALSE ; + mIsFetched = FALSE ; +} + +LLViewerFetchedTexture::~LLViewerFetchedTexture() +{ + //*NOTE getTextureFetch can return NULL when Viewer is shutting down. + // This is due to LLWearableList is singleton and is destroyed after + // LLAppViewer::cleanup() was called. (see ticket EXT-177) + if (mHasFetcher && LLAppViewer::getTextureFetch()) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + } + cleanup(); +} + +//virtual +S8 LLViewerFetchedTexture::getType() const +{ + return LLViewerTexture::FETCHED_TEXTURE ; +} + +void LLViewerFetchedTexture::cleanup() +{ + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback( FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData ); + delete entryp; + } + mLoadedCallbackList.clear(); + mNeedsAux = FALSE; + + // Clean up image data + destroyRawImage(); +} + +void LLViewerFetchedTexture::setForSculpt() +{ + mForSculpt = TRUE ; +} + +BOOL LLViewerFetchedTexture::isDeleted() +{ + return mTextureState == DELETED ; +} + +BOOL LLViewerFetchedTexture::isInactive() +{ + return mTextureState == INACTIVE ; +} + +BOOL LLViewerFetchedTexture::isDeletionCandidate() +{ + return mTextureState == DELETION_CANDIDATE ; +} + +void LLViewerFetchedTexture::setDeletionCandidate() +{ + if(mGLTexturep.notNull() && mGLTexturep->getTexName() && (mTextureState == INACTIVE)) + { + mTextureState = DELETION_CANDIDATE ; + } +} + +//set the texture inactive +void LLViewerFetchedTexture::setInactive() +{ + if(mTextureState == ACTIVE && mGLTexturep.notNull() && mGLTexturep->getTexName() && !mGLTexturep->getBoundRecently()) + { + mTextureState = INACTIVE ; + } +} + +// virtual +void LLViewerFetchedTexture::dump() +{ + LLViewerTexture::dump(); + + llinfos << "LLViewerFetchedTexture" + << " mIsMissingAsset " << (S32)mIsMissingAsset + << " mFullWidth " << mFullWidth + << " mFullHeight " << mFullHeight + << " mOrigWidth" << mOrigWidth + << " mOrigHeight" << mOrigHeight + << llendl; +} + +/////////////////////////////////////////////////////////////////////////////// +// ONLY called from LLViewerFetchedTextureList +void LLViewerFetchedTexture::destroyTexture() +{ + if(LLImageGL::sGlobalTextureMemoryInBytes < sMaxDesiredTextureMemInBytes)//not ready to release unused memory. + { + return ; + } + if (mNeedsCreateTexture)//return if in the process of generating a new texture. + { + return ; + } + + destroyGLTexture() ; + mFullyLoaded = FALSE ; +} + +// ONLY called from LLViewerTextureList +BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/) +{ + if (!mNeedsCreateTexture) + { + destroyRawImage(); + return FALSE; + } + mNeedsCreateTexture = FALSE; + if (mRawImage.isNull()) + { + llerrs << "LLViewerTexture trying to create texture with no Raw Image" << llendl; + } +// llinfos << llformat("IMAGE Creating (%d) [%d x %d] Bytes: %d ", +// mRawDiscardLevel, +// mRawImage->getWidth(), mRawImage->getHeight(),mRawImage->getDataSize()) +// << mID.getString() << llendl; + BOOL res = TRUE; + if (!gNoRender) + { + // store original size only for locally-sourced images + if (!mLocalFileName.empty()) + { + mOrigWidth = mRawImage->getWidth(); + mOrigHeight = mRawImage->getHeight(); + + // leave black border, do not scale image content + mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE); + + mFullWidth = mRawImage->getWidth(); + mFullHeight = mRawImage->getHeight(); + } + else + { + mOrigWidth = mFullWidth; + mOrigHeight = mFullHeight; + } + + bool size_okay = true; + + U32 raw_width = mRawImage->getWidth() << mRawDiscardLevel; + U32 raw_height = mRawImage->getHeight() << mRawDiscardLevel; + if( raw_width > MAX_IMAGE_SIZE || raw_height > MAX_IMAGE_SIZE ) + { + llinfos << "Width or height is greater than " << MAX_IMAGE_SIZE << ": (" << raw_width << "," << raw_height << ")" << llendl; + size_okay = false; + } + + if (!LLImageGL::checkSize(mRawImage->getWidth(), mRawImage->getHeight())) + { + // A non power-of-two image was uploaded (through a non standard client) + llinfos << "Non power of two width or height: (" << mRawImage->getWidth() << "," << mRawImage->getHeight() << ")" << llendl; + size_okay = false; + } + + if( !size_okay ) + { + // An inappropriately-sized image was uploaded (through a non standard client) + // We treat these images as missing assets which causes them to + // be renderd as 'missing image' and to stop requesting data + setIsMissingAsset(); + destroyRawImage(); + return FALSE; + } + + res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename); + setActive() ; + } + + // + // Iterate through the list of image loading callbacks to see + // what sort of data they need. + // + // *TODO: Fix image callback code + BOOL imageraw_callbacks = FALSE; + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + if (entryp->mNeedsImageRaw) + { + imageraw_callbacks = TRUE; + break; + } + } + + if (!imageraw_callbacks) + { + mNeedsAux = FALSE; + destroyRawImage(); + } + return res; +} + +// Call with 0,0 to turn this feature off. +void LLViewerFetchedTexture::setKnownDrawSize(S32 width, S32 height) +{ + mKnownDrawWidth = width; + mKnownDrawHeight = height; + addTextureStats((F32)(width * height)); +} + +//virtual +void LLViewerFetchedTexture::processTextureStats() +{ + if(mFullyLoaded)//already loaded + { + return ; + } + + if(!mFullWidth || !mFullHeight) + { + mDesiredDiscardLevel = getMaxDiscardLevel() ; + } + else + { + mDesiredDiscardLevel = 0; + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + { + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + + if(getDiscardLevel() >= 0 && (getDiscardLevel() <= mDesiredDiscardLevel)) + { + mFullyLoaded = TRUE ; + } + } +} + +//texture does not have any data, so we don't know the size of the image, treat it like 32 * 32. +F32 LLViewerFetchedTexture::calcDecodePriorityForUnknownTexture(F32 pixel_priority) +{ + static const F64 log_2 = log(2.0); + + F32 desired = (F32)(log(32.0/pixel_priority) / log_2); + S32 ddiscard = MAX_DISCARD_LEVEL - (S32)desired + 1; + ddiscard = llclamp(ddiscard, 1, 9); + + return ddiscard*100000.f; +} + +F32 LLViewerFetchedTexture::calcDecodePriority() +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (mID == LLAppViewer::getTextureFetch()->mDebugID) + { + LLAppViewer::getTextureFetch()->mDebugCount++; // for setting breakpoints + } +#endif + + if(mFullyLoaded)//already loaded for static texture + { + return -4.0f ; //alreay fetched + } + + if (mNeedsCreateTexture) + { + return mDecodePriority; // no change while waiting to create + } + + F32 priority; + S32 cur_discard = getDiscardLevel(); + bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel)); + F32 pixel_priority = fsqrtf(mMaxVirtualSize); + const S32 MIN_NOT_VISIBLE_FRAMES = 30; // NOTE: this function is not called every frame + mDecodeFrame++; + if (pixel_priority > 0.f) + { + mVisibleFrame = mDecodeFrame; + } + + if (mIsMissingAsset) + { + priority = 0.0f; + } + else if (mDesiredDiscardLevel > getMaxDiscardLevel()) + { + // Don't decode anything we don't need + priority = -1.0f; + } + else if (mBoostLevel == LLViewerTexture::BOOST_UI && !have_all_data) + { + priority = 1.f; + } + else if (pixel_priority <= 0.f && !have_all_data) + { + // Not on screen but we might want some data + if (mBoostLevel > BOOST_HIGH) + { + // Always want high boosted images + priority = 1.f; + } + else if (mVisibleFrame == 0 || (mDecodeFrame - mVisibleFrame > MIN_NOT_VISIBLE_FRAMES)) + { + // Don't decode anything that isn't visible unless it's important + priority = -2.0f; + } + else + { + // Leave the priority as-is + return mDecodePriority; + } + } + else if (cur_discard < 0) + { + priority = calcDecodePriorityForUnknownTexture(pixel_priority) ; + } + else if ((mMinDiscardLevel > 0) && (cur_discard <= mMinDiscardLevel)) + { + // larger mips are corrupted + priority = -3.0f; + } + else if (cur_discard <= mDesiredDiscardLevel) + { + priority = -4.0f; + } + else + { + // priority range = 100000-400000 + S32 ddiscard = cur_discard - mDesiredDiscardLevel; + if (getDontDiscard()) + { + ddiscard+=2; + } + else if (mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == 0) + { + ddiscard-=2; + } + ddiscard = llclamp(ddiscard, 0, 4); + priority = ddiscard*100000.f; + } + if (priority > 0.0f) + { + pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); // priority range = 100000-900000 + if ( mBoostLevel > BOOST_HIGH) + { + priority = 1000000.f + pixel_priority + 1000.f * mBoostLevel; + } + else + { + priority += 0.f + pixel_priority + 1000.f * mBoostLevel; + } + } + return priority; +} +//============================================================================ + +void LLViewerFetchedTexture::setDecodePriority(F32 priority) +{ + llassert(!mInImageList); + mDecodePriority = priority; +} + +bool LLViewerFetchedTexture::updateFetch() +{ + mFetchState = 0; + mFetchPriority = 0; + mFetchDeltaTime = 999999.f; + mRequestDeltaTime = 999999.f; + +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (mID == LLAppViewer::getTextureFetch()->mDebugID) + { + LLAppViewer::getTextureFetch()->mDebugCount++; // for setting breakpoints + } +#endif + + if (mNeedsCreateTexture) + { + // We may be fetching still (e.g. waiting on write) + // but don't check until we've processed the raw data we have + return false; + } + if (mIsMissingAsset) + { + llassert_always(!mHasFetcher); + return false; // skip + } + if (!mLoadedCallbackList.empty() && mRawImage.notNull()) + { + return false; // process any raw image data in callbacks before replacing + } + + S32 current_discard = getDiscardLevel() ; + S32 desired_discard = getDesiredDiscardLevel(); + F32 decode_priority = getDecodePriority(); + decode_priority = llmax(decode_priority, 0.0f); + + if (mIsFetching) + { + // Sets mRawDiscardLevel, mRawImage, mAuxRawImage + S32 fetch_discard = current_discard; + if (mRawImage.notNull()) sRawCount--; + if (mAuxRawImage.notNull()) sAuxCount--; + bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage); + if (mRawImage.notNull()) sRawCount++; + if (mAuxRawImage.notNull()) sAuxCount++; + if (finished) + { + mIsFetching = FALSE; + } + else + { + mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, + mFetchPriority, mFetchDeltaTime, mRequestDeltaTime); + } + + // We may have data ready regardless of whether or not we are finished (e.g. waiting on write) + if (mRawImage.notNull()) + { + if(LLViewerTextureManager::sTesterp) + { + mIsFetched = TRUE ; + LLViewerTextureManager::sTesterp->updateTextureLoadingStats(this, mRawImage, LLAppViewer::getTextureFetch()->isFromLocalCache(mID)) ; + } + mRawDiscardLevel = fetch_discard; + if ((mRawImage->getDataSize() > 0 && mRawDiscardLevel >= 0) && + (current_discard < 0 || mRawDiscardLevel < current_discard)) + { + if (getComponents() != mRawImage->getComponents()) + { + // We've changed the number of components, so we need to move any + // objects using this pool to a different pool. + mComponents = mRawImage->getComponents(); + mGLTexturep->setComponents(mComponents) ; + + gTextureList.dirtyImage(this); + } + mIsRawImageValid = TRUE; + gTextureList.mCreateTextureList.insert(this); + mNeedsCreateTexture = TRUE; + mFullWidth = mRawImage->getWidth() << mRawDiscardLevel; + mFullHeight = mRawImage->getHeight() << mRawDiscardLevel; + } + else + { + // Data is ready but we don't need it + // (received it already while fetcher was writing to disk) + destroyRawImage(); + return false; // done + } + } + + if (!mIsFetching) + { + if ((decode_priority > 0) && (mRawDiscardLevel < 0 || mRawDiscardLevel == INVALID_DISCARD_LEVEL)) + { + // We finished but received no data + if (current_discard < 0) + { + setIsMissingAsset(); + desired_discard = -1; + } + else + { + llwarns << mID << ": Setting min discard to " << current_discard << llendl; + mMinDiscardLevel = current_discard; + desired_discard = current_discard; + } + destroyRawImage(); + } + else if (mRawImage.isNull()) + { + // We have data, but our fetch failed to return raw data + // *TODO: FIgure out why this is happening and fix it + destroyRawImage(); + } + } + else + { + LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority); + } + } + + bool make_request = true; + + if (decode_priority <= 0) + { + make_request = false; + } + else if (mNeedsCreateTexture || mIsMissingAsset) + { + make_request = false; + } + else if (current_discard >= 0 && current_discard <= mMinDiscardLevel) + { + make_request = false; + } + else + { + if (mIsFetching) + { + if (mRequestedDiscardLevel <= desired_discard) + { + make_request = false; + } + } + else + { + if (current_discard >= 0 && current_discard <= desired_discard) + { + make_request = false; + } + } + } + + if (make_request) + { + S32 w=0, h=0, c=0; + if (current_discard >= 0) + { + w = mGLTexturep->getWidth(0); + h = mGLTexturep->getHeight(0); + c = mComponents; + } + if (!mDontDiscard) + { + if (mBoostLevel == 0) + { + desired_discard = llmax(desired_discard, current_discard-1); + } + else + { + desired_discard = llmax(desired_discard, current_discard-2); + } + } + + // bypass texturefetch directly by pulling from LLTextureCache + bool fetch_request_created = false; + if (mLocalFileName.empty()) + { + fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(getID(), getTargetHost(), decode_priority, + w, h, c, desired_discard, + needsAux()); + } + else + { + fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mLocalFileName, getID(),getTargetHost(), decode_priority, + w, h, c, desired_discard, + needsAux()); + } + + if (fetch_request_created) + { + mHasFetcher = TRUE; + mIsFetching = TRUE; + mRequestedDiscardLevel = desired_discard; + mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority, + mFetchPriority, mFetchDeltaTime, mRequestDeltaTime); + } + + // if createRequest() failed, we're finishing up a request for this UUID, + // wait for it to complete + } + else if (mHasFetcher && !mIsFetching) + { + // Only delete requests that haven't receeived any network data for a while + const F32 FETCH_IDLE_TIME = 5.f; + if (mLastPacketTimer.getElapsedTimeF32() > FETCH_IDLE_TIME) + { +// llinfos << "Deleting request: " << getID() << " Discard: " << current_discard << " <= min:" << mMinDiscardLevel << " or priority == 0: " << decode_priority << llendl; + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + } + } + + llassert_always(mRawImage.notNull() || (!mNeedsCreateTexture && !mIsRawImageValid)); + + return mIsFetching ? true : false; +} + +void LLViewerFetchedTexture::setIsMissingAsset() +{ + llwarns << mLocalFileName << " " << mID << ": Marking image as missing" << llendl; + if (mHasFetcher) + { + LLAppViewer::getTextureFetch()->deleteRequest(getID(), true); + mHasFetcher = FALSE; + mIsFetching = FALSE; + mFetchState = 0; + mFetchPriority = 0; + } + mIsMissingAsset = TRUE; +} + +void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_callback, + S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, void* userdata) +{ + // + // Don't do ANYTHING here, just add it to the global callback list + // + if (mLoadedCallbackList.empty()) + { + // Put in list to call this->doLoadedCallbacks() periodically + gTextureList.mCallbackList.insert(this); + } + LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata); + mLoadedCallbackList.push_back(entryp); + mNeedsAux |= needs_aux; + if (mNeedsAux && mAuxRawImage.isNull() && getDiscardLevel() >= 0) + { + // We need aux data, but we've already loaded the image, and it didn't have any + llwarns << "No aux data available for callback for image:" << getID() << llendl; + } +} + +bool LLViewerFetchedTexture::doLoadedCallbacks() +{ + if (mNeedsCreateTexture) + { + return false; + } + + bool res = false; + + if (isMissingAsset()) + { + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + // We never finished loading the image. Indicate failure. + // Note: this allows mLoadedCallbackUserData to be cleaned up. + entryp->mCallback(FALSE, this, NULL, NULL, 0, TRUE, entryp->mUserData); + delete entryp; + } + mLoadedCallbackList.clear(); + + // Remove ourself from the global list of textures with callbacks + gTextureList.mCallbackList.erase(this); + } + + S32 gl_discard = getDiscardLevel(); + + // If we don't have a legit GL image, set it to be lower than the worst discard level + if (gl_discard == -1) + { + gl_discard = MAX_DISCARD_LEVEL + 1; + } + + // + // Determine the quality levels of textures that we can provide to callbacks + // and whether we need to do decompression/readback to get it + // + S32 current_raw_discard = MAX_DISCARD_LEVEL + 1; // We can always do a readback to get a raw discard + S32 best_raw_discard = gl_discard; // Current GL quality level + S32 current_aux_discard = MAX_DISCARD_LEVEL + 1; + S32 best_aux_discard = MAX_DISCARD_LEVEL + 1; + + if (mIsRawImageValid) + { + // If we have an existing raw image, we have a baseline for the raw and auxiliary quality levels. + best_raw_discard = llmin(best_raw_discard, mRawDiscardLevel); + best_aux_discard = llmin(best_aux_discard, mRawDiscardLevel); // We always decode the aux when we decode the base raw + current_aux_discard = llmin(current_aux_discard, best_aux_discard); + } + else + { + // We have no data at all, we need to get it + // Do this by forcing the best aux discard to be 0. + best_aux_discard = 0; + } + + + // + // See if any of the callbacks would actually run using the data that we can provide, + // and also determine if we need to perform any readbacks or decodes. + // + bool run_gl_callbacks = false; + bool run_raw_callbacks = false; + bool need_readback = false; + + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + LLLoadedCallbackEntry *entryp = *iter++; + if (entryp->mNeedsImageRaw) + { + if (mNeedsAux) + { + // + // Need raw and auxiliary channels + // + if (entryp->mLastUsedDiscard > current_aux_discard) + { + // We have useful data, run the callbacks + run_raw_callbacks = true; + } + } + else + { + if (entryp->mLastUsedDiscard > current_raw_discard) + { + // We have useful data, just run the callbacks + run_raw_callbacks = true; + } + else if (entryp->mLastUsedDiscard > best_raw_discard) + { + // We can readback data, and then run the callbacks + need_readback = true; + run_raw_callbacks = true; + } + } + } + else + { + // Needs just GL + if (entryp->mLastUsedDiscard > gl_discard) + { + // We have enough data, run this callback requiring GL data + run_gl_callbacks = true; + } + } + } + + // + // Do a readback if required, OR start off a texture decode + // + if (need_readback && (getMaxDiscardLevel() > gl_discard)) + { + // Do a readback to get the GL data into the raw image + // We have GL data. + + destroyRawImage(); + readBackRawImage(gl_discard); + llassert_always(mRawImage.notNull()); + llassert_always(!mNeedsAux || mAuxRawImage.notNull()); + } + + // + // Run raw/auxiliary data callbacks + // + if (run_raw_callbacks && mIsRawImageValid && (mRawDiscardLevel <= getMaxDiscardLevel())) + { + // Do callbacks which require raw image data. + //llinfos << "doLoadedCallbacks raw for " << getID() << llendl; + + // Call each party interested in the raw data. + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLLoadedCallbackEntry *entryp = *curiter; + if (entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > mRawDiscardLevel)) + { + // If we've loaded all the data there is to load or we've loaded enough + // to satisfy the interested party, then this is the last time that + // we're going to call them. + + llassert_always(mRawImage.notNull()); + if(mNeedsAux && mAuxRawImage.isNull()) + { + llwarns << "Raw Image with no Aux Data for callback" << llendl; + } + BOOL final = mRawDiscardLevel <= entryp->mDesiredDiscard ? TRUE : FALSE; + //llinfos << "Running callback for " << getID() << llendl; + //llinfos << mRawImage->getWidth() << "x" << mRawImage->getHeight() << llendl; + if (final) + { + //llinfos << "Final!" << llendl; + } + entryp->mLastUsedDiscard = mRawDiscardLevel; + entryp->mCallback(TRUE, this, mRawImage, mAuxRawImage, mRawDiscardLevel, final, entryp->mUserData); + if (final) + { + iter = mLoadedCallbackList.erase(curiter); + delete entryp; + } + res = true; + } + } + } + + // + // Run GL callbacks + // + if (run_gl_callbacks && (gl_discard <= getMaxDiscardLevel())) + { + //llinfos << "doLoadedCallbacks GL for " << getID() << llendl; + + // Call the callbacks interested in GL data. + for(callback_list_t::iterator iter = mLoadedCallbackList.begin(); + iter != mLoadedCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + LLLoadedCallbackEntry *entryp = *curiter; + if (!entryp->mNeedsImageRaw && (entryp->mLastUsedDiscard > gl_discard)) + { + BOOL final = gl_discard <= entryp->mDesiredDiscard ? TRUE : FALSE; + entryp->mLastUsedDiscard = gl_discard; + entryp->mCallback(TRUE, this, NULL, NULL, gl_discard, final, entryp->mUserData); + if (final) + { + iter = mLoadedCallbackList.erase(curiter); + delete entryp; + } + res = true; + } + } + } + + // + // If we have no callbacks, take us off of the image callback list. + // + if (mLoadedCallbackList.empty()) + { + gTextureList.mCallbackList.erase(this); + } + + // Done with any raw image data at this point (will be re-created if we still have callbacks) + destroyRawImage(); + + return res; +} + +//virtual +void LLViewerFetchedTexture::forceImmediateUpdate() +{ + //only immediately update a deleted texture which is now being re-used. + if(!isDeleted()) + { + return ; + } + //if already called forceImmediateUpdate() + if(mInImageList && mDecodePriority == LLViewerFetchedTexture::maxDecodePriority()) + { + return ; + } + + gTextureList.forceImmediateUpdate(this) ; + return ; +} + +// Was in LLImageGL +LLImageRaw* LLViewerFetchedTexture::readBackRawImage(S8 discard_level) +{ + llassert_always(mGLTexturep.notNull()) ; + llassert_always(discard_level >= 0); + llassert_always(mComponents > 0); + if (mRawImage.notNull()) + { + llerrs << "called with existing mRawImage" << llendl; + mRawImage = NULL; + } + mRawImage = new LLImageRaw(mGLTexturep->getWidth(discard_level), mGLTexturep->getHeight(discard_level), mComponents); + sRawCount++; + mRawDiscardLevel = discard_level; + mGLTexturep->readBackRaw(mRawDiscardLevel, mRawImage, false); + mIsRawImageValid = TRUE; + + return mRawImage; +} + +void LLViewerFetchedTexture::destroyRawImage() +{ + if (mRawImage.notNull()) sRawCount--; + if (mAuxRawImage.notNull()) sAuxCount--; + mRawImage = NULL; + mAuxRawImage = NULL; + mIsRawImageValid = FALSE; + mRawDiscardLevel = INVALID_DISCARD_LEVEL; +} +//---------------------------------------------------------------------------------------------- +//end of LLViewerFetchedTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLViewerLODTexture +//---------------------------------------------------------------------------------------------- +LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps) + : LLViewerFetchedTexture(id, usemipmaps) +{ + init(TRUE) ; +} + +LLViewerLODTexture::LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps) + : LLViewerFetchedTexture(full_path, id, usemipmaps) +{ + init(TRUE) ; +} + +void LLViewerLODTexture::init(bool firstinit) +{ + mTexelsPerImage = 64.f*64.f; + mDiscardVirtualSize = 0.f; + mCalculatedDiscardLevel = -1.f; +} + +//virtual +S8 LLViewerLODTexture::getType() const +{ + return LLViewerTexture::LOD_TEXTURE ; +} + +// This is gauranteed to get called periodically for every texture +//virtual +void LLViewerLODTexture::processTextureStats() +{ + // Generate the request priority and render priority + if (mDontDiscard || !mUseMipMaps) + { + mDesiredDiscardLevel = 0; + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + mDesiredDiscardLevel = 1; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + } + else if (mBoostLevel < LLViewerTexture::BOOST_HIGH && mMaxVirtualSize <= 10.f) + { + // If the image has not been significantly visible in a while, we don't want it + mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, (S8)(MAX_DISCARD_LEVEL + 1)); + } + else if (!mFullWidth || !mFullHeight) + { + mDesiredDiscardLevel = getMaxDiscardLevel() ; + } + else + { + //static const F64 log_2 = log(2.0); + static const F64 log_4 = log(4.0); + + S32 fullwidth = llmin(mFullWidth,(S32)MAX_IMAGE_SIZE_DEFAULT); + S32 fullheight = llmin(mFullHeight,(S32)MAX_IMAGE_SIZE_DEFAULT); + mTexelsPerImage = (F32)fullwidth * fullheight; + + F32 discard_level = 0.f; + + // If we know the output width and height, we can force the discard + // level to the correct value, and thus not decode more texture + // data than we need to. + /*if (mBoostLevel == LLViewerTexture::BOOST_UI || + mBoostLevel == LLViewerTexture::BOOST_PREVIEW || + mBoostLevel == LLViewerTexture::BOOST_AVATAR_SELF) // JAMESDEBUG what about AVATAR_BAKED_SELF? + { + discard_level = 0; // full res + } + else*/ if (mKnownDrawWidth && mKnownDrawHeight) + { + S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight; + + // Use log_4 because we're in square-pixel space, so an image + // with twice the width and twice the height will have mTexelsPerImage + // 4 * draw_size + discard_level = (F32)(log(mTexelsPerImage/draw_texels) / log_4); + } + else + { + if ((mCalculatedDiscardLevel >= 0.f) && + (llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f)) + { + // < 20% change in virtual size = no change in desired discard + discard_level = mCalculatedDiscardLevel; + } + else + { + // Calculate the required scale factor of the image using pixels per texel + discard_level = (F32)(log(mTexelsPerImage/mMaxVirtualSize) / log_4); + mDiscardVirtualSize = mMaxVirtualSize; + mCalculatedDiscardLevel = discard_level; + } + } + if (mBoostLevel < LLViewerTexture::BOOST_HIGH) + { + static const F32 discard_bias = -.5f; // Must be < 1 or highest discard will never load! + discard_level += discard_bias; + discard_level += sDesiredDiscardBias; + discard_level *= sDesiredDiscardScale; // scale + } + discard_level = floorf(discard_level); +// discard_level -= (gTextureList.mVideoMemorySetting>>1); // more video ram = higher detail + + F32 min_discard = 0.f; + if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT) + min_discard = 1.f; // MAX_IMAGE_SIZE_DEFAULT = 1024 and max size ever is 2048 + + discard_level = llclamp(discard_level, min_discard, (F32)MAX_DISCARD_LEVEL); + + // Can't go higher than the max discard level + mDesiredDiscardLevel = llmin(getMaxDiscardLevel() + 1, (S32)discard_level); + // Clamp to min desired discard + mDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel, mDesiredDiscardLevel); + + // + // At this point we've calculated the quality level that we want, + // if possible. Now we check to see if we have it, and take the + // proper action if we don't. + // + + BOOL increase_discard = FALSE; + S32 current_discard = getDiscardLevel(); + if ((sDesiredDiscardBias > 0.0f) && + (current_discard >= 0 && mDesiredDiscardLevel >= current_discard)) + { + if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) + { + // Limit the amount of GL memory bound each frame + if (mDesiredDiscardLevel > current_discard) + { + increase_discard = TRUE; + } + } + if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale) + { + // Only allow GL to have 2x the video card memory + if (!mGLTexturep->getBoundRecently()) + { + increase_discard = TRUE; + } + } + if (increase_discard) + { + // llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl; + sBoundTextureMemoryInBytes -= mGLTexturep->mTextureMemory; + sTotalTextureMemoryInBytes -= mGLTexturep->mTextureMemory; + // Increase the discard level (reduce the texture res) + S32 new_discard = current_discard+1; + mGLTexturep->setDiscardLevel(new_discard); + sBoundTextureMemoryInBytes += mGLTexturep->mTextureMemory; + sTotalTextureMemoryInBytes += mGLTexturep->mTextureMemory; + if(LLViewerTextureManager::sTesterp) + { + LLViewerTextureManager::sTesterp->setStablizingTime() ; + } + } + } + } +} + +//---------------------------------------------------------------------------------------------- +//end of LLViewerLODTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLViewerMediaTexture +//---------------------------------------------------------------------------------------------- +//static +void LLViewerMediaTexture::updateClass() +{ + static const F32 MAX_INACTIVE_TIME = 30.f ; + + for(media_map_t::iterator iter = sMediaMap.begin() ; iter != sMediaMap.end(); ) + { + LLViewerMediaTexture* mediap = iter->second; + ++iter ; + + if(mediap->getNumRefs() == 1 && mediap->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) //one by sMediaMap + { + sMediaMap.erase(mediap->getID()) ; + } + } +} + +LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LLImageGL* gl_image) + : LLViewerTexture(id, usemipmaps) +{ + sMediaMap.insert(std::make_pair(id, this)); + + mGLTexturep = gl_image ; + if(mGLTexturep.isNull()) + { + generateGLTexture() ; + } + mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; + + mIsPlaying = FALSE ; +} + +void LLViewerMediaTexture::reinit(BOOL usemipmaps /* = TRUE */) +{ + mGLTexturep = NULL ; + init(false); + mUseMipMaps = usemipmaps ; + mIsPlaying = FALSE ; + getLastReferencedTimer()->reset() ; + + generateGLTexture() ; + mGLTexturep->setNeedsAlphaAndPickMask(FALSE) ; +} + +void LLViewerMediaTexture::setUseMipMaps(BOOL mipmap) +{ + mUseMipMaps = mipmap; + + if(mGLTexturep.notNull()) + { + mGLTexturep->setUseMipMaps(mipmap) ; + } +} + +//virtual +S8 LLViewerMediaTexture::getType() const +{ + return LLViewerTexture::MEDIA_TEXTURE ; +} + +void LLViewerMediaTexture::setOldTexture(LLViewerTexture* tex) +{ + mOldTexturep = tex ; +} + +LLViewerTexture* LLViewerMediaTexture::getOldTexture() const +{ + return mOldTexturep ; +} +//---------------------------------------------------------------------------------------------- +//end of LLViewerMediaTexture +//---------------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------------- +//start of LLTexturePipelineTester +//---------------------------------------------------------------------------------------------- +LLTexturePipelineTester::LLTexturePipelineTester() : + LLMetricPerformanceTester("TextureTester", FALSE) +{ + addMetricString("TotalBytesLoaded") ; + addMetricString("TotalBytesLoadedFromCache") ; + addMetricString("TotalBytesLoadedForLargeImage") ; + addMetricString("TotalBytesLoadedForSculpties") ; + addMetricString("StartFetchingTime") ; + addMetricString("TotalGrayTime") ; + addMetricString("TotalStablizingTime") ; + addMetricString("StartTimeLoadingSculpties") ; + addMetricString("EndTimeLoadingSculpties") ; + + addMetricString("Time") ; + addMetricString("TotalBytesBound") ; + addMetricString("TotalBytesBoundForLargeImage") ; + addMetricString("PercentageBytesBound") ; + + mTotalBytesLoaded = 0 ; + mTotalBytesLoadedFromCache = 0 ; + mTotalBytesLoadedForLargeImage = 0 ; + mTotalBytesLoadedForSculpties = 0 ; + + reset() ; +} + +LLTexturePipelineTester::~LLTexturePipelineTester() +{ + LLViewerTextureManager::sTesterp = NULL ; +} + +void LLTexturePipelineTester::update() +{ + mLastTotalBytesUsed = mTotalBytesUsed ; + mLastTotalBytesUsedForLargeImage = mTotalBytesUsedForLargeImage ; + mTotalBytesUsed = 0 ; + mTotalBytesUsedForLargeImage = 0 ; + + if(LLAppViewer::getTextureFetch()->getNumRequests() > 0) //fetching list is not empty + { + if(mPause) + { + //start a new fetching session + reset() ; + mStartFetchingTime = LLImageGL::sLastFrameTime ; + mPause = FALSE ; + } + + //update total gray time + if(mUsingDefaultTexture) + { + mUsingDefaultTexture = FALSE ; + mTotalGrayTime = LLImageGL::sLastFrameTime - mStartFetchingTime ; + } + + //update the stablizing timer. + updateStablizingTime() ; + + outputTestResults() ; + } + else if(!mPause) + { + //stop the current fetching session + mPause = TRUE ; + outputTestResults() ; + reset() ; + } +} + +void LLTexturePipelineTester::reset() +{ + mPause = TRUE ; + + mUsingDefaultTexture = FALSE ; + mStartStablizingTime = 0.0f ; + mEndStablizingTime = 0.0f ; + + mTotalBytesUsed = 0 ; + mTotalBytesUsedForLargeImage = 0 ; + mLastTotalBytesUsed = 0 ; + mLastTotalBytesUsedForLargeImage = 0 ; + + mStartFetchingTime = 0.0f ; + + mTotalGrayTime = 0.0f ; + mTotalStablizingTime = 0.0f ; + + mStartTimeLoadingSculpties = 1.0f ; + mEndTimeLoadingSculpties = 0.0f ; +} + +//virtual +void LLTexturePipelineTester::outputTestRecord(LLSD *sd) +{ + (*sd)[mCurLabel]["TotalBytesLoaded"] = (LLSD::Integer)mTotalBytesLoaded ; + (*sd)[mCurLabel]["TotalBytesLoadedFromCache"] = (LLSD::Integer)mTotalBytesLoadedFromCache ; + (*sd)[mCurLabel]["TotalBytesLoadedForLargeImage"] = (LLSD::Integer)mTotalBytesLoadedForLargeImage ; + (*sd)[mCurLabel]["TotalBytesLoadedForSculpties"] = (LLSD::Integer)mTotalBytesLoadedForSculpties ; + + (*sd)[mCurLabel]["StartFetchingTime"] = (LLSD::Real)mStartFetchingTime ; + (*sd)[mCurLabel]["TotalGrayTime"] = (LLSD::Real)mTotalGrayTime ; + (*sd)[mCurLabel]["TotalStablizingTime"] = (LLSD::Real)mTotalStablizingTime ; + + (*sd)[mCurLabel]["StartTimeLoadingSculpties"] = (LLSD::Real)mStartTimeLoadingSculpties ; + (*sd)[mCurLabel]["EndTimeLoadingSculpties"] = (LLSD::Real)mEndTimeLoadingSculpties ; + + (*sd)[mCurLabel]["Time"] = LLImageGL::sLastFrameTime ; + (*sd)[mCurLabel]["TotalBytesBound"] = (LLSD::Integer)mLastTotalBytesUsed ; + (*sd)[mCurLabel]["TotalBytesBoundForLargeImage"] = (LLSD::Integer)mLastTotalBytesUsedForLargeImage ; + (*sd)[mCurLabel]["PercentageBytesBound"] = (LLSD::Real)(100.f * mLastTotalBytesUsed / mTotalBytesLoaded) ; +} + +void LLTexturePipelineTester::updateTextureBindingStats(const LLViewerTexture* imagep) +{ + U32 mem_size = (U32)imagep->getTextureMemory() ; + mTotalBytesUsed += mem_size ; + + if(MIN_LARGE_IMAGE_AREA <= (U32)(mem_size / (U32)imagep->getComponents())) + { + mTotalBytesUsedForLargeImage += mem_size ; + } +} + +void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) +{ + U32 data_size = (U32)raw_imagep->getDataSize() ; + mTotalBytesLoaded += data_size ; + + if(from_cache) + { + mTotalBytesLoadedFromCache += data_size ; + } + + if(MIN_LARGE_IMAGE_AREA <= (U32)(data_size / (U32)raw_imagep->getComponents())) + { + mTotalBytesLoadedForLargeImage += data_size ; + } + + if(imagep->isForSculpt()) + { + mTotalBytesLoadedForSculpties += data_size ; + + if(mStartTimeLoadingSculpties > mEndTimeLoadingSculpties) + { + mStartTimeLoadingSculpties = LLImageGL::sLastFrameTime ; + } + mEndTimeLoadingSculpties = LLImageGL::sLastFrameTime ; + } +} + +void LLTexturePipelineTester::updateGrayTextureBinding() +{ + mUsingDefaultTexture = TRUE ; +} + +void LLTexturePipelineTester::setStablizingTime() +{ + if(mStartStablizingTime <= mStartFetchingTime) + { + mStartStablizingTime = LLImageGL::sLastFrameTime ; + } + mEndStablizingTime = LLImageGL::sLastFrameTime ; +} + +void LLTexturePipelineTester::updateStablizingTime() +{ + if(mStartStablizingTime > mStartFetchingTime) + { + F32 t = mEndStablizingTime - mStartStablizingTime ; + + if(t > 0.0001f && (t - mTotalStablizingTime) < 0.0001f) + { + //already stablized + mTotalStablizingTime = LLImageGL::sLastFrameTime - mStartStablizingTime ; + + //cancel the timer + mStartStablizingTime = 0.f ; + mEndStablizingTime = 0.f ; + } + else + { + mTotalStablizingTime = t ; + } + } + mTotalStablizingTime = 0.f ; +} + +//virtual +void LLTexturePipelineTester::compareTestSessions(std::ofstream* os) +{ + LLTexturePipelineTester::LLTextureTestSession* base_sessionp = dynamic_cast(mBaseSessionp) ; + LLTexturePipelineTester::LLTextureTestSession* current_sessionp = dynamic_cast(mCurrentSessionp) ; + if(!base_sessionp || !current_sessionp) + { + llerrs << "type of test session does not match!" << llendl ; + } + + //compare and output the comparison + *os << llformat("%s\n", mName.c_str()) ; + *os << llformat("AggregateResults\n") ; + + compareTestResults(os, "TotalFetchingTime", base_sessionp->mTotalFetchingTime, current_sessionp->mTotalFetchingTime) ; + compareTestResults(os, "TotalGrayTime", base_sessionp->mTotalGrayTime, current_sessionp->mTotalGrayTime) ; + compareTestResults(os, "TotalStablizingTime", base_sessionp->mTotalStablizingTime, current_sessionp->mTotalStablizingTime); + compareTestResults(os, "StartTimeLoadingSculpties", base_sessionp->mStartTimeLoadingSculpties, current_sessionp->mStartTimeLoadingSculpties) ; + compareTestResults(os, "TotalTimeLoadingSculpties", base_sessionp->mTotalTimeLoadingSculpties, current_sessionp->mTotalTimeLoadingSculpties) ; + + compareTestResults(os, "TotalBytesLoaded", base_sessionp->mTotalBytesLoaded, current_sessionp->mTotalBytesLoaded) ; + compareTestResults(os, "TotalBytesLoadedFromCache", base_sessionp->mTotalBytesLoadedFromCache, current_sessionp->mTotalBytesLoadedFromCache) ; + compareTestResults(os, "TotalBytesLoadedForLargeImage", base_sessionp->mTotalBytesLoadedForLargeImage, current_sessionp->mTotalBytesLoadedForLargeImage) ; + compareTestResults(os, "TotalBytesLoadedForSculpties", base_sessionp->mTotalBytesLoadedForSculpties, current_sessionp->mTotalBytesLoadedForSculpties) ; + + *os << llformat("InstantResults\n") ; + S32 size = llmin(base_sessionp->mInstantPerformanceListCounter, current_sessionp->mInstantPerformanceListCounter) ; + for(S32 i = 0 ; i < size ; i++) + { + *os << llformat("Time(B-T)-%.4f-%.4f\n", base_sessionp->mInstantPerformanceList[i].mTime, current_sessionp->mInstantPerformanceList[i].mTime) ; + + compareTestResults(os, "AverageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond, + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; + + compareTestResults(os, "AverageBytesUsedForLargeImagePerSecond", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond, + current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; + + compareTestResults(os, "AveragePercentageBytesUsedPerSecond", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond, + current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + } + + if(size < base_sessionp->mInstantPerformanceListCounter) + { + for(S32 i = size ; i < base_sessionp->mInstantPerformanceListCounter ; i++) + { + *os << llformat("Time(B-T)-%.4f- \n", base_sessionp->mInstantPerformanceList[i].mTime) ; + + *os << llformat(", AverageBytesUsedPerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, %d, N/A \n", base_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; + *os << llformat(", AveragePercentageBytesUsedPerSecond, %.4f, N/A \n", base_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + } + } + else if(size < current_sessionp->mInstantPerformanceListCounter) + { + for(S32 i = size ; i < current_sessionp->mInstantPerformanceListCounter ; i++) + { + *os << llformat("Time(B-T)- -%.4f\n", current_sessionp->mInstantPerformanceList[i].mTime) ; + + *os << llformat(", AverageBytesUsedPerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedPerSecond) ; + *os << llformat(", AverageBytesUsedForLargeImagePerSecond, N/A, %d\n", current_sessionp->mInstantPerformanceList[i].mAverageBytesUsedForLargeImagePerSecond) ; + *os << llformat(", AveragePercentageBytesUsedPerSecond, N/A, %.4f\n", current_sessionp->mInstantPerformanceList[i].mAveragePercentageBytesUsedPerSecond) ; + } + } +} + +//virtual +LLMetricPerformanceTester::LLTestSession* LLTexturePipelineTester::loadTestSession(LLSD* log) +{ + LLTexturePipelineTester::LLTextureTestSession* sessionp = new LLTexturePipelineTester::LLTextureTestSession() ; + if(!sessionp) + { + return NULL ; + } + + F32 total_fetching_time = 0.f ; + F32 total_gray_time = 0.f ; + F32 total_stablizing_time = 0.f ; + F32 total_loading_sculpties_time = 0.f ; + + F32 start_fetching_time = -1.f ; + F32 start_fetching_sculpties_time = 0.f ; + + F32 last_time = 0.0f ; + S32 frame_count = 0 ; + + sessionp->mInstantPerformanceListCounter = 0 ; + sessionp->mInstantPerformanceList.resize(128) ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0 ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0 ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; + + //load a session + BOOL in_log = (*log).has(mCurLabel) ; + while(in_log) + { + LLSD::String label = mCurLabel ; + incLabel() ; + in_log = (*log).has(mCurLabel) ; + + if(sessionp->mInstantPerformanceListCounter >= (S32)sessionp->mInstantPerformanceList.size()) + { + sessionp->mInstantPerformanceList.resize(sessionp->mInstantPerformanceListCounter + 128) ; + } + + //time + F32 start_time = (*log)[label]["StartFetchingTime"].asReal() ; + F32 cur_time = (*log)[label]["Time"].asReal() ; + if(start_time - start_fetching_time > 0.0001f) //fetching has paused for a while + { + sessionp->mTotalFetchingTime += total_fetching_time ; + sessionp->mTotalGrayTime += total_gray_time ; + sessionp->mTotalStablizingTime += total_stablizing_time ; + + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time ; + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time ; + + start_fetching_time = start_time ; + total_fetching_time = 0.0f ; + total_gray_time = 0.f ; + total_stablizing_time = 0.f ; + total_loading_sculpties_time = 0.f ; + } + else + { + total_fetching_time = cur_time - start_time ; + total_gray_time = (*log)[label]["TotalGrayTime"].asReal() ; + total_stablizing_time = (*log)[label]["TotalStablizingTime"].asReal() ; + + total_loading_sculpties_time = (*log)[label]["EndTimeLoadingSculpties"].asReal() - (*log)[label]["StartTimeLoadingSculpties"].asReal() ; + if(start_fetching_sculpties_time < 0.f && total_loading_sculpties_time > 0.f) + { + start_fetching_sculpties_time = (*log)[label]["StartTimeLoadingSculpties"].asReal() ; + } + } + + //total loaded bytes + sessionp->mTotalBytesLoaded = (*log)[label]["TotalBytesLoaded"].asInteger() ; + sessionp->mTotalBytesLoadedFromCache = (*log)[label]["TotalBytesLoadedFromCache"].asInteger() ; + sessionp->mTotalBytesLoadedForLargeImage = (*log)[label]["TotalBytesLoadedForLargeImage"].asInteger() ; + sessionp->mTotalBytesLoadedForSculpties = (*log)[label]["TotalBytesLoadedForSculpties"].asInteger() ; + + //instant metrics + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond += + (*log)[label]["TotalBytesBound"].asInteger() ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond += + (*log)[label]["TotalBytesBoundForLargeImage"].asInteger() ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond += + (*log)[label]["PercentageBytesBound"].asReal() ; + frame_count++ ; + if(cur_time - last_time >= 1.0f) + { + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond /= frame_count ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond /= frame_count ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond /= frame_count ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = last_time ; + + frame_count = 0 ; + last_time = cur_time ; + sessionp->mInstantPerformanceListCounter++ ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedPerSecond = 0 ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAverageBytesUsedForLargeImagePerSecond = 0 ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mAveragePercentageBytesUsedPerSecond = 0.f ; + sessionp->mInstantPerformanceList[sessionp->mInstantPerformanceListCounter].mTime = 0.f ; + } + } + + sessionp->mTotalFetchingTime += total_fetching_time ; + sessionp->mTotalGrayTime += total_gray_time ; + sessionp->mTotalStablizingTime += total_stablizing_time ; + + if(sessionp->mStartTimeLoadingSculpties < 0.f) + { + sessionp->mStartTimeLoadingSculpties = start_fetching_sculpties_time ; + } + sessionp->mTotalTimeLoadingSculpties += total_loading_sculpties_time ; + + return sessionp; +} + +LLTexturePipelineTester::LLTextureTestSession::LLTextureTestSession() +{ + reset() ; +} +LLTexturePipelineTester::LLTextureTestSession::~LLTextureTestSession() +{ +} +void LLTexturePipelineTester::LLTextureTestSession::reset() +{ + mTotalFetchingTime = 0.0f ; + + mTotalGrayTime = 0.0f ; + mTotalStablizingTime = 0.0f ; + + mStartTimeLoadingSculpties = 0.0f ; + mTotalTimeLoadingSculpties = 0.0f ; + + mTotalBytesLoaded = 0 ; + mTotalBytesLoadedFromCache = 0 ; + mTotalBytesLoadedForLargeImage = 0 ; + mTotalBytesLoadedForSculpties = 0 ; + + mInstantPerformanceListCounter = 0 ; +} +//---------------------------------------------------------------------------------------------- +//end of LLTexturePipelineTester +//---------------------------------------------------------------------------------------------- + diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h new file mode 100644 index 0000000000..142c212435 --- /dev/null +++ b/indra/newview/llviewertexture.h @@ -0,0 +1,672 @@ +/** + * @file llviewertexture.h + * @brief Object for managing images and their textures + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERTEXTURE_H +#define LL_LLVIEWERTEXTURE_H + +#include "lltexture.h" +#include "lltimer.h" +#include "llframetimer.h" +#include "llhost.h" +#include "llgltypes.h" +#include "llrender.h" +#include "llmetricperformancetester.h" + +#include +#include + +#define MIN_VIDEO_RAM_IN_MEGA_BYTES 32 +#define MAX_VIDEO_RAM_IN_MEGA_BYTES 512 // 512MB max for performance reasons. + +class LLFace; +class LLImageGL ; +class LLViewerTexture; +class LLViewerFetchedTexture ; +class LLViewerMediaTexture ; +class LLTexturePipelineTester ; + +typedef void (*loaded_callback_func)( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); + +class LLVFile; +class LLMessageSystem; + +class LLLoadedCallbackEntry +{ +public: + LLLoadedCallbackEntry(loaded_callback_func cb, + S32 discard_level, + BOOL need_imageraw, // Needs image raw for the callback + void* userdata ) + : mCallback(cb), + mLastUsedDiscard(MAX_DISCARD_LEVEL+1), + mDesiredDiscard(discard_level), + mNeedsImageRaw(need_imageraw), + mUserData(userdata) + { + } + + loaded_callback_func mCallback; + S32 mLastUsedDiscard; + S32 mDesiredDiscard; + BOOL mNeedsImageRaw; + void* mUserData; +}; + +class LLTextureBar; + +class LLViewerTexture : public LLTexture +{ +public: + enum + { + MAX_IMAGE_SIZE_DEFAULT = 1024, + INVALID_DISCARD_LEVEL = 0x7fff + }; + enum + { + LOCAL_TEXTURE, + MEDIA_TEXTURE, + DYNAMIC_TEXTURE, + FETCHED_TEXTURE, + LOD_TEXTURE, + INVALID_TEXTURE_TYPE + }; + + enum EBoostLevel + { + BOOST_NONE = 0, + BOOST_AVATAR_BAKED = 1, + BOOST_AVATAR = 2, + BOOST_CLOUDS = 3, + BOOST_SCULPTED = 4, + + BOOST_HIGH = 10, + BOOST_TERRAIN = 11, // has to be high priority for minimap / low detail + BOOST_SELECTED = 12, + BOOST_HUD = 13, + BOOST_AVATAR_BAKED_SELF = 14, + BOOST_UI = 15, + BOOST_PREVIEW = 16, + BOOST_MAP = 17, + BOOST_MAP_LAYER = 18, + BOOST_AVATAR_SELF = 19, // needed for baking avatar + BOOST_MAX_LEVEL + }; + +protected: + virtual ~LLViewerTexture(); + LOG_CLASS(LLViewerTexture); + +public: + static void initClass(); + static void cleanupClass(); + static void updateClass(const F32 velocity, const F32 angular_velocity) ; + + LLViewerTexture(BOOL usemipmaps = TRUE); + LLViewerTexture(const LLUUID& id, BOOL usemipmaps) ; + LLViewerTexture(const LLImageRaw* raw, BOOL usemipmaps) ; + LLViewerTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps) ; + + virtual S8 getType() const; + virtual BOOL isMissingAsset()const ; + virtual void dump(); // debug info to llinfos + + /*virtual*/ bool bindDefaultImage(const S32 stage = 0) const ; + /*virtual*/ void forceImmediateUpdate() ; + + const LLUUID& getID() const { return mID; } + + void setBoostLevel(S32 level); + S32 getBoostLevel() { return mBoostLevel; } + + //maxVirtualSize of the texture + void addTextureStats(F32 virtual_size) const ; + void resetTextureStats(BOOL zero = FALSE); + F32 getMaxVirtualSize()const {return mMaxVirtualSize ;} + + LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;} + + S32 getFullWidth() const { return mFullWidth; } + S32 getFullHeight() const { return mFullHeight; } + + void addFace(LLFace* facep) ; + void removeFace(LLFace* facep) ; + + void generateGLTexture() ; + void destroyGLTexture() ; + + //--------------------------------------------------------------------------------------------- + //functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + /*virtual*/S32 getWidth(S32 discard_level = -1) const; + /*virtual*/S32 getHeight(S32 discard_level = -1) const; + + BOOL hasGLTexture() const ; + BOOL hasValidGLTexture() const ; + LLGLuint getTexName() const ; + BOOL createGLTexture() ; + BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0); + + void setFilteringOption(LLTexUnit::eTextureFilterOptions option); + void setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE); + void setAddressMode(LLTexUnit::eTextureAddressMode mode); + BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height); + BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height); + void setGLTextureCreated (bool initialized); + + LLTexUnit::eTextureAddressMode getAddressMode(void) const ; + S32 getMaxDiscardLevel() const; + S32 getDiscardLevel() const; + S8 getComponents() const ; + BOOL getBoundRecently() const; + S32 getTextureMemory() const ; + LLGLenum getPrimaryFormat() const; + BOOL getIsAlphaMask() const ; + LLTexUnit::eTextureType getTarget(void) const ; + BOOL getMask(const LLVector2 &tc); + F32 getTimePassedSinceLastBound(); + BOOL getMissed() const ; + BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ; + BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const; + //--------------------------------------------------------------------------------------------- + //end of functions to access LLImageGL + //--------------------------------------------------------------------------------------------- + + void switchToTexture(LLViewerTexture* new_texture) ; //make all faces pointing to this texture to point to new_texture. + + //----------------- + /*virtual*/ void setActive() ; + void forceActive() ; + void setNoDelete() ; + void dontDiscard() { mDontDiscard = 1; mTextureState = NO_DELETE; } + BOOL getDontDiscard() const { return mDontDiscard; } + //----------------- + + /*virtual*/ void updateBindStatsForTester() ; +protected: + void cleanup() ; + void init(bool firstinit) ; + +private: + //note: do not make this function public. + /*virtual*/ LLImageGL* getGLTexture() const ; + +protected: + LLUUID mID; + S32 mBoostLevel; // enum describing priority level + S32 mFullWidth; + S32 mFullHeight; + BOOL mUseMipMaps ; + S8 mComponents; + mutable F32 mMaxVirtualSize; // The largest virtual size of the image, in pixels - how much data to we need? + + LLFrameTimer mLastReferencedTimer; + + typedef std::list ll_face_list_t ; + ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture + + //GL texture + LLPointer mGLTexturep ; + S8 mDontDiscard; // Keep full res version of this image (for UI, etc) + +protected: + typedef enum + { + DELETED = 0, //removed from memory + DELETION_CANDIDATE, //ready to be removed from memory + INACTIVE, //not be used for the last certain period (i.e., 30 seconds). + ACTIVE, //just being used, can become inactive if not being used for a certain time (10 seconds). + NO_DELETE = 99 //stay in memory, can not be removed. + } LLGLTexureState; + LLGLTexureState mTextureState ; + +public: + static const U32 sCurrentFileVersion; + static S32 sImageCount; + static S32 sRawCount; + static S32 sAuxCount; + static LLTimer sEvaluationTimer; + static F32 sDesiredDiscardBias; + static F32 sDesiredDiscardScale; + static S32 sBoundTextureMemoryInBytes; + static S32 sTotalTextureMemoryInBytes; + static S32 sMaxBoundTextureMemInMegaBytes; + static S32 sMaxTotalTextureMemInMegaBytes; + static S32 sMaxDesiredTextureMemInBytes ; + static BOOL sDontLoadVolumeTextures; + + static LLPointer sNullImagep; // Null texture for non-textured objects. +}; + + +// +//textures are managed in gTextureList. +//raw image data is fetched from remote or local cache +//but the raw image this texture pointing to is fixed. +// +class LLViewerFetchedTexture : public LLViewerTexture +{ + friend class LLTextureBar; // debug info only + friend class LLTextureView; // debug info only + +protected: + /*virtual*/ ~LLViewerFetchedTexture(); +public: + LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps = TRUE); + LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps); + LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE); + +public: + static F32 maxDecodePriority(); + + struct Compare + { + // lhs < rhs + bool operator()(const LLPointer &lhs, const LLPointer &rhs) const + { + const LLViewerFetchedTexture* lhsp = (const LLViewerFetchedTexture*)lhs; + const LLViewerFetchedTexture* rhsp = (const LLViewerFetchedTexture*)rhs; + // greater priority is "less" + const F32 lpriority = lhsp->getDecodePriority(); + const F32 rpriority = rhsp->getDecodePriority(); + if (lpriority > rpriority) // higher priority + return true; + if (lpriority < rpriority) + return false; + return lhsp < rhsp; + } + }; + +public: + /*virtual*/ S8 getType() const ; + /*virtual*/ void forceImmediateUpdate() ; + /*virtual*/ void dump() ; + + // Set callbacks to get called when the image gets updated with higher + // resolution versions. + void setLoadedCallback(loaded_callback_func cb, + S32 discard_level, BOOL keep_imageraw, BOOL needs_aux, + void* userdata); + bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; } + bool doLoadedCallbacks(); + + // ONLY call from LLViewerTextureList + BOOL createTexture(S32 usename = 0); + void destroyTexture() ; + + virtual void processTextureStats() ; + F32 calcDecodePriority() ; + + BOOL needsAux() const { return mNeedsAux; } + + // Host we think might have this image, used for baked av textures. + void setTargetHost(LLHost host) { mTargetHost = host; } + LLHost getTargetHost() const { return mTargetHost; } + + // Set the decode priority for this image... + // DON'T CALL THIS UNLESS YOU KNOW WHAT YOU'RE DOING, it can mess up + // the priority list, and cause horrible things to happen. + void setDecodePriority(F32 priority = -1.0f); + F32 getDecodePriority() const { return mDecodePriority; }; + + // setDesiredDiscardLevel is only used by LLViewerTextureList + void setDesiredDiscardLevel(S32 discard) { mDesiredDiscardLevel = discard; } + S32 getDesiredDiscardLevel() { return mDesiredDiscardLevel; } + void setMinDiscardLevel(S32 discard) { mMinDesiredDiscardLevel = llmin(mMinDesiredDiscardLevel,(S8)discard); } + + bool updateFetch(); + + // Override the computation of discard levels if we know the exact output + // size of the image. Used for UI textures to not decode, even if we have + // more data. + void setKnownDrawSize(S32 width, S32 height); + + void setIsMissingAsset(); + /*virtual*/ BOOL isMissingAsset() const { return mIsMissingAsset; } + + // returns dimensions of original image for local files (before power of two scaling) + // and returns 0 for all asset system images + S32 getOriginalWidth() { return mOrigWidth; } + S32 getOriginalHeight() { return mOrigHeight; } + + BOOL isInImageList() const {return mInImageList ;} + void setInImageList(BOOL flag) {mInImageList = flag ;} + + const std::string& getLocalFileName() const {return mLocalFileName ;} + LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;} + + U32 getFetchPriority() const { return mFetchPriority ;} + F32 getDownloadProgress() const {return mDownloadProgress ;} + + LLImageRaw* readBackRawImage(S8 discard_level) ; + void destroyRawImage(); + + //--------------- + BOOL isDeleted() ; + BOOL isInactive() ; + BOOL isDeletionCandidate(); + void setDeletionCandidate() ; + void setInactive() ; + BOOL getUseDiscard() const { return mUseMipMaps && !mDontDiscard; } + //--------------- + + void setForSculpt(); + BOOL isForSculpt() const {return mForSculpt;} + +private: + void init(bool firstinit) ; + void cleanup() ; + + F32 calcDecodePriorityForUnknownTexture(F32 pixel_priority) ; + +private: + BOOL mFullyLoaded; + +protected: + S32 mOrigWidth; + S32 mOrigHeight; + + // Override the computation of discard levels if we know the exact output size of the image. + // Used for UI textures to not decode, even if we have more data. + S32 mKnownDrawWidth; + S32 mKnownDrawHeight; + + std::string mLocalFileName; + + S8 mDesiredDiscardLevel; // The discard level we'd LIKE to have - if we have it and there's space + S8 mMinDesiredDiscardLevel; // The minimum discard level we'd like to have + S32 mMinDiscardLevel; + + S32 mRequestedDiscardLevel; + F32 mRequestedDownloadPriority; + S32 mFetchState; + U32 mFetchPriority; + F32 mDownloadProgress; + F32 mFetchDeltaTime; + F32 mRequestDeltaTime; + S32 mDecodeFrame; + S32 mVisibleFrame; // decode frame where image was last visible + + S8 mNeedsAux; // We need to decode the auxiliary channels + S8 mDecodingAux; // Are we decoding high components + S8 mIsRawImageValid; + S8 mHasFetcher; // We've made a fecth request + S8 mIsFetching; // Fetch request is active + + mutable S8 mIsMissingAsset; // True if we know that there is no image asset with this image id in the database. + + F32 mDecodePriority; // The priority for decoding this image. + typedef std::list callback_list_t; + callback_list_t mLoadedCallbackList; + + LLPointer mRawImage; + S32 mRawDiscardLevel; + + // Used ONLY for cloth meshes right now. Make SURE you know what you're + // doing if you use it for anything else! - djs + LLPointer mAuxRawImage; + + LLHost mTargetHost; // if LLHost::invalid, just request from agent's simulator + + // Timers + LLFrameTimer mLastPacketTimer; // Time since last packet. + + BOOL mInImageList; // TRUE if image is in list (in which case don't reset priority!) + BOOL mNeedsCreateTexture; + + BOOL mForSculpt ; //a flag if the texture is used as sculpt data. + BOOL mIsFetched ; //is loaded from remote or from cache, not generated locally. + +public: + static LLPointer sMissingAssetImagep; // Texture to show for an image asset that is not in the database + static LLPointer sWhiteImagep; // Texture to show NOTHING (whiteness) + static LLPointer sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local. + static LLPointer sSmokeImagep; // Old "Default" translucent texture +}; + +// +//the image data is fetched from remote or from local cache +//the resolution of the texture is adjustable: depends on the view-dependent parameters. +// +class LLViewerLODTexture : public LLViewerFetchedTexture +{ +protected: + /*virtual*/ ~LLViewerLODTexture(){} + +public: + LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps = TRUE); + LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE); + + /*virtual*/ S8 getType() const; + // Process image stats to determine priority/quality requirements. + /*virtual*/ void processTextureStats(); + +private: + void init(bool firstinit) ; + +private: + + F32 mTexelsPerImage; // Texels per image. + F32 mDiscardVirtualSize; // Virtual size used to calculate desired discard + F32 mCalculatedDiscardLevel; // Last calculated discard level +}; + +// +//the image data is fetched from the media pipeline periodically +//the resolution of the texture is also adjusted by the media pipeline +// +class LLViewerMediaTexture : public LLViewerTexture +{ +protected: + /*virtual*/ ~LLViewerMediaTexture() {} + +public: + LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; + + /*virtual*/ S8 getType() const; + + void reinit(BOOL usemipmaps = TRUE); + + BOOL getUseMipMaps() {return mUseMipMaps ; } + void setUseMipMaps(BOOL mipmap) ; + + void setOldTexture(LLViewerTexture* tex) ; + LLViewerTexture* getOldTexture() const ; + + void setPlaying(BOOL playing) {mIsPlaying = playing ;} + BOOL isPlaying() const {return mIsPlaying;} + +private: + LLPointer mOldTexturep ; //the texture this media texture replaces. + BOOL mIsPlaying ; + +public: + static void updateClass() ; + +public: + typedef std::map< LLUUID, LLPointer > media_map_t ; + static media_map_t sMediaMap ; +}; + +//just an interface class, do not create instance from this class. +class LLViewerTextureManager +{ +private: + //make the constructor private to preclude creating instances from this class. + LLViewerTextureManager(){} + +public: + //texture pipeline tester + static LLTexturePipelineTester* sTesterp ; + + //returns NULL if tex is not a LLViewerFetchedTexture nor derived from LLViewerFetchedTexture. + static LLViewerFetchedTexture* staticCastToFetchedTexture(LLViewerTexture* tex, BOOL report_error = FALSE) ; + + // + //"find-texture" just check if the texture exists, if yes, return it, otherwise return null. + // + static LLViewerTexture* findTexture(const LLUUID& id) ; + static LLViewerMediaTexture* findMediaTexture(const LLUUID& id) ; + + static LLViewerMediaTexture* createMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; + + // + //"get-texture" will create a new texture if the texture does not exist. + // + static LLViewerMediaTexture* getMediaTexture(const LLUUID& id, BOOL usemipmaps = TRUE, LLImageGL* gl_image = NULL) ; + + static LLPointer getLocalTexture(BOOL usemipmaps = TRUE, BOOL generate_gl_tex = TRUE); + static LLPointer getLocalTexture(const LLUUID& id, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ; + static LLPointer getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) ; + static LLPointer getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex = TRUE) ; + + static LLViewerFetchedTexture* getFetchedTexture(const LLUUID &image_id, + BOOL usemipmap = TRUE, + BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, + LLGLint internal_format = 0, + LLGLenum primary_format = 0, + LLHost request_from_host = LLHost() + ); + + static LLViewerFetchedTexture* getFetchedTextureFromFile(const std::string& filename, + BOOL usemipmap = TRUE, + BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, + LLGLint internal_format = 0, + LLGLenum primary_format = 0, + const LLUUID& force_id = LLUUID::null + ); + + static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) ; + + static void init() ; + static void cleanup() ; +}; +// +//this class is used for test/debug only +//it tracks the activities of the texture pipeline +//records them, and outputs them to log files +// +class LLTexturePipelineTester : public LLMetricPerformanceTester +{ + enum + { + MIN_LARGE_IMAGE_AREA = 262144 //512 * 512 + }; +public: + LLTexturePipelineTester() ; + ~LLTexturePipelineTester() ; + + void update(); + void updateTextureBindingStats(const LLViewerTexture* imagep) ; + void updateTextureLoadingStats(const LLViewerFetchedTexture* imagep, const LLImageRaw* raw_imagep, BOOL from_cache) ; + void updateGrayTextureBinding() ; + void setStablizingTime() ; + + /*virtual*/ void analyzePerformance(std::ofstream* os, LLSD* base, LLSD* current) ; + +private: + void reset() ; + void updateStablizingTime() ; + + /*virtual*/ void outputTestRecord(LLSD* sd) ; + +private: + BOOL mPause ; +private: + BOOL mUsingDefaultTexture; //if set, some textures are still gray. + + U32 mTotalBytesUsed ; //total bytes of textures bound/used for the current frame. + U32 mTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the current frame for images larger than 256 * 256. + U32 mLastTotalBytesUsed ; //total bytes of textures bound/used for the previous frame. + U32 mLastTotalBytesUsedForLargeImage ; //total bytes of textures bound/used for the previous frame for images larger than 256 * 256. + + // + //data size + // + U32 mTotalBytesLoaded ; //total bytes fetched by texture pipeline + U32 mTotalBytesLoadedFromCache ; //total bytes fetched by texture pipeline from local cache + U32 mTotalBytesLoadedForLargeImage ; //total bytes fetched by texture pipeline for images larger than 256 * 256. + U32 mTotalBytesLoadedForSculpties ; //total bytes fetched by texture pipeline for sculpties + + // + //time + //NOTE: the error tolerances of the following timers is one frame time. + // + F32 mStartFetchingTime ; + F32 mTotalGrayTime ; //total loading time when no gray textures. + F32 mTotalStablizingTime ; //total stablizing time when texture memory overflows + F32 mStartTimeLoadingSculpties ; //the start moment of loading sculpty images. + F32 mEndTimeLoadingSculpties ; //the end moment of loading sculpty images. + F32 mStartStablizingTime ; + F32 mEndStablizingTime ; + +private: + // + //The following members are used for performance analyzing + // + class LLTextureTestSession : public LLTestSession + { + public: + LLTextureTestSession() ; + /*virtual*/ ~LLTextureTestSession() ; + + void reset() ; + + F32 mTotalFetchingTime ; + F32 mTotalGrayTime ; + F32 mTotalStablizingTime ; + F32 mStartTimeLoadingSculpties ; + F32 mTotalTimeLoadingSculpties ; + + S32 mTotalBytesLoaded ; + S32 mTotalBytesLoadedFromCache ; + S32 mTotalBytesLoadedForLargeImage ; + S32 mTotalBytesLoadedForSculpties ; + + typedef struct _texture_instant_preformance_t + { + S32 mAverageBytesUsedPerSecond ; + S32 mAverageBytesUsedForLargeImagePerSecond ; + F32 mAveragePercentageBytesUsedPerSecond ; + F32 mTime ; + }texture_instant_preformance_t ; + std::vector mInstantPerformanceList ; + S32 mInstantPerformanceListCounter ; + }; + + /*virtual*/ LLMetricPerformanceTester::LLTestSession* loadTestSession(LLSD* log) ; + /*virtual*/ void compareTestSessions(std::ofstream* os) ; +}; + +#endif diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp new file mode 100644 index 0000000000..dac2331ca3 --- /dev/null +++ b/indra/newview/llviewertexturelist.cpp @@ -0,0 +1,1513 @@ +/** + * @file llviewertexturelist.cpp + * @brief Object for managing the list of images within a region + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include + +#include "llviewertexturelist.h" + +#include "imageids.h" +#include "llgl.h" // fot gathering stats from GL +#include "llimagegl.h" +#include "llimagebmp.h" +#include "llimagej2c.h" +#include "llimagetga.h" +#include "llimagejpeg.h" +#include "llimagepng.h" + +#include "llsdserialize.h" +#include "llsys.h" +#include "llvfs.h" +#include "llvfile.h" +#include "llvfsthread.h" +#include "llxmltree.h" +#include "message.h" + +#include "lltexturecache.h" +#include "lltexturefetch.h" +#include "llviewercontrol.h" +#include "llviewertexture.h" +#include "llviewermedia.h" +#include "llviewerregion.h" +#include "llviewerstats.h" +#include "pipeline.h" +#include "llappviewer.h" +#include "llxuiparser.h" + +//////////////////////////////////////////////////////////////////////////// + +void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL; + +const S32 IMAGES_PER_REQUEST = 42; +const S32 IMAGES_MIN_UPDATES = 4; // Always update the highest N images each frame +const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame +const F32 RESEND_IMAGE_REQUEST_TIME = 15.f; // seconds + +LLViewerTextureList gTextureList; +static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images"); + +/////////////////////////////////////////////////////////////////////////////// + +LLViewerTextureList::LLViewerTextureList() + : mForceResetTextureStats(FALSE), + mUpdateStats(FALSE), + mMaxResidentTexMemInMegaBytes(0), + mMaxTotalTextureMemInMegaBytes(0) +{ +} + +void LLViewerTextureList::init() +{ + mNumImages = 0; + mMaxResidentTexMemInMegaBytes = 0; + mMaxTotalTextureMemInMegaBytes = 0 ; + if (gNoRender) + { + // Don't initialize GL stuff if we're not rendering. + return; + } + + mUpdateStats = TRUE; + + // Update how much texture RAM we're allowed to use. + updateMaxResidentTexMem(0); // 0 = use current + + doPreloadImages(); +} + + +void LLViewerTextureList::doPreloadImages() +{ + LL_DEBUGS("ViewerImages") << "Preloading images..." << LL_ENDL; + + // Set the "missing asset" image + LLViewerFetchedTexture::sMissingAssetImagep = LLViewerTextureManager::getFetchedTextureFromFile("missing_asset.tga", MIPMAP_NO, IMMEDIATE_YES); + + // Set the "white" image + LLViewerFetchedTexture::sWhiteImagep = LLViewerTextureManager::getFetchedTextureFromFile("white.tga", MIPMAP_NO, IMMEDIATE_YES); + + LLUIImageList* image_list = LLUIImageList::getInstance(); + + image_list->initFromFile(); + + // turn off clamping and bilinear filtering for uv picking images + //LLViewerFetchedTexture* uv_test = preloadUIImage("uv_test1.tga", LLUUID::null, FALSE); + //uv_test->setClamp(FALSE, FALSE); + //uv_test->setMipFilterNearest(TRUE, TRUE); + //uv_test = preloadUIImage("uv_test2.tga", LLUUID::null, FALSE); + //uv_test->setClamp(FALSE, FALSE); + //uv_test->setMipFilterNearest(TRUE, TRUE); + + // prefetch specific UUIDs + LLViewerTextureManager::getFetchedTexture(IMG_SHOT, TRUE); + LLViewerTextureManager::getFetchedTexture(IMG_SMOKE_POOF, TRUE); + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTextureFromFile("silhouette.j2c", MIPMAP_YES, IMMEDIATE_YES); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryLines.png", MIPMAP_YES, IMMEDIATE_YES); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + image = LLViewerTextureManager::getFetchedTextureFromFile("world/NoEntryPassLines.png", MIPMAP_YES, IMMEDIATE_YES); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + image = LLViewerTextureManager::getFetchedTexture(DEFAULT_WATER_NORMAL, MIPMAP_YES, IMMEDIATE_YES); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + image = LLViewerTextureManager::getFetchedTextureFromFile("transparent.j2c", MIPMAP_YES, IMMEDIATE_YES, LLViewerTexture::FETCHED_TEXTURE, + 0,0,LLUUID("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903")); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + } + +} + +static std::string get_texture_list_name() +{ + return std::string("texture_list_") + gSavedSettings.getString("LoginLocation") + ".xml"; +} + +void LLViewerTextureList::doPrefetchImages() +{ + if (LLAppViewer::instance()->getPurgeCache()) + { + // cache was purged, no point + return; + } + + // Pre-fetch textures from last logout + LLSD imagelist; + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name()); + llifstream file; + file.open(filename); + if (file.is_open()) + { + LLSDSerialize::fromXML(imagelist, file); + } + for (LLSD::array_iterator iter = imagelist.beginArray(); + iter != imagelist.endArray(); ++iter) + { + LLSD imagesd = *iter; + LLUUID uuid = imagesd["uuid"]; + S32 pixel_area = imagesd["area"]; + S32 texture_type = imagesd["type"]; + + if(LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type) + { + LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, MIPMAP_TRUE, FALSE, texture_type); + if (image) + { + image->addTextureStats((F32)pixel_area); + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +LLViewerTextureList::~LLViewerTextureList() +{ +} + +void LLViewerTextureList::shutdown() +{ + // clear out preloads + mImagePreloads.clear(); + + // Write out list of currently loaded textures for precaching on startup + typedef std::set > image_area_list_t; + image_area_list_t image_area_list; + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ++iter) + { + LLViewerFetchedTexture* image = *iter; + if (!image->hasGLTexture() || + !image->getUseDiscard() || + image->needsAux() || + image->getTargetHost() != LLHost::invalid) + { + continue; // avoid UI, baked, and other special images + } + S32 desired = image->getDesiredDiscardLevel(); + if (desired >= 0 && desired < MAX_DISCARD_LEVEL) + { + S32 pixel_area = image->getWidth(desired) * image->getHeight(desired); + image_area_list.insert(std::make_pair(pixel_area, image)); + } + } + + LLSD imagelist; + const S32 max_count = 1000; + S32 count = 0; + S32 image_type ; + for (image_area_list_t::reverse_iterator riter = image_area_list.rbegin(); + riter != image_area_list.rend(); ++riter) + { + LLViewerFetchedTexture* image = riter->second; + image_type = (S32)image->getType() ; + imagelist[count]["area"] = riter->first; + imagelist[count]["uuid"] = image->getID(); + imagelist[count]["type"] = image_type; + if (++count >= max_count) + break; + } + + if (count > 0 && !gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, "").empty()) + { + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, get_texture_list_name()); + llofstream file; + file.open(filename); + LLSDSerialize::toPrettyXML(imagelist, file); + } + + // + // Clean up "loaded" callbacks. + // + mCallbackList.clear(); + + // Flush all of the references + mLoadingStreamList.clear(); + mCreateTextureList.clear(); + + mUUIDMap.clear(); + + mImageList.clear(); +} + +void LLViewerTextureList::dump() +{ + llinfos << "LLViewerTextureList::dump()" << llendl; + for (image_priority_list_t::iterator it = mImageList.begin(); it != mImageList.end(); ++it) + { + LLViewerFetchedTexture* image = *it; + + llinfos << "priority " << image->getDecodePriority() + << " boost " << image->getBoostLevel() + << " size " << image->getWidth() << "x" << image->getHeight() + << " discard " << image->getDiscardLevel() + << " desired " << image->getDesiredDiscardLevel() + << " http://asset.siva.lindenlab.com/" << image->getID() << ".texture" + << llendl; + } +} + +void LLViewerTextureList::destroyGL(BOOL save_state) +{ + LLImageGL::destroyGL(save_state); +} + +void LLViewerTextureList::restoreGL() +{ + LLImageGL::restoreGL(); +} + +/* Vertical tab container button image IDs + Seem to not decode when running app in debug. + + const LLUUID BAD_IMG_ONE("1097dcb3-aef9-8152-f471-431d840ea89e"); + const LLUUID BAD_IMG_TWO("bea77041-5835-1661-f298-47e2d32b7a70"); + */ + +/////////////////////////////////////////////////////////////////////////////// + +LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename, + BOOL usemipmaps, + BOOL level_immediate, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + const LLUUID& force_id) +{ + if (gNoRender) + { + // Never mind that this ignores image_set_id; + // getImage() will handle that later. + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE); + } + + std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename); + if (full_path.empty()) + { + llwarns << "Failed to find local image file: " << filename << llendl; + return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE); + } + + // generate UUID based on hash of filename + LLUUID new_id; + if (force_id.notNull()) + { + new_id = force_id; + } + else + { + new_id.generate(full_path); + } + + LLPointer imagep = findImage(new_id); + + if (imagep.isNull()) + { + switch(texture_type) + { + case LLViewerTexture::FETCHED_TEXTURE: + imagep = new LLViewerFetchedTexture(full_path, new_id, usemipmaps); + break ; + case LLViewerTexture::LOD_TEXTURE: + imagep = new LLViewerLODTexture(full_path, new_id, usemipmaps); + break ; + default: + llerrs << "Invalid texture type " << texture_type << llendl ; + } + + if (internal_format && primary_format) + { + imagep->setExplicitFormat(internal_format, primary_format); + } + + addImage(imagep); + + if (level_immediate) + { + imagep->dontDiscard(); + imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI); + } + } + + imagep->setGLTextureCreated(true); + + return imagep; +} + + +LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id, + BOOL usemipmaps, + BOOL level_immediate, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + LLHost request_from_host) +{ + // Return the image with ID image_id + // If the image is not found, creates new image and + // enqueues a request for transmission + + if ((&image_id == NULL) || image_id.isNull()) + { + return (LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE)); + } + + LLPointer imagep = findImage(image_id); + + if (imagep.isNull()) + { + imagep = createImage(image_id, usemipmaps, level_immediate, texture_type, internal_format, primary_format, request_from_host) ; + } + + imagep->setGLTextureCreated(true); + + return imagep; +} + +//when this function is called, there is no such texture in the gTextureList with image_id. +LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id, + BOOL usemipmaps, + BOOL level_immediate, + S8 texture_type, + LLGLint internal_format, + LLGLenum primary_format, + LLHost request_from_host) +{ + LLPointer imagep ; + switch(texture_type) + { + case LLViewerTexture::FETCHED_TEXTURE: + imagep = new LLViewerFetchedTexture(image_id, usemipmaps); + break ; + case LLViewerTexture::LOD_TEXTURE: + imagep = new LLViewerLODTexture(image_id, usemipmaps); + break ; + default: + llerrs << "Invalid texture type " << texture_type << llendl ; + } + + // Might want to request from host other than where the agent is. JC + imagep->setTargetHost(request_from_host); + + if (internal_format && primary_format) + { + imagep->setExplicitFormat(internal_format, primary_format); + } + + addImage(imagep); + + if (level_immediate) + { + imagep->dontDiscard(); + imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI); + } + else + { + //by default, the texure can not be removed from memory even if it is not used. + //here turn this off + //if this texture should be set to NO_DELETE, either pass level_immediate == TRUE here, or call setNoDelete() afterwards. + imagep->forceActive() ; + } + + return imagep ; +} + +LLViewerFetchedTexture *LLViewerTextureList::findImage(const LLUUID &image_id) +{ + uuid_map_t::iterator iter = mUUIDMap.find(image_id); + if(iter == mUUIDMap.end()) + return NULL; + return iter->second; +} + +void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image) +{ + llassert(image); + if (image->isInImageList()) + { + llerrs << "LLViewerTextureList::addImageToList - Image already in list" << llendl; + } + llverify((mImageList.insert(image)).second == true); + image->setInImageList(TRUE) ; +} + +void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image) +{ + llassert(image); + if (!image->isInImageList()) + { + llinfos << "RefCount: " << image->getNumRefs() << llendl ; + uuid_map_t::iterator iter = mUUIDMap.find(image->getID()); + if(iter == mUUIDMap.end() || iter->second != image) + { + llinfos << "Image is not in mUUIDMap!" << llendl ; + } + llerrs << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl; + } + llverify(mImageList.erase(image) == 1); + image->setInImageList(FALSE) ; +} + +void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image) +{ + if (!new_image) + { + llwarning("No image to add to image list", 0); + return; + } + LLUUID image_id = new_image->getID(); + + LLViewerFetchedTexture *image = findImage(image_id); + if (image) + { + llwarns << "Image with ID " << image_id << " already in list" << llendl; + } + mNumImages++; + + addImageToList(new_image); + mUUIDMap[image_id] = new_image; +} + + +void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image) +{ + if( image) + { + if (image->hasCallbacks()) + { + mCallbackList.erase(image); + } + + llverify(mUUIDMap.erase(image->getID()) == 1); + mNumImages--; + removeImageFromList(image); + } +} + +/////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////// + +void LLViewerTextureList::dirtyImage(LLViewerFetchedTexture *image) +{ + mDirtyTextureList.insert(image); +} + +//////////////////////////////////////////////////////////////////////////// +static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images"); + +void LLViewerTextureList::updateImages(F32 max_time) +{ + LLViewerStats::getInstance()->mNumImagesStat.addValue(mNumImages); + LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount); + LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes)); + LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes)); + LLViewerStats::getInstance()->mRawMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageRaw::sGlobalRawMemory)); + LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory)); + + updateImagesDecodePriorities(); + max_time -= updateImagesFetchTextures(max_time); + max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f); + max_time -= updateImagesCreateTextures(max_time); + max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f); + if (!mDirtyTextureList.empty()) + { + LLFastTimer t(FTM_IMAGE_MARK_DIRTY); + gPipeline.dirtyPoolObjectTextures(mDirtyTextureList); + mDirtyTextureList.clear(); + } + bool didone = false; + for (image_list_t::iterator iter = mCallbackList.begin(); + iter != mCallbackList.end(); ) + { + //trigger loaded callbacks on local textures immediately + LLViewerFetchedTexture* image = *iter++; + if (!image->getLocalFileName().empty()) + { + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); + } + else if (!didone) + { + // Do stuff to handle callbacks, update priorities, etc. + didone = image->doLoadedCallbacks(); + } + } + if (!gNoRender && !gGLManager.mIsDisabled) + { + LLViewerMedia::updateMedia(); + } + updateImagesUpdateStats(); +} + +void LLViewerTextureList::updateImagesDecodePriorities() +{ + // Update the decode priority for N images each frame + { + const size_t max_update_count = llmin((S32) (1024*gFrameIntervalSeconds) + 1, 32); //target 1024 textures per second + S32 update_counter = llmin(max_update_count, mUUIDMap.size()/10); + uuid_map_t::iterator iter = mUUIDMap.upper_bound(mLastUpdateUUID); + while(update_counter > 0 && !mUUIDMap.empty()) + { + if (iter == mUUIDMap.end()) + { + iter = mUUIDMap.begin(); + } + mLastUpdateUUID = iter->first; + LLPointer imagep = iter->second; + ++iter; // safe to incrament now + + // + // Flush formatted images using a lazy flush + // + const F32 LAZY_FLUSH_TIMEOUT = 30.f; // stop decoding + const F32 MAX_INACTIVE_TIME = 50.f; // actually delete + S32 min_refs = 3; // 1 for mImageList, 1 for mUUIDMap, 1 for local reference + if (imagep->hasCallbacks()) + { + min_refs++; // Add an extra reference if we're on the loaded callback list + } + S32 num_refs = imagep->getNumRefs(); + if (num_refs == min_refs) + { + if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > LAZY_FLUSH_TIMEOUT) + { + // Remove the unused image from the image list + deleteImage(imagep); + imagep = NULL; // should destroy the image + } + continue; + } + else + { + if(imagep->isDeleted()) + { + continue ; + } + else if(imagep->isDeletionCandidate()) + { + imagep->destroyTexture() ; + continue ; + } + else if(imagep->isInactive()) + { + if (imagep->getLastReferencedTimer()->getElapsedTimeF32() > MAX_INACTIVE_TIME) + { + imagep->setDeletionCandidate() ; + } + continue ; + } + else + { + imagep->getLastReferencedTimer()->reset(); + + //reset texture state. + imagep->setInactive() ; + } + } + + imagep->processTextureStats(); + F32 old_priority = imagep->getDecodePriority(); + F32 old_priority_test = llmax(old_priority, 0.0f); + F32 decode_priority = imagep->calcDecodePriority(); + F32 decode_priority_test = llmax(decode_priority, 0.0f); + // Ignore < 20% difference + if ((decode_priority_test < old_priority_test * .8f) || + (decode_priority_test > old_priority_test * 1.25f)) + { + removeImageFromList(imagep); + imagep->setDecodePriority(decode_priority); + addImageToList(imagep); + } + update_counter--; + } + } +} + +/* + static U8 get_image_type(LLViewerFetchedTexture* imagep, LLHost target_host) + { + // Having a target host implies this is a baked image. I don't + // believe that boost level has been set at this point. JC + U8 type_from_host = (target_host.isOk() + ? LLImageBase::TYPE_AVATAR_BAKE + : LLImageBase::TYPE_NORMAL); + S32 boost_level = imagep->getBoostLevel(); + U8 type_from_boost = ( (boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED + || boost_level == LLViewerFetchedTexture::BOOST_AVATAR_BAKED_SELF) + ? LLImageBase::TYPE_AVATAR_BAKE + : LLImageBase::TYPE_NORMAL); + if (type_from_host == LLImageBase::TYPE_NORMAL + && type_from_boost == LLImageBase::TYPE_AVATAR_BAKE) + { + llwarns << "TAT: get_image_type() type_from_host doesn't match type_from_boost" + << " host " << target_host + << " boost " << imagep->getBoostLevel() + << " imageid " << imagep->getID() + << llendl; + imagep->dump(); + } + return type_from_host; + } + */ +static LLFastTimer::DeclareTimer FTM_IMAGE_CREATE("Create Images"); + +F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) +{ + if (gNoRender || gGLManager.mIsDisabled) return 0.0f; + + // + // Create GL textures for all textures that need them (images which have been + // decoded, but haven't been pushed into GL). + // + LLFastTimer t(FTM_IMAGE_CREATE); + + LLTimer create_timer; + image_list_t::iterator enditer = mCreateTextureList.begin(); + for (image_list_t::iterator iter = mCreateTextureList.begin(); + iter != mCreateTextureList.end();) + { + image_list_t::iterator curiter = iter++; + enditer = iter; + LLViewerFetchedTexture *imagep = *curiter; + imagep->createTexture(); + if (create_timer.getElapsedTimeF32() > max_time) + { + break; + } + } + mCreateTextureList.erase(mCreateTextureList.begin(), enditer); + return create_timer.getElapsedTimeF32(); +} + +void LLViewerTextureList::forceImmediateUpdate(LLViewerFetchedTexture* imagep) +{ + if(!imagep) + { + return ; + } + if(imagep->isInImageList()) + { + removeImageFromList(imagep); + } + + imagep->processTextureStats(); + F32 decode_priority = LLViewerFetchedTexture::maxDecodePriority() ; + imagep->setDecodePriority(decode_priority); + mImageList.insert(imagep); + imagep->setInImageList(TRUE) ; + + return ; +} + +F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time) +{ + LLTimer image_op_timer; + + // Update the decode priority for N images each frame + // Make a list with 32 high priority entries + 256 cycled entries + const size_t max_priority_count = llmin((S32) (256*10.f*gFrameIntervalSeconds)+1, 32); + const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256); + + // 32 high priority entries + std::set entries; + size_t update_counter = llmin(max_priority_count, mImageList.size()); + image_priority_list_t::iterator iter1 = mImageList.begin(); + while(update_counter > 0) + { + // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad + if(iter1 == mImageList.end()) + { + llerrs << "DEV-12002: update_counter not calculated correctly!" << llendl; + return 0.f; + } + + LLPointer const & ptr = *iter1; + + LLViewerFetchedTexture * img = ptr.get(); + + // added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad + if(img == NULL) + { + llwarns << "DEV-12002: image is NULL!" << llendl; + } + + entries.insert(img); + + ++iter1; + update_counter--; + } + + // 256 cycled entries + update_counter = llmin(max_update_count, mUUIDMap.size()); + uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID); + while(update_counter > 0) + { + if (iter2 == mUUIDMap.end()) + { + iter2 = mUUIDMap.begin(); + } + mLastFetchUUID = iter2->first; + entries.insert(iter2->second); + ++iter2; + update_counter--; + } + + S32 min_count = max_priority_count + max_update_count/4; + for (std::set::iterator iter3 = entries.begin(); + iter3 != entries.end(); ) + { + LLPointer imagep = *iter3++; + + imagep->updateFetch(); + if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time) + { + break; + } + min_count--; + } + return image_op_timer.getElapsedTimeF32(); +} + +void LLViewerTextureList::updateImagesUpdateStats() +{ + if (mUpdateStats) + { + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ) + { + LLViewerFetchedTexture* imagep = *iter++; + imagep->resetTextureStats(mForceResetTextureStats); + } + mUpdateStats = FALSE; + mForceResetTextureStats = FALSE; + } +} + +void LLViewerTextureList::decodeAllImages(F32 max_time) +{ + LLTimer timer; + if(gNoRender) return; + + // Update texture stats and priorities + std::vector > image_list; + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ) + { + LLViewerFetchedTexture* imagep = *iter++; + image_list.push_back(imagep); + imagep->setInImageList(FALSE) ; + } + mImageList.clear(); + for (std::vector >::iterator iter = image_list.begin(); + iter != image_list.end(); ++iter) + { + LLViewerFetchedTexture* imagep = *iter; + imagep->processTextureStats(); + F32 decode_priority = imagep->calcDecodePriority(); + imagep->setDecodePriority(decode_priority); + mImageList.insert(imagep); + imagep->setInImageList(TRUE) ; + } + image_list.clear(); + + // Update fetch (decode) + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ) + { + LLViewerFetchedTexture* imagep = *iter++; + imagep->updateFetch(); + } + // Run threads + S32 fetch_pending = 0; + while (1) + { + LLAppViewer::instance()->getTextureCache()->update(1); // unpauses the texture cache thread + LLAppViewer::instance()->getImageDecodeThread()->update(1); // unpauses the image thread + fetch_pending = LLAppViewer::instance()->getTextureFetch()->update(1); // unpauses the texture fetch thread + if (fetch_pending == 0 || timer.getElapsedTimeF32() > max_time) + { + break; + } + } + // Update fetch again + for (image_priority_list_t::iterator iter = mImageList.begin(); + iter != mImageList.end(); ) + { + LLViewerFetchedTexture* imagep = *iter++; + imagep->updateFetch(); + } + max_time -= timer.getElapsedTimeF32(); + max_time = llmax(max_time, .001f); + F32 create_time = updateImagesCreateTextures(max_time); + + LL_DEBUGS("ViewerImages") << "decodeAllImages() took " << timer.getElapsedTimeF32() << " seconds. " + << " fetch_pending " << fetch_pending + << " create_time " << create_time + << LL_ENDL; +} + + +BOOL LLViewerTextureList::createUploadFile(const std::string& filename, + const std::string& out_filename, + const U8 codec) +{ + // First, load the image. + LLPointer raw_image = new LLImageRaw; + + switch (codec) + { + case IMG_CODEC_BMP: + { + LLPointer bmp_image = new LLImageBMP; + + if (!bmp_image->load(filename)) + { + return FALSE; + } + + if (!bmp_image->decode(raw_image, 0.0f)) + { + return FALSE; + } + } + break; + case IMG_CODEC_TGA: + { + LLPointer tga_image = new LLImageTGA; + + if (!tga_image->load(filename)) + { + return FALSE; + } + + if (!tga_image->decode(raw_image)) + { + return FALSE; + } + + if( (tga_image->getComponents() != 3) && + (tga_image->getComponents() != 4) ) + { + tga_image->setLastError( "Image files with less than 3 or more than 4 components are not supported." ); + return FALSE; + } + } + break; + case IMG_CODEC_JPEG: + { + LLPointer jpeg_image = new LLImageJPEG; + + if (!jpeg_image->load(filename)) + { + return FALSE; + } + + if (!jpeg_image->decode(raw_image, 0.0f)) + { + return FALSE; + } + } + break; + case IMG_CODEC_PNG: + { + LLPointer png_image = new LLImagePNG; + + if (!png_image->load(filename)) + { + return FALSE; + } + + if (!png_image->decode(raw_image, 0.0f)) + { + return FALSE; + } + } + break; + default: + return FALSE; + } + + LLPointer compressedImage = convertToUploadFile(raw_image); + + if( !compressedImage->save(out_filename) ) + { + llinfos << "Couldn't create output file " << out_filename << llendl; + return FALSE; + } + + // test to see if the encode and save worked. + LLPointer integrity_test = new LLImageJ2C; + if( !integrity_test->loadAndValidate( out_filename ) ) + { + llinfos << "Image: " << out_filename << " is corrupt." << llendl; + return FALSE; + } + + return TRUE; +} + +// note: modifies the argument raw_image!!!! +LLPointer LLViewerTextureList::convertToUploadFile(LLPointer raw_image) +{ + raw_image->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); + LLPointer compressedImage = new LLImageJ2C(); + compressedImage->setRate(0.f); + + if (gSavedSettings.getBOOL("LosslessJ2CUpload") && + (raw_image->getWidth() * raw_image->getHeight() <= LL_IMAGE_REZ_LOSSLESS_CUTOFF * LL_IMAGE_REZ_LOSSLESS_CUTOFF)) + compressedImage->setReversible(TRUE); + + compressedImage->encode(raw_image, 0.0f); + + return compressedImage; +} + +// Returns min setting for TextureMemory (in MB) +S32 LLViewerTextureList::getMinVideoRamSetting() +{ + S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); + //min texture mem sets to 64M if total physical mem is more than 1.5GB + return (system_ram > 1500) ? 64 : MIN_VIDEO_RAM_IN_MEGA_BYTES ; +} + +//static +// Returns max setting for TextureMemory (in MB) +S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended) +{ + S32 max_texmem; + if (gGLManager.mVRAM != 0) + { + // Treat any card with < 32 MB (shudder) as having 32 MB + // - it's going to be swapping constantly regardless + S32 max_vram = gGLManager.mVRAM; + max_vram = llmax(max_vram, getMinVideoRamSetting()); + max_texmem = max_vram; + if (!get_recommended) + max_texmem *= 2; + } + else + { + if (get_recommended) + max_texmem = 128; + else + max_texmem = 512; + llwarns << "VRAM amount not detected, defaulting to " << max_texmem << " MB" << llendl; + } + + S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB + //llinfos << "*** DETECTED " << system_ram << " MB of system memory." << llendl; + if (get_recommended) + max_texmem = llmin(max_texmem, (S32)(system_ram/2)); + else + max_texmem = llmin(max_texmem, (S32)(system_ram)); + + max_texmem = llclamp(max_texmem, getMinVideoRamSetting(), MAX_VIDEO_RAM_IN_MEGA_BYTES); + + return max_texmem; +} + +const S32 VIDEO_CARD_FRAMEBUFFER_MEM = 12; // MB +const S32 MIN_MEM_FOR_NON_TEXTURE = 512 ; //MB +void LLViewerTextureList::updateMaxResidentTexMem(S32 mem) +{ + // Initialize the image pipeline VRAM settings + S32 cur_mem = gSavedSettings.getS32("TextureMemory"); + F32 mem_multiplier = gSavedSettings.getF32("RenderTextureMemoryMultiple"); + S32 default_mem = getMaxVideoRamSetting(true); // recommended default + if (mem == 0) + { + mem = cur_mem > 0 ? cur_mem : default_mem; + } + else if (mem < 0) + { + mem = default_mem; + } + + // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise + mem = llmin(mem, (S32) (mem_multiplier * (F32) default_mem)); + + mem = llclamp(mem, getMinVideoRamSetting(), getMaxVideoRamSetting()); + if (mem != cur_mem) + { + gSavedSettings.setS32("TextureMemory", mem); + return; //listener will re-enter this function + } + + // TODO: set available resident texture mem based on use by other subsystems + // currently max(12MB, VRAM/4) assumed... + + S32 vb_mem = mem; + S32 fb_mem = llmax(VIDEO_CARD_FRAMEBUFFER_MEM, vb_mem/4); + mMaxResidentTexMemInMegaBytes = (vb_mem - fb_mem) ; //in MB + + mMaxTotalTextureMemInMegaBytes = mMaxResidentTexMemInMegaBytes * 2; + if (mMaxResidentTexMemInMegaBytes > 640) + { + mMaxTotalTextureMemInMegaBytes -= (mMaxResidentTexMemInMegaBytes >> 2); + } + + //system mem + S32 system_ram = (S32)BYTES_TO_MEGA_BYTES(gSysMemory.getPhysicalMemoryClamped()); // In MB + + //minimum memory reserved for non-texture use. + //if system_raw >= 1GB, reserve at least 512MB for non-texture use; + //otherwise reserve half of the system_ram for non-texture use. + S32 min_non_texture_mem = llmin(system_ram / 2, MIN_MEM_FOR_NON_TEXTURE) ; + + if (mMaxTotalTextureMemInMegaBytes > system_ram - min_non_texture_mem) + { + mMaxTotalTextureMemInMegaBytes = system_ram - min_non_texture_mem ; + } + + llinfos << "Total Video Memory set to: " << vb_mem << " MB" << llendl; + llinfos << "Available Texture Memory set to: " << (vb_mem - fb_mem) << " MB" << llendl; +} + +/////////////////////////////////////////////////////////////////////////////// + +// static +void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_data) +{ + LLFastTimer t(FTM_PROCESS_IMAGES); + + // Receive image header, copy into image object and decompresses + // if this is a one-packet image. + + LLUUID id; + + char ip_string[256]; + u32_to_ip_string(msg->getSenderIP(),ip_string); + + if (msg->getReceiveCompressedSize()) + { + gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8; + } + else + { + gTextureList.mTextureBits += msg->getReceiveSize() * 8; + } + gTextureList.mTexturePackets++; + + U8 codec; + U16 packets; + U32 totalbytes; + msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id); + msg->getU8Fast(_PREHASH_ImageID, _PREHASH_Codec, codec); + msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packets, packets); + msg->getU32Fast(_PREHASH_ImageID, _PREHASH_Size, totalbytes); + + S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); + if (!data_size) + { + return; + } + if (data_size < 0) + { + // msg->getSizeFast() is probably trying to tell us there + // was an error. + llerrs << "image header chunk size was negative: " + << data_size << llendl; + return; + } + + // this buffer gets saved off in the packet list + U8 *data = new U8[data_size]; + msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); + + LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + if (!image) + { + delete [] data; + return; + } + image->getLastPacketTimer()->reset(); + bool res = LLAppViewer::getTextureFetch()->receiveImageHeader(msg->getSender(), id, codec, packets, totalbytes, data_size, data); + if (!res) + { + delete[] data; + } +} + +// static +void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_data) +{ + LLMemType mt1(LLMemType::MTYPE_APPFMTIMAGE); + LLFastTimer t(FTM_PROCESS_IMAGES); + + // Receives image packet, copy into image object, + // checks if all packets received, decompresses if so. + + LLUUID id; + U16 packet_num; + + char ip_string[256]; + u32_to_ip_string(msg->getSenderIP(),ip_string); + + if (msg->getReceiveCompressedSize()) + { + gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8; + } + else + { + gTextureList.mTextureBits += msg->getReceiveSize() * 8; + } + gTextureList.mTexturePackets++; + + //llprintline("Start decode, image header..."); + msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id); + msg->getU16Fast(_PREHASH_ImageID, _PREHASH_Packet, packet_num); + S32 data_size = msg->getSizeFast(_PREHASH_ImageData, _PREHASH_Data); + + if (!data_size) + { + return; + } + if (data_size < 0) + { + // msg->getSizeFast() is probably trying to tell us there + // was an error. + llerrs << "image data chunk size was negative: " + << data_size << llendl; + return; + } + if (data_size > MTUBYTES) + { + llerrs << "image data chunk too large: " << data_size << " bytes" << llendl; + return; + } + U8 *data = new U8[data_size]; + msg->getBinaryDataFast(_PREHASH_ImageData, _PREHASH_Data, data, data_size); + + LLViewerFetchedTexture *image = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + if (!image) + { + delete [] data; + return; + } + image->getLastPacketTimer()->reset(); + bool res = LLAppViewer::getTextureFetch()->receiveImagePacket(msg->getSender(), id, packet_num, data_size, data); + if (!res) + { + delete[] data; + } +} + + +// We've been that the asset server does not contain the requested image id. +// static +void LLViewerTextureList::processImageNotInDatabase(LLMessageSystem *msg,void **user_data) +{ + LLFastTimer t(FTM_PROCESS_IMAGES); + LLUUID image_id; + msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, image_id); + + LLViewerFetchedTexture* image = gTextureList.findImage( image_id ); + if( image ) + { + image->setIsMissingAsset(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +//static +const U32 SIXTEEN_MEG = 0x1000000; +S32 LLViewerTextureList::calcMaxTextureRAM() +{ + // Decide the maximum amount of RAM we should allow the user to allocate to texture cache + LLMemoryInfo memory_info; + U32 available_memory = memory_info.getPhysicalMemoryClamped(); + + clamp_rescale((F32)available_memory, + (F32)(SIXTEEN_MEG * 16), + (F32)U32_MAX, + (F32)(SIXTEEN_MEG * 4), + (F32)(U32_MAX >> 1)); + return available_memory; +} + +/////////////////////////////////////////////////////////////////////////////// + +// explicitly cleanup resources, as this is a singleton class with process +// lifetime so ability to perform std::map operations in destructor is not +// guaranteed. +void LLUIImageList::cleanUp() +{ + mUIImages.clear(); + mUITextureList.clear() ; +} + +LLUIImagePtr LLUIImageList::getUIImageByID(const LLUUID& image_id) +{ + // use id as image name + std::string image_name = image_id.asString(); + + // look for existing image + uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name); + if (found_it != mUIImages.end()) + { + return found_it->second; + } + + return loadUIImageByID(image_id); +} + +LLUIImagePtr LLUIImageList::getUIImage(const std::string& image_name) +{ + // look for existing image + uuid_ui_image_map_t::iterator found_it = mUIImages.find(image_name); + if (found_it != mUIImages.end()) + { + return found_it->second; + } + + return loadUIImageByName(image_name, image_name); +} + +LLUIImagePtr LLUIImageList::loadUIImageByName(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect) +{ + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTextureFromFile(filename, MIPMAP_NO, IMMEDIATE_YES); + return loadUIImage(imagep, name, use_mips, scale_rect); +} + +LLUIImagePtr LLUIImageList::loadUIImageByID(const LLUUID& id, BOOL use_mips, const LLRect& scale_rect) +{ + LLViewerFetchedTexture* imagep = LLViewerTextureManager::getFetchedTexture(id, MIPMAP_NO, IMMEDIATE_YES); + return loadUIImage(imagep, id.asString(), use_mips, scale_rect); +} + +LLUIImagePtr LLUIImageList::loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips, const LLRect& scale_rect) +{ + if (!imagep) return NULL; + + imagep->setAddressMode(LLTexUnit::TAM_CLAMP); + + //all UI images are non-deletable + imagep->setNoDelete() ; + + LLUIImagePtr new_imagep = new LLUIImage(name, imagep); + mUIImages.insert(std::make_pair(name, new_imagep)); + mUITextureList.push_back(imagep) ; + + LLUIImageLoadData* datap = new LLUIImageLoadData; + datap->mImageName = name; + datap->mImageScaleRegion = scale_rect; + + imagep->setLoadedCallback(onUIImageLoaded, 0, FALSE, FALSE, datap); + + return new_imagep; +} + +LLUIImagePtr LLUIImageList::preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect) +{ + // look for existing image + uuid_ui_image_map_t::iterator found_it = mUIImages.find(name); + if (found_it != mUIImages.end()) + { + // image already loaded! + llerrs << "UI Image " << name << " already loaded." << llendl; + } + + return loadUIImageByName(name, filename, use_mips, scale_rect); +} + +//static +void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* user_data ) +{ + if(!success || !user_data) + { + return; + } + + LLUIImageLoadData* image_datap = (LLUIImageLoadData*)user_data; + std::string ui_image_name = image_datap->mImageName; + LLRect scale_rect = image_datap->mImageScaleRegion; + if (final) + { + delete image_datap; + } + + LLUIImageList* instance = getInstance(); + + uuid_ui_image_map_t::iterator found_it = instance->mUIImages.find(ui_image_name); + if (found_it != instance->mUIImages.end()) + { + LLUIImagePtr imagep = found_it->second; + + // for images grabbed from local files, apply clipping rectangle to restore original dimensions + // from power-of-2 gl image + if (success && imagep.notNull() && src_vi && !src_vi->getLocalFileName().empty()) + { + F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getFullWidth(); + F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getFullHeight(); + imagep->setClipRegion(LLRectf(0.f, clip_y, clip_x, 0.f)); + if (scale_rect != LLRect::null) + { + imagep->setScaleRegion( + LLRectf(llclamp((F32)scale_rect.mLeft / (F32)imagep->getWidth(), 0.f, 1.f), + llclamp((F32)scale_rect.mTop / (F32)imagep->getHeight(), 0.f, 1.f), + llclamp((F32)scale_rect.mRight / (F32)imagep->getWidth(), 0.f, 1.f), + llclamp((F32)scale_rect.mBottom / (F32)imagep->getHeight(), 0.f, 1.f))); + } + } + } +} + +struct UIImageDeclaration : public LLInitParam::Block +{ + Mandatory name; + Optional file_name; + Optional preload; + Optional scale_rect; + Optional use_mips; + + UIImageDeclaration() + : name("name"), + file_name("file_name"), + preload("preload", false), + scale_rect("scale"), + use_mips("use_mips", false) + {} +}; + +struct UIImageDeclarations : public LLInitParam::Block +{ + Mandatory version; + Multiple textures; + + UIImageDeclarations() + : version("version"), + textures("texture") + {} +}; + +bool LLUIImageList::initFromFile() +{ + // construct path to canonical textures.xml in default skin dir + std::string base_file_path = gDirUtilp->getExpandedFilename(LL_PATH_SKINS, "default", "textures", "textures.xml"); + + LLXMLNodePtr root; + + if (!LLXMLNode::parseFile(base_file_path, root, NULL)) + { + llwarns << "Unable to parse UI image list file " << base_file_path << llendl; + return false; + } + + std::vector paths; + // path to current selected skin + paths.push_back(gDirUtilp->getSkinDir() + + gDirUtilp->getDirDelimiter() + + "textures" + + gDirUtilp->getDirDelimiter() + + "textures.xml"); + // path to user overrides on current skin + paths.push_back(gDirUtilp->getUserSkinDir() + + gDirUtilp->getDirDelimiter() + + "textures" + + gDirUtilp->getDirDelimiter() + + "textures.xml"); + + // apply skinned xml files incrementally + for(std::vector::iterator path_it = paths.begin(); + path_it != paths.end(); + ++path_it) + { + // don't reapply base file to itself + if (!path_it->empty() && (*path_it) != base_file_path) + { + LLXMLNodePtr update_root; + if (LLXMLNode::parseFile(*path_it, update_root, NULL)) + { + LLXMLNode::updateNode(root, update_root); + } + } + } + + UIImageDeclarations images; + LLXUIParser::instance().readXUI(root, images); + + if (!images.validateBlock()) return false; + + enum e_decode_pass + { + PASS_DECODE_NOW, + PASS_DECODE_LATER, + NUM_PASSES + }; + + for (S32 cur_pass = PASS_DECODE_NOW; cur_pass < NUM_PASSES; cur_pass++) + { + for (LLInitParam::ParamIterator::const_iterator image_it = images.textures().begin(); + image_it != images.textures().end(); + ++image_it) + { + std::string file_name = image_it->file_name.isProvided() ? image_it->file_name() : image_it->name(); + + // load high priority textures on first pass (to kick off decode) + enum e_decode_pass decode_pass = image_it->preload ? PASS_DECODE_NOW : PASS_DECODE_LATER; + if (decode_pass != cur_pass) + { + continue; + } + preloadUIImage(image_it->name, file_name, image_it->use_mips, image_it->scale_rect); + } + + if (cur_pass == PASS_DECODE_NOW && !gSavedSettings.getBOOL("NoPreload")) + { + gTextureList.decodeAllImages(10.f); // decode preloaded images + } + } + return true; +} + + diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h new file mode 100644 index 0000000000..11d1dd855f --- /dev/null +++ b/indra/newview/llviewertexturelist.h @@ -0,0 +1,243 @@ +/** + * @file llviewertexturelist.h + * @brief Object for managing the list of images within a region + * + * $LicenseInfo:firstyear=2000&license=viewergpl$ + * + * Copyright (c) 2000-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVIEWERTEXTURELIST_H +#define LL_LLVIEWERTEXTURELIST_H + +#include "lluuid.h" +//#include "message.h" +#include "llgl.h" +#include "llstat.h" +#include "llviewertexture.h" +#include "llui.h" +#include +#include + +const U32 LL_IMAGE_REZ_LOSSLESS_CUTOFF = 128; + +const BOOL MIPMAP_YES = TRUE; +const BOOL MIPMAP_NO = FALSE; + +const BOOL GL_TEXTURE_YES = TRUE; +const BOOL GL_TEXTURE_NO = FALSE; + +const BOOL IMMEDIATE_YES = TRUE; +const BOOL IMMEDIATE_NO = FALSE; + +class LLImageJ2C; +class LLMessageSystem; +class LLTextureView; + +typedef void (*LLImageCallback)(BOOL success, + LLViewerFetchedTexture *src_vi, + LLImageRaw* src, + LLImageRaw* src_aux, + S32 discard_level, + BOOL final, + void* userdata); + +class LLViewerTextureList +{ + LOG_CLASS(LLViewerTextureList); + + friend class LLTextureView; + friend class LLViewerTextureManager; + +public: + static BOOL createUploadFile(const std::string& filename, const std::string& out_filename, const U8 codec); + static LLPointer convertToUploadFile(LLPointer raw_image); + static void processImageNotInDatabase( LLMessageSystem *msg, void **user_data ); + static S32 calcMaxTextureRAM(); + static void receiveImageHeader(LLMessageSystem *msg, void **user_data); + static void receiveImagePacket(LLMessageSystem *msg, void **user_data); + +public: + LLViewerTextureList(); + ~LLViewerTextureList(); + + void init(); + void shutdown(); + void dump(); + void destroyGL(BOOL save_state = TRUE); + void restoreGL(); + + LLViewerFetchedTexture *findImage(const LLUUID &image_id); + + void dirtyImage(LLViewerFetchedTexture *image); + + // Using image stats, determine what images are necessary, and perform image updates. + void updateImages(F32 max_time); + void forceImmediateUpdate(LLViewerFetchedTexture* imagep) ; + + // Decode and create textures for all images currently in list. + void decodeAllImages(F32 max_decode_time); + + void handleIRCallback(void **data, const S32 number); + + void setUpdateStats(BOOL b) { mUpdateStats = b; } + + S32 getMaxResidentTexMem() const { return mMaxResidentTexMemInMegaBytes; } + S32 getMaxTotalTextureMem() const { return mMaxTotalTextureMemInMegaBytes;} + S32 getNumImages() { return mImageList.size(); } + + void updateMaxResidentTexMem(S32 mem); + + void doPreloadImages(); + void doPrefetchImages(); + + static S32 getMinVideoRamSetting(); + static S32 getMaxVideoRamSetting(bool get_recommended = false); + +private: + void updateImagesDecodePriorities(); + F32 updateImagesCreateTextures(F32 max_time); + F32 updateImagesFetchTextures(F32 max_time); + void updateImagesUpdateStats(); + + void addImage(LLViewerFetchedTexture *image); + void deleteImage(LLViewerFetchedTexture *image); + + void addImageToList(LLViewerFetchedTexture *image); + void removeImageFromList(LLViewerFetchedTexture *image); + + LLViewerFetchedTexture * getImage(const LLUUID &image_id, + BOOL usemipmap = TRUE, + BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, + LLGLint internal_format = 0, + LLGLenum primary_format = 0, + LLHost request_from_host = LLHost() + ); + + LLViewerFetchedTexture * getImageFromFile(const std::string& filename, + BOOL usemipmap = TRUE, + BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, + LLGLint internal_format = 0, + LLGLenum primary_format = 0, + const LLUUID& force_id = LLUUID::null + ); + + LLViewerFetchedTexture* createImage(const LLUUID &image_id, + BOOL usemipmap = TRUE, + BOOL level_immediate = FALSE, // Get the requested level immediately upon creation. + S8 texture_type = LLViewerTexture::FETCHED_TEXTURE, + LLGLint internal_format = 0, + LLGLenum primary_format = 0, + LLHost request_from_host = LLHost() + ); + + // Request image from a specific host, used for baked avatar textures. + // Implemented in header in case someone changes default params above. JC + LLViewerFetchedTexture* getImageFromHost(const LLUUID& image_id, LLHost host) + { return getImage(image_id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE, 0, 0, host); } + +public: + typedef std::set > image_list_t; + image_list_t mLoadingStreamList; + image_list_t mCreateTextureList; + image_list_t mCallbackList; + + // Note: just raw pointers because they are never referenced, just compared against + std::set mDirtyTextureList; + + BOOL mForceResetTextureStats; + +private: + typedef std::map< LLUUID, LLPointer > uuid_map_t; + uuid_map_t mUUIDMap; + LLUUID mLastUpdateUUID; + LLUUID mLastFetchUUID; + + typedef std::set, LLViewerFetchedTexture::Compare> image_priority_list_t; + image_priority_list_t mImageList; + + // simply holds on to LLViewerFetchedTexture references to stop them from being purged too soon + std::set > mImagePreloads; + + BOOL mUpdateStats; + S32 mMaxResidentTexMemInMegaBytes; + S32 mMaxTotalTextureMemInMegaBytes; + LLFrameTimer mForceDecodeTimer; + +public: + U32 mTextureBits; + U32 mTexturePackets; + +private: + S32 mNumImages; + static void (*sUUIDCallback)(void**, const LLUUID &); +}; + +class LLUIImageList : public LLImageProviderInterface, public LLSingleton +{ +public: + // LLImageProviderInterface + LLUIImagePtr getUIImageByID(const LLUUID& id); + LLUIImagePtr getUIImage(const std::string& name); + void cleanUp(); + + bool initFromFile(); + + LLUIImagePtr preloadUIImage(const std::string& name, const std::string& filename, BOOL use_mips, const LLRect& scale_rect); + + static void onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata ); +private: + LLUIImagePtr loadUIImageByName(const std::string& name, const std::string& filename, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); + LLUIImagePtr loadUIImageByID(const LLUUID& id, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); + + LLUIImagePtr loadUIImage(LLViewerFetchedTexture* imagep, const std::string& name, BOOL use_mips = FALSE, const LLRect& scale_rect = LLRect::null); + + + struct LLUIImageLoadData + { + std::string mImageName; + LLRect mImageScaleRegion; + }; + + typedef std::map< std::string, LLPointer > uuid_ui_image_map_t; + uuid_ui_image_map_t mUIImages; + + // + //keep a copy of UI textures to prevent them to be deleted. + //mGLTexturep of each UI texture equals to some LLUIImage.mImage. + std::list< LLPointer > mUITextureList ; +}; + +const BOOL GLTEXTURE_TRUE = TRUE; +const BOOL GLTEXTURE_FALSE = FALSE; +const BOOL MIPMAP_TRUE = TRUE; +const BOOL MIPMAP_FALSE = FALSE; + +extern LLViewerTextureList gTextureList; + +#endif diff --git a/indra/newview/llviewervisualparam.cpp b/indra/newview/llviewervisualparam.cpp index 8c7700eb65..7d717ed6dc 100644 --- a/indra/newview/llviewervisualparam.cpp +++ b/indra/newview/llviewervisualparam.cpp @@ -76,7 +76,7 @@ BOOL LLViewerVisualParamInfo::parseXml(LLXmlTreeNode *node) static LLStdStringHandle wearable_string = LLXmlTree::addAttributeString("wearable"); if( node->getFastAttributeString( wearable_string, wearable) ) { - mWearableType = LLWearable::typeNameToType( wearable ); + mWearableType = LLWearableDictionary::typeNameToType( wearable ); } static LLStdStringHandle edit_group_string = LLXmlTree::addAttributeString("edit_group"); @@ -119,12 +119,6 @@ LLViewerVisualParam::LLViewerVisualParam() { } -/* -//============================================================================= -// These virtual functions should always be overridden, -// but are included here for use as templates -//============================================================================= - //----------------------------------------------------------------------------- // setInfo() //----------------------------------------------------------------------------- @@ -140,6 +134,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info) return TRUE; } +/* +//============================================================================= +// These virtual functions should always be overridden, +// but are included here for use as templates +//============================================================================= + //----------------------------------------------------------------------------- // parseData() //----------------------------------------------------------------------------- diff --git a/indra/newview/llviewervisualparam.h b/indra/newview/llviewervisualparam.h index 48d28cebf3..77a95db564 100644 --- a/indra/newview/llviewervisualparam.h +++ b/indra/newview/llviewervisualparam.h @@ -90,7 +90,7 @@ public: virtual const LLVector3* getNextDistortion(U32 *index, LLPolyMesh **mesh) = 0; // interface methods - F32 getDisplayOrder() { return getInfo()->mEditGroupDisplayOrder; } + F32 getDisplayOrder() const { return getInfo()->mEditGroupDisplayOrder; } S32 getWearableType() const { return getInfo()->mWearableType; } const std::string& getEditGroup() const { return getInfo()->mEditGroup; } diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index cbda0e8a64..461f7fc1c7 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -36,9 +36,12 @@ #include #include #include +#include +#include "llfloaterreg.h" #include "llpanellogin.h" #include "llviewerkeyboard.h" +#include "llviewermenu.h" #include "llviewerwindow.h" #include "llviewquery.h" @@ -48,15 +51,15 @@ #include "llvoiceclient.h" // for push-to-talk button handling - // // TODO: Many of these includes are unnecessary. Remove them. // // linden library includes -#include "audioengine.h" // mute on minimize +#include "llaudioengine.h" // mute on minimize #include "indra_constants.h" #include "llassetstorage.h" +#include "llerrorcontrol.h" #include "llfontgl.h" #include "llmousehandler.h" #include "llrect.h" @@ -76,7 +79,6 @@ #include "llagent.h" #include "llalertdialog.h" #include "llbox.h" -#include "llchatbar.h" #include "llconsole.h" #include "llviewercontrol.h" #include "llcylinder.h" @@ -91,23 +93,22 @@ #include "llfeaturemanager.h" #include "llfilepicker.h" #include "llfloater.h" -#include "llfloateractivespeakers.h" #include "llfloaterbuildoptions.h" #include "llfloaterbuyland.h" #include "llfloatercamera.h" #include "llfloaterchat.h" #include "llfloaterchatterbox.h" #include "llfloatercustomize.h" -#include "llfloatereditui.h" // HACK JAMESDEBUG for ui editor #include "llfloaterland.h" #include "llfloaterinspect.h" +#include "llfloatermap.h" #include "llfloaternamedesc.h" #include "llfloaterpreference.h" #include "llfloatersnapshot.h" #include "llfloatertools.h" #include "llfloaterworldmap.h" #include "llfocusmgr.h" -#include "llframestatview.h" +#include "llfontfreetype.h" #include "llgesturemgr.h" #include "llglheaders.h" #include "llhoverview.h" @@ -115,20 +116,21 @@ #include "llhudview.h" #include "llimagebmp.h" #include "llimagej2c.h" -#include "llinventoryview.h" #include "llkeyboard.h" #include "lllineeditor.h" #include "llmenugl.h" #include "llmodaldialog.h" #include "llmorphview.h" #include "llmoveview.h" +#include "llnavigationbar.h" #include "llnotify.h" #include "lloverlaybar.h" #include "llpreviewtexture.h" #include "llprogressview.h" #include "llresmgr.h" -#include "llrootview.h" +#include "llsidetray.h" #include "llselectmgr.h" +#include "llrootview.h" #include "llrendersphere.h" #include "llstartup.h" #include "llstatusbar.h" @@ -151,18 +153,19 @@ #include "lltoolmgr.h" #include "lltoolmorph.h" #include "lltoolpie.h" -#include "lltoolplacer.h" #include "lltoolselectland.h" -#include "lltoolview.h" +#include "lltrans.h" #include "lluictrlfactory.h" #include "lluploaddialog.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llvieweraudio.h" #include "llviewercamera.h" #include "llviewergesture.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerinventory.h" #include "llviewerkeyboard.h" +#include "llviewermedia.h" +#include "llviewermediafocus.h" #include "llviewermenu.h" #include "llviewermessage.h" #include "llviewerobjectlist.h" @@ -170,7 +173,7 @@ #include "llviewerregion.h" #include "llviewershadermgr.h" #include "llviewerstats.h" -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvovolume.h" #include "llworld.h" #include "llworldmapview.h" @@ -182,10 +185,16 @@ #include "llviewerjoystick.h" #include "llviewernetwork.h" #include "llpostprocess.h" +#include "llbottomtray.h" +#include "llnearbychatbar.h" +#include "llagentui.h" + +#include "llnotificationmanager.h" -#include "llfloatertest.h" // HACK! #include "llfloaternotificationsconsole.h" +#include "llnearbychat.h" + #if LL_WINDOWS #include // For Unicode conversion methods #endif @@ -194,7 +203,6 @@ // Globals // void render_ui(F32 zoom_factor = 1.f, int subfield = 0); -LLBottomPanel* gBottomPanel = NULL; extern BOOL gDebugClicks; extern BOOL gDisplaySwapBuffers; @@ -203,7 +211,6 @@ extern BOOL gResizeScreenTexture; extern S32 gJamesInt; LLViewerWindow *gViewerWindow = NULL; -LLVelocityBar *gVelocityBar = NULL; BOOL gDebugSelect = FALSE; @@ -247,9 +254,27 @@ std::string LLViewerWindow::sSnapshotDir; std::string LLViewerWindow::sMovieBaseName; -extern void toggle_debug_menus(void*); - +class RecordToChatConsole : public LLError::Recorder, public LLSingleton +{ +public: + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + // only log warnings to chat console + if (level == LLError::LEVEL_WARN) + { + LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance("chat"); + if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat")) + { + LLChat chat; + chat.mText = message; + chat.mSourceType = CHAT_SOURCE_SYSTEM; + chat_floater->addChat(chat, FALSE, FALSE); + } + } + } +}; //////////////////////////////////////////////////////////////////////////// // @@ -513,7 +538,7 @@ public: ypos += y_inc; } // only display these messages if we are actually rendering beacons at this moment - if (LLPipeline::getRenderBeacons(NULL) && gSavedSettings.getBOOL("BeaconAlwaysOn")) + if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons")) { if (LLPipeline::getRenderParticleBeacons(NULL)) { @@ -557,7 +582,7 @@ public: const Line& line = *iter; LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor, LLFontGL::LEFT, LLFontGL::TOP, - LLFontGL::NORMAL, S32_MAX, S32_MAX, NULL, FALSE); + LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE); } mLineList.clear(); } @@ -580,11 +605,11 @@ bool LLViewerWindow::shouldShowToolTipFor(LLMouseHandler *mh) { LLMouseHandler::EShowToolTip showlevel = mh->getShowToolTip(); - return ( - showlevel == LLMouseHandler::SHOW_ALWAYS || - (showlevel == LLMouseHandler::SHOW_IF_NOT_BLOCKED && - !mToolTipBlocked) - ); + bool tool_tip_allowed = (showlevel == LLMouseHandler::SHOW_ALWAYS + || (showlevel == LLMouseHandler::SHOW_IF_NOT_BLOCKED + && !mToolTipBlocked)); + + return tool_tip_allowed; } return false; } @@ -912,8 +937,6 @@ void LLViewerWindow::handleFocus(LLWindow *window) gAgent.onAppFocusGained(); LLToolMgr::getInstance()->onAppFocusGained(); - gShowTextEditCursor = TRUE; - // See if we're coming in with modifier keys held down if (gKeyboard) { @@ -943,11 +966,6 @@ void LLViewerWindow::handleFocusLost(LLWindow *window) showCursor(); getWindow()->setMouseClipping(FALSE); - // JC - Leave keyboard focus, so if you're popping in and out editing - // a script, you don't have to click in the editor again and again. - // gFocusMgr.setKeyboardFocus( NULL ); - gShowTextEditCursor = FALSE; - // If losing focus while keys are down, reset them. if (gKeyboard) { @@ -1089,7 +1107,7 @@ BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255))); std::string name_str; - gAgent.getName(name_str); + LLAgentUI::buildName(name_str); std::string temp_str; temp_str = llformat( "%s FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */ @@ -1138,7 +1156,7 @@ void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data) case SLURL_MESSAGE_TYPE: // received URL std::string url = (const char*)data; - LLWebBrowserCtrl* web = NULL; + LLMediaCtrl* web = NULL; const bool trusted_browser = false; if (LLURLDispatcher::dispatch(url, web, trusted_browser)) { @@ -1186,6 +1204,27 @@ void LLViewerWindow::handlePauseWatchdog(LLWindow *window) LLAppViewer::instance()->pauseMainloopTimeout(); } +//virtual +std::string LLViewerWindow::translateString(const char* tag) +{ + return LLTrans::getString( std::string(tag) ); +} + +//virtual +std::string LLViewerWindow::translateString(const char* tag, + const std::map& args) +{ + // LLTrans uses a special subclass of std::string for format maps, + // but we must use std::map<> in these callbacks, otherwise we create + // a dependency between LLWindow and LLFormatMapString. So copy the data. + LLStringUtil::format_map_t args_copy; + std::map::const_iterator it = args.begin(); + for ( ; it != args.end(); ++it) + { + args_copy[it->first] = it->second; + } + return LLTrans::getString( std::string(tag), args_copy); +} // // Classes @@ -1196,11 +1235,13 @@ LLViewerWindow::LLViewerWindow( S32 width, S32 height, BOOL fullscreen, BOOL ignore_pixel_depth) : + mWindow(NULL), mActive(TRUE), mWantFullscreen(fullscreen), mShowFullscreenProgress(FALSE), mWindowRect(0, height, width, 0), mVirtualWindowRect(0, height, width, 0), + mWorldViewRect(0, height, width, 0), mLeftMouseDown(FALSE), mMiddleMouseDown(FALSE), mRightMouseDown(FALSE), @@ -1224,6 +1265,8 @@ LLViewerWindow::LLViewerWindow( LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert); LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert); + LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications")); + llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl; // Default to application directory. LLViewerWindow::sSnapshotBaseName = "Snapshot"; @@ -1231,7 +1274,7 @@ LLViewerWindow::LLViewerWindow( resetSnapshotLoc(); // create window - mWindow = LLWindowManager::createWindow( + mWindow = LLWindowManager::createWindow(this, title, name, x, y, width, height, 0, fullscreen, gNoRender, @@ -1306,26 +1349,31 @@ LLViewerWindow::LLViewerWindow( mInitAlert = "DisplaySettingsNoShaders"; LLFeatureManager::getInstance()->setGraphicsLevel(0, false); gSavedSettings.setU32("RenderQualityPerformance", 0); - } - // set callbacks - mWindow->setCallbacks(this); - // Init the image list. Must happen after GL is initialized and before the images that // LLViewerWindow needs are requested. - gImageList.init(); - LLViewerImage::initClass(); + gTextureList.init(); + LLViewerTextureManager::init() ; gBumpImageList.init(); - + + // Init font system, but don't actually load the fonts yet + // because our window isn't onscreen and they take several + // seconds to parse. + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), + mDisplayScale.mV[VX], + mDisplayScale.mV[VY], + gDirUtilp->getAppRODataDir(), + LLUI::getXUIPaths()); + // Create container for all sub-views - mRootView = new LLRootView("root", mVirtualWindowRect, FALSE); - - if (!gNoRender) - { - // Init default fonts - initFonts(); - } + LLView::Params rvp; + rvp.name("root"); + rvp.rect(mVirtualWindowRect); + rvp.mouse_opaque(false); + rvp.follows.flags(FOLLOWS_NONE); + mRootView = LLUICtrlFactory::create(rvp); + LLUI::setRootView(mRootView); // Make avatar head look forward at start mCurrentMousePoint.mX = getWindowWidth() / 2; @@ -1381,8 +1429,6 @@ void LLViewerWindow::initBase() LLRect full_window(0, height, width, 0); - adjustRectanglesForFirstUse(full_window); - //////////////////// // // Set the gamma @@ -1402,41 +1448,57 @@ void LLViewerWindow::initBase() // Constrain floaters to inside the menu and status bar regions. LLRect floater_view_rect = full_window; - // make space for menu bar if we have one + // make space for menu bar floater_view_rect.mTop -= MENU_BAR_HEIGHT; - // TODO: Eliminate magic constants - please used named constants if changing this - floater_view_rect.mBottom += STATUS_BAR_HEIGHT + 12 + 16 + 2; + LLFloaterView::Params fvparams; + fvparams.name("Floater View"); + fvparams.rect(floater_view_rect); + fvparams.mouse_opaque(false); + fvparams.follows.flags(FOLLOWS_ALL); + fvparams.tab_stop(false); + gFloaterView = LLUICtrlFactory::create (fvparams); - // Check for non-first startup - S32 floater_view_bottom = gSavedSettings.getS32("FloaterViewBottom"); - if (floater_view_bottom >= 0) - { - floater_view_rect.mBottom = floater_view_bottom; - } - gFloaterView = new LLFloaterView("Floater View", floater_view_rect ); - gFloaterView->setVisible(TRUE); - - gSnapshotFloaterView = new LLSnapshotFloaterView("Snapshot Floater View", full_window); + LLSnapshotFloaterView::Params snapParams; + snapParams.name("Snapshot Floater View"); + snapParams.rect(full_window); + snapParams.enabled(false); + gSnapshotFloaterView = LLUICtrlFactory::create (snapParams); + // Snapshot floater must start invisible otherwise it eats all // the tooltips. JC gSnapshotFloaterView->setVisible(FALSE); // Console llassert( !gConsole ); - gConsole = new LLConsole( - "console", - gSavedSettings.getS32("ConsoleBufferSize"), - getChatConsoleRect(), - gSavedSettings.getS32("ChatFontSize"), - gSavedSettings.getF32("ChatPersistTime") ); - gConsole->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + LLConsole::Params cp; + cp.name("console"); + cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize")); + cp.rect(getChatConsoleRect()); + cp.persist_time(gSavedSettings.getF32("ChatPersistTime")); + cp.font_size_index(gSavedSettings.getS32("ChatFontSize")); + cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM); + gConsole = LLUICtrlFactory::create(cp); mRootView->addChild(gConsole); + // optionally forward warnings to chat console/chat floater + // for qa runs and dev builds +#if !LL_RELEASE_FOR_DOWNLOAD + LLError::addRecorder(RecordToChatConsole::getInstance()); +#else + if(gSavedSettings.getBOOL("QAMode")) + { + LLError::addRecorder(RecordToChatConsole::getInstance()); + } +#endif + // Debug view over the console - gDebugView = new LLDebugView("gDebugView", full_window); - gDebugView->setFollowsAll(); - gDebugView->setVisible(TRUE); + LLDebugView::Params debug_p; + debug_p.name("DebugView"); + debug_p.rect(full_window); + debug_p.follows.flags(FOLLOWS_ALL); + debug_p.visible(true); + gDebugView = LLUICtrlFactory::create(debug_p); mRootView->addChild(gDebugView); // Add floater view at the end so it will be on top, and give it tab priority over others @@ -1444,303 +1506,204 @@ void LLViewerWindow::initBase() mRootView->addChild(gSnapshotFloaterView); // notify above floaters! - LLRect notify_rect = full_window; - //notify_rect.mTop -= 24; - notify_rect.mBottom += STATUS_BAR_HEIGHT; - gNotifyBoxView = new LLNotifyBoxView("notify_container", notify_rect, FALSE, FOLLOWS_ALL); + LLRect notify_rect = floater_view_rect; + LLNotifyBoxView::Params p; + p.name("notify_container"); + p.rect(notify_rect); + p.mouse_opaque(false); + p.follows.flags(FOLLOWS_ALL); + gNotifyBoxView = LLUICtrlFactory::create (p); mRootView->addChild(gNotifyBoxView, -2); // Tooltips go above floaters - mToolTip = new LLTextBox( std::string("tool tip"), LLRect(0, 1, 1, 0 ) ); - mToolTip->setHPad( 4 ); - mToolTip->setVPad( 2 ); - mToolTip->setColor( gColors.getColor( "ToolTipTextColor" ) ); - mToolTip->setBorderColor( gColors.getColor( "ToolTipBorderColor" ) ); - mToolTip->setBorderVisible( FALSE ); - mToolTip->setBackgroundColor( gColors.getColor( "ToolTipBgColor" ) ); - mToolTip->setBackgroundVisible( TRUE ); - mToolTip->setFontStyle(LLFontGL::NORMAL); - mToolTip->setBorderDropshadowVisible( TRUE ); - mToolTip->setVisible( FALSE ); + LLTextBox::Params params; + params.text("tool tip"); + params.name(params.text); + params.rect(LLRect (0, 1, 1, 0)); + params.h_pad(4); + params.v_pad(2); + params.text_color(LLUIColorTable::instance().getColor( "ToolTipTextColor" )); + params.border_color(LLUIColorTable::instance().getColor( "ToolTipBorderColor" )); + params.border_visible(false); + params.background_color(LLUIColorTable::instance().getColor( "ToolTipBgColor" )); + params.bg_visible(true); + params.font.style("NORMAL"); + params.border_drop_shadow_visible(true); + params.visible(false); + mToolTip = LLUICtrlFactory::create (params); // Add the progress bar view (startup view), which overrides everything - mProgressView = new LLProgressView(std::string("ProgressView"), full_window); + mProgressView = new LLProgressView(full_window); mRootView->addChild(mProgressView); setShowProgress(FALSE); setProgressCancelButtonVisible(FALSE); } - -void adjust_rect_top_left(const std::string& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setLeftTopAndSize(0, window.getHeight(), r.getWidth(), r.getHeight()); - gSavedSettings.setRect(control, r); - } -} - -void adjust_rect_top_center(const std::string& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setLeftTopAndSize( window.getWidth()/2 - r.getWidth()/2, - window.getHeight(), - r.getWidth(), - r.getHeight() ); - gSavedSettings.setRect(control, r); - } -} - -void adjust_rect_top_right(const std::string& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setLeftTopAndSize(window.getWidth() - r.getWidth(), - window.getHeight(), - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect(control, r); - } -} - -// *TODO: Adjust based on XUI XML -const S32 TOOLBAR_HEIGHT = 64; - -void adjust_rect_bottom_left(const std::string& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setOriginAndSize(0, TOOLBAR_HEIGHT, r.getWidth(), r.getHeight()); - gSavedSettings.setRect(control, r); - } -} - -void adjust_rect_bottom_center(const std::string& control, const LLRect& window) -{ - LLRect r = gSavedSettings.getRect(control); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setOriginAndSize( - window.getWidth()/2 - r.getWidth()/2, - TOOLBAR_HEIGHT, - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect(control, r); - } -} - -void adjust_rect_centered_partial_zoom(const std::string& control, - const LLRect& window) -{ - LLRect rect = gSavedSettings.getRect(control); - // Only adjust on first use - if (rect.mLeft == 0 && rect.mBottom == 0) - { - S32 width = window.getWidth(); - S32 height = window.getHeight(); - rect.set(0, height-STATUS_BAR_HEIGHT, width, TOOL_BAR_HEIGHT); - // Make floater fill 80% of window, leaving 20% padding on - // the sides. - const F32 ZOOM_FRACTION = 0.8f; - S32 dx = (S32)(width * (1.f - ZOOM_FRACTION)); - S32 dy = (S32)(height * (1.f - ZOOM_FRACTION)); - rect.stretch(-dx/2, -dy/2); - gSavedSettings.setRect(control, rect); - } -} - - -// Many rectangles can't be placed until we know the screen size. -// These rectangles have their bottom-left corner as 0,0 -void LLViewerWindow::adjustRectanglesForFirstUse(const LLRect& window) -{ - LLRect r; - - // *NOTE: The width and height of these floaters must be - // identical in settings.xml and their relevant floater.xml - // files, otherwise the window construction will get - // confused. JC - adjust_rect_bottom_center("FloaterMoveRect2", window); - - adjust_rect_top_center("FloaterCameraRect3", window); - - adjust_rect_top_left("FloaterCustomizeAppearanceRect", window); - - adjust_rect_top_left("FloaterLandRect5", window); - - adjust_rect_top_left("FloaterFindRect2", window); - - adjust_rect_top_left("FloaterGestureRect2", window); - - adjust_rect_top_right("FloaterMiniMapRect", window); - - adjust_rect_top_right("FloaterLagMeter", window); - - adjust_rect_top_left("FloaterBuildOptionsRect", window); - - adjust_rect_bottom_left("FloaterActiveSpeakersRect", window); - - adjust_rect_bottom_left("FloaterBumpRect", window); - - adjust_rect_bottom_left("FloaterRegionInfo", window); - - adjust_rect_bottom_left("FloaterEnvRect", window); - - adjust_rect_bottom_left("FloaterAdvancedSkyRect", window); - - adjust_rect_bottom_left("FloaterAdvancedWaterRect", window); - - adjust_rect_bottom_left("FloaterDayCycleRect", window); - - adjust_rect_top_right("FloaterStatisticsRect", window); - - - // bottom-right - r = gSavedSettings.getRect("FloaterInventoryRect"); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setOriginAndSize( - window.getWidth() - r.getWidth(), - 0, - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect("FloaterInventoryRect", r); - } - -// adjust_rect_top_left("FloaterHUDRect2", window); - - // slightly off center to be left of the avatar. - r = gSavedSettings.getRect("FloaterHUDRect2"); - if (r.mLeft == 0 && r.mBottom == 0) - { - r.setOriginAndSize( - window.getWidth()/4 - r.getWidth()/2, - 2*window.getHeight()/3 - r.getHeight()/2, - r.getWidth(), - r.getHeight()); - gSavedSettings.setRect("FloaterHUDRect2", r); - } -} - -//Rectangles need to be adjusted after the window is constructed -//in order for proper centering to take place -void LLViewerWindow::adjustControlRectanglesForFirstUse(const LLRect& window) -{ - adjust_rect_bottom_center("FloaterMoveRect2", window); - adjust_rect_top_center("FloaterCameraRect3", window); -} - void LLViewerWindow::initWorldUI() { - pre_init_menus(); - S32 height = mRootView->getRect().getHeight(); S32 width = mRootView->getRect().getWidth(); LLRect full_window(0, height, width, 0); - if ( gBottomPanel == NULL ) // Don't re-enter if objects are alreay created + gIMMgr = LLIMMgr::getInstance(); + + // side tray + getRootView()->addChild(LLSideTray::getInstance()); + + getRootView()->sendChildToFront(gFloaterView); + getRootView()->sendChildToFront(gSnapshotFloaterView); + + // new bottom panel + LLRect rc = LLBottomTray::getInstance()->getRect(); + rc.mLeft = 0; + rc.mRight = mRootView->getRect().getWidth(); + LLBottomTray::getInstance()->reshape(rc.getWidth(),rc.getHeight(),FALSE); + LLBottomTray::getInstance()->setRect(rc); + + // View for hover information + LLHoverView::Params hvp; + hvp.name("gHoverview"); + hvp.rect(full_window); + gHoverView = LLUICtrlFactory::create(hvp); + mRootView->addChild(gHoverView); + + // Pre initialize instance communicate instance; + // currently needs to happen before initializing chat or IM + LLFloaterReg::getInstance("communicate"); + + if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) { - // panel containing chatbar, toolbar, and overlay, over floaters - gBottomPanel = new LLBottomPanel(mRootView->getRect()); - mRootView->addChild(gBottomPanel); + LLFloaterChat::loadHistory(); + } - // View for hover information - gHoverView = new LLHoverView(std::string("gHoverView"), full_window); - gHoverView->setVisible(TRUE); - mRootView->addChild(gHoverView); - - gIMMgr = LLIMMgr::getInstance(); + LLRect morph_view_rect = full_window; + morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); + morph_view_rect.mTop = full_window.mTop - 32; + LLMorphView::Params mvp; + mvp.name("MorphView"); + mvp.rect(morph_view_rect); + mvp.visible(false); + gMorphView = LLUICtrlFactory::create(mvp); + mRootView->addChild(gMorphView); - if ( gSavedPerAccountSettings.getBOOL("LogShowHistory") ) + // Make space for nav bar. + LLRect floater_view_rect = gFloaterView->getRect(); + LLRect notify_view_rect = gNotifyBoxView->getRect(); + floater_view_rect.mTop -= NAVIGATION_BAR_HEIGHT; + floater_view_rect.mBottom += LLBottomTray::getInstance()->getRect().getHeight(); + notify_view_rect.mTop -= NAVIGATION_BAR_HEIGHT; + notify_view_rect.mBottom += LLBottomTray::getInstance()->getRect().getHeight(); + gFloaterView->setRect(floater_view_rect); + gNotifyBoxView->setRect(notify_view_rect); + + // *Note: this is where gFloaterMute used to be initialized. + + LLWorldMapView::initClass(); + + // Force gFloaterWorldMap to initialize + LLFloaterReg::getInstance("world_map"); + + // Force gFloaterTools to initialize + LLFloaterReg::getInstance("build"); + LLFloaterReg::hideInstance("build"); + + // Status bar + S32 menu_bar_height = gMenuBarView->getRect().getHeight(); + LLRect root_rect = getRootView()->getRect(); + LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); + gStatusBar = new LLStatusBar(status_rect); + gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); + + gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); + gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); + // sync bg color with menu bar + gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() ); + + // Navigation bar + + LLNavigationBar* navbar = LLNavigationBar::getInstance(); + navbar->reshape(root_rect.getWidth(), navbar->getRect().getHeight(), TRUE); // *TODO: redundant? + navbar->translate(0, root_rect.getHeight() - menu_bar_height - navbar->getRect().getHeight()); // FIXME + navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get()); + + if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel")) + { + navbar->showNavigationPanel(FALSE); + } + + if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel")) + { + navbar->showFavoritesPanel(FALSE); + } + + getRootView()->addChild(gStatusBar); + getRootView()->addChild(navbar); + + + //sidetray + //then notify area + //then menu + //getRootView()->sendChildToFront(LLSideTray::getInstance()); + + getRootView()->sendChildToFront(gNotifyBoxView); + // menu holder appears on top to get first pass at all mouse events + getRootView()->sendChildToFront(gMenuHolder); + + //Channel Manager + LLNotificationsUI::LLChannelManager* channel_manager = LLNotificationsUI::LLChannelManager::getInstance(); + getRootView()->addChild(channel_manager); + //Notification Manager + LLNotificationsUI::LLNotificationManager* notify_manager = LLNotificationsUI::LLNotificationManager::getInstance(); + getRootView()->addChild(notify_manager); + + if ( gHUDView == NULL ) + { + LLRect hud_rect = full_window; + hud_rect.mBottom += 50; + if (gMenuBarView) { - LLFloaterChat::getInstance(LLSD())->loadHistory(); + hud_rect.mTop -= gMenuBarView->getRect().getHeight(); } - - LLRect morph_view_rect = full_window; - morph_view_rect.stretch( -STATUS_BAR_HEIGHT ); - morph_view_rect.mTop = full_window.mTop - 32; - gMorphView = new LLMorphView(std::string("gMorphView"), morph_view_rect ); - mRootView->addChild(gMorphView); - gMorphView->setVisible(FALSE); - - // *Note: this is where gFloaterMute used to be initialized. - - LLWorldMapView::initClass(); - - adjust_rect_centered_partial_zoom("FloaterWorldMapRect2", full_window); - - gFloaterWorldMap = new LLFloaterWorldMap(); - gFloaterWorldMap->setVisible(FALSE); - - // - // Tools for building - // - - // Toolbox floater - init_menus(); - - gFloaterTools = new LLFloaterTools(); - gFloaterTools->setVisible(FALSE); - - // Status bar - S32 menu_bar_height = gMenuBarView->getRect().getHeight(); - LLRect root_rect = getRootView()->getRect(); - LLRect status_rect(0, root_rect.getHeight(), root_rect.getWidth(), root_rect.getHeight() - menu_bar_height); - gStatusBar = new LLStatusBar(std::string("status"), status_rect); - gStatusBar->setFollows(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_TOP); - - gStatusBar->reshape(root_rect.getWidth(), gStatusBar->getRect().getHeight(), TRUE); - gStatusBar->translate(0, root_rect.getHeight() - gStatusBar->getRect().getHeight()); - // sync bg color with menu bar - gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor() ); - - LLFloaterChatterBox::createInstance(LLSD()); - - getRootView()->addChild(gStatusBar); - - // menu holder appears on top to get first pass at all mouse events - getRootView()->sendChildToFront(gMenuHolder); + gHUDView = new LLHUDView(hud_rect); + // put behind everything else in the UI + getRootView()->addChildInBack(gHUDView); } } // Destroy the UI void LLViewerWindow::shutdownViews() { + // clean up warning logger + LLError::removeRecorder(RecordToChatConsole::getInstance()); + delete mDebugText; mDebugText = NULL; - gSavedSettings.setS32("FloaterViewBottom", gFloaterView->getRect().mBottom); - // Cleanup global views if (gMorphView) { gMorphView->setVisible(FALSE); } + // Delete Tool Tip + delete mToolTip; + mToolTip = NULL; + // Delete all child views. delete mRootView; mRootView = NULL; // Automatically deleted as children of mRootView. Fix the globals. - gFloaterTools = NULL; gStatusBar = NULL; gIMMgr = NULL; gHoverView = NULL; - gFloaterView = NULL; - gMorphView = NULL; + gFloaterView = NULL; + gMorphView = NULL; gHUDView = NULL; gNotifyBoxView = NULL; - - delete mToolTip; - mToolTip = NULL; } void LLViewerWindow::shutdownGL() @@ -1755,7 +1718,7 @@ void LLViewerWindow::shutdownGL() gSky.cleanup(); stop_glerror(); - gImageList.shutdown(); + gTextureList.shutdown(); stop_glerror(); gBumpImageList.shutdown(); @@ -1767,7 +1730,7 @@ void LLViewerWindow::shutdownGL() gPipeline.cleanup(); stop_glerror(); - LLViewerImage::cleanupClass(); + LLViewerTextureManager::cleanup() ; llinfos << "Cleaning up select manager" << llendl; LLSelectMgr::getInstance()->cleanup(); @@ -1829,8 +1792,8 @@ void LLViewerWindow::sendShapeToSim() msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode); msg->nextBlockFast(_PREHASH_HeightWidthBlock); msg->addU32Fast(_PREHASH_GenCounter, 0); - U16 height16 = (U16) mWindowRect.getHeight(); - U16 width16 = (U16) mWindowRect.getWidth(); + U16 height16 = (U16) mWorldViewRect.getHeight(); + U16 width16 = (U16) mWorldViewRect.getWidth(); msg->addU16Fast(_PREHASH_Height, height16); msg->addU16Fast(_PREHASH_Width, width16); gAgent.sendReliableMessage(); @@ -1851,25 +1814,18 @@ void LLViewerWindow::reshape(S32 width, S32 height) return; } - glViewport(0, 0, width, height ); - - if (height > 0) - { - LLViewerCamera::getInstance()->setViewHeightInPixels( height ); - if (mWindow->getFullscreen()) - { - // force to 4:3 aspect for odd resolutions - LLViewerCamera::getInstance()->setAspect( getDisplayAspectRatio() ); - } - else - { - LLViewerCamera::getInstance()->setAspect( width / (F32) height); - } - } - // update our window rectangle mWindowRect.mRight = mWindowRect.mLeft + width; mWindowRect.mTop = mWindowRect.mBottom + height; + + //glViewport(0, 0, width, height ); + + if (height > 0) + { + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRect.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); + } + calcDisplayScale(); BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor; @@ -1879,7 +1835,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) mVirtualWindowRect.mRight = mVirtualWindowRect.mLeft + llround((F32)width / mDisplayScale.mV[VX]); mVirtualWindowRect.mTop = mVirtualWindowRect.mBottom + llround((F32)height / mDisplayScale.mV[VY]); - setupViewport(); + setup2DViewport(); // Inform lower views of the change // round up when converting coordinates to make sure there are no gaps at edge of window @@ -1897,7 +1853,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) // store the mode the user wants (even if not there yet) - gSavedSettings.setBOOL("FullScreen", mWantFullscreen); + gSavedSettings.setBOOL("WindowFullScreen", mWantFullscreen); // store new settings for the mode we are in, regardless if (!mWindow->getFullscreen()) @@ -1917,7 +1873,6 @@ void LLViewerWindow::reshape(S32 width, S32 height) LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width); LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height); - gResizeScreenTexture = TRUE; } } @@ -1925,10 +1880,10 @@ void LLViewerWindow::reshape(S32 width, S32 height) // Hide normal UI when a logon fails void LLViewerWindow::setNormalControlsVisible( BOOL visible ) { - if ( gBottomPanel ) + if(LLBottomTray::instanceExists()) { - gBottomPanel->setVisible( visible ); - gBottomPanel->setEnabled( visible ); + LLBottomTray::getInstance()->setVisible(visible); + LLBottomTray::getInstance()->setEnabled(visible); } if ( gMenuBarView ) @@ -1946,6 +1901,12 @@ void LLViewerWindow::setNormalControlsVisible( BOOL visible ) gStatusBar->setVisible( visible ); gStatusBar->setEnabled( visible ); } + + LLNavigationBar* navbarp = LLUI::getRootView()->findChild("navigation_bar"); + if (navbarp) + { + navbarp->setVisible( visible ); + } } void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) @@ -1955,19 +1916,19 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) if(god_mode && LLViewerLogin::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuBarGodBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" ); } else if(god_mode && !LLViewerLogin::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuNonProductionGodBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" ); } else if(!god_mode && !LLViewerLogin::getInstance()->isInProductionGrid()) { - new_bg_color = gColors.getColor( "MenuNonProductionBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" ); } else { - new_bg_color = gColors.getColor( "MenuBarBgColor" ); + new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" ); } if(gMenuBarView) @@ -1978,6 +1939,7 @@ void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid) if(gStatusBar) { gStatusBar->setBackgroundColor( new_bg_color ); + gStatusBar->getChild("HealthText")->setBackgroundColor(new_bg_color); } } @@ -2021,7 +1983,7 @@ void LLViewerWindow::draw() glLoadIdentity(); microsecondsToTimecodeString(gFrameTime,text); - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); + const LLFontGL* font = LLFontGL::getFontSansSerif(); font->renderUTF8(text, 0, llround((getWindowWidth()/2)-100.f), llround((getWindowHeight()-60.f)), @@ -2067,6 +2029,11 @@ void LLViewerWindow::draw() // No translation needed, this view is glued to 0,0 mRootView->draw(); + if (mToolTip->getVisible() && LLView::sDebugRects) + { + gl_rect_2d(mToolTipStickyRect, LLColor4::white, false); + } + // Draw optional on-top-of-everyone view LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); if (top_ctrl && top_ctrl->getVisible()) @@ -2126,6 +2093,9 @@ void LLViewerWindow::draw() #if LL_DEBUG LLView::sIsDrawing = FALSE; #endif + + // UI post-draw Updates + gNotifyBoxView->updateNotifyBoxView(); } // Takes a single keydown event, usually when UI is visible @@ -2140,18 +2110,18 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) if (key < 0x80) { // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first. - return gFocusMgr.childHasKeyboardFocus(mRootView); + return (gFocusMgr.getKeyboardFocus() != NULL); } } - // HACK look for UI editing keys - if (LLView::sEditingUI) - { - if (LLFloaterEditUI::processKeystroke(key, mask)) - { - return TRUE; - } - } + //// HACK look for UI editing keys + //if (LLView::sEditingUI) + //{ + // if (LLFloaterEditUI::processKeystroke(key, mask)) + // { + // return TRUE; + // } + //} // Hide tooltips on keypress mToolTipBlocked = TRUE; // block until next time mouse is moved @@ -2193,7 +2163,8 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) && (MASK_CONTROL & mask) && ('5' == key)) { - LLFloaterNotificationConsole::showInstance(); + //LLFloaterNotificationConsole::showInstance(); + LLFloaterReg::showInstance("notifications_console"); return TRUE; } @@ -2222,13 +2193,14 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } // Traverses up the hierarchy - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { + LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL; // arrow keys move avatar while chatting hack - if (gChatBar && gChatBar->inputEditorHasFocus()) + if (chat_editor && chat_editor->hasFocus()) { - if (gChatBar->getCurrentChat().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar")) + if (chat_editor->getText().empty() || gSavedSettings.getBOOL("ArrowKeysMoveAvatar")) { switch(key) { @@ -2269,7 +2241,7 @@ BOOL LLViewerWindow::handleKey(KEY key, MASK mask) } // Try for a new-format gesture - if (gGestureManager.triggerGesture(key, mask)) + if (LLGestureManager::instance().triggerGesture(key, mask)) { return TRUE; } @@ -2356,7 +2328,7 @@ BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask) } // Traverses up the hierarchy - LLView* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); if( keyboard_focus ) { if (keyboard_focus->handleUnicodeChar(uni_char, FALSE)) @@ -2434,8 +2406,8 @@ void LLViewerWindow::handleScrollWheel(S32 clicks) void LLViewerWindow::moveCursorToCenter() { - S32 x = mVirtualWindowRect.getWidth() / 2; - S32 y = mVirtualWindowRect.getHeight() / 2; + S32 x = mWorldViewRect.getWidth() / 2; + S32 y = mWorldViewRect.getHeight() / 2; //on a forced move, all deltas get zeroed out to prevent jumping mCurrentMousePoint.set(x,y); @@ -2445,6 +2417,30 @@ void LLViewerWindow::moveCursorToCenter() LLUI::setCursorPositionScreen(x, y); } +void LLViewerWindow::updateBottomTrayRect() +{ + if(LLBottomTray::instanceExists() && LLSideTray::instanceCreated()) + { + S32 side_tray_width = 0; + if(LLSideTray::getInstance()->getVisible()) + { + side_tray_width = LLSideTray::getInstance()->getTrayWidth(); + } + + LLBottomTray* bottom_tray = LLBottomTray::getInstance(); + S32 right = llround((F32)mWindowRect.mRight / mDisplayScale.mV[VX]) - side_tray_width; + + LLRect rc = bottom_tray->getRect(); + if (right != rc.mRight) + { + rc.mRight = right; + bottom_tray->reshape(rc.getWidth(), rc.getHeight(), FALSE); + bottom_tray->setRect(rc); + mOnBottomTrayWidthChanged(); + } + } +} + ////////////////////////////////////////////////////////////////////// // // Hover handlers @@ -2452,103 +2448,141 @@ void LLViewerWindow::moveCursorToCenter() // Update UI based on stored mouse position from mouse-move // event processing. -BOOL LLViewerWindow::handlePerFrameHover() +void LLViewerWindow::updateUI() { static std::string last_handle_msg; + updateWorldViewRect(); + + //updateBottomTrayRect(); + LLView::sMouseHandlerMessage.clear(); S32 x = mCurrentMousePoint.mX; S32 y = mCurrentMousePoint.mY; MASK mask = gKeyboard->currentMask(TRUE); - //RN: fix for asynchronous notification of mouse leaving window not working - LLCoordWindow mouse_pos; - mWindow->getCursorPosition(&mouse_pos); - if (mouse_pos.mX < 0 || - mouse_pos.mY < 0 || - mouse_pos.mX > mWindowRect.getWidth() || - mouse_pos.mY > mWindowRect.getHeight()) - { - mMouseInWindow = FALSE; - } - else - { - mMouseInWindow = TRUE; - } - - - S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); - S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); - - LLVector2 mouse_vel; - - if (gSavedSettings.getBOOL("MouseSmooth")) - { - static F32 fdx = 0.f; - static F32 fdy = 0.f; - - F32 amount = 16.f; - fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); - fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); - - mCurrentMouseDelta.set(llround(fdx), llround(fdy)); - mouse_vel.setVec(fdx,fdy); - } - else - { - mCurrentMouseDelta.set(dx, dy); - mouse_vel.setVec((F32) dx, (F32) dy); - } - - mMouseVelocityStat.addValue(mouse_vel.magVec()); - if (gNoRender) { - return TRUE; + return; } - // clean up current focus - LLUICtrl* cur_focus = gFocusMgr.getKeyboardFocus(); - if (cur_focus) - { - if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) - { - gFocusMgr.releaseFocusIfNeeded(cur_focus); - - LLUICtrl* parent = cur_focus->getParentUICtrl(); - const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); - while(parent) - { - if (parent->isCtrl() && - (parent->hasTabStop() || parent == focus_root) && - !parent->getIsChrome() && - parent->isInVisibleChain() && - parent->isInEnabledChain()) - { - if (!parent->focusFirstItem()) - { - parent->setFocus(TRUE); - } - break; - } - parent = parent->getParentUICtrl(); - } - } - else if (cur_focus->isFocusRoot()) - { - // focus roots keep trying to delegate focus to their first valid descendant - // this assumes that focus roots are not valid focus holders on their own - cur_focus->focusFirstItem(); - } - } + updateMouseDelta(); + updateKeyboardFocus(); BOOL handled = FALSE; BOOL handled_by_top_ctrl = FALSE; LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl(); - LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture(); + + //build set of views containing mouse cursor by traversing UI hierarchy and testing + //screen rect against mouse cursor + view_handle_set_t mouse_hover_set; + + // start at current mouse captor (if is a view) or UI root + LLView* root_view = NULL; + root_view = dynamic_cast(mouse_captor); + if (!root_view) + { + root_view = mRootView; + } + + // aggregate visible views that contain mouse cursor in display order + + // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events + if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y)) + { + // iterator over contents of top_ctrl, and throw into mouse_hover_set + for (LLView::tree_iterator_t it = top_ctrl->beginTree(); + it != top_ctrl->endTree(); + ++it) + { + LLView* viewp = *it; + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) + { + // we have a view that contains the mouse, add it to the set + mouse_hover_set.insert(viewp->getHandle()); + } + else + { + // skip this view and all of its children + it.skipDescendants(); + } + } + } + else + { + // walk UI tree in depth-first order + LLView::tree_iterator_t end_it; + for (LLView::tree_iterator_t it = root_view->beginTree(); + it != end_it; + ++it) + { + LLView* viewp = *it; + // calculating the screen rect involves traversing the parent, so this is less than optimal + if (viewp->getVisible() + && viewp->calcScreenBoundingRect().pointInRect(x, y)) + { + + // if this view is mouse opaque, nothing behind it should be in mouse_hover_set + if (viewp->getMouseOpaque()) + { + // constrain further iteration to children of this widget + it = viewp->beginTree(); + } + + // we have a view that contains the mouse, add it to the set + mouse_hover_set.insert(viewp->getHandle()); + } + else + { + // skip this view and all of its children + it.skipDescendants(); + } + } + } + + typedef std::vector > view_handle_list_t; + + // call onMouseEnter() on all views which contain the mouse cursor but did not before + view_handle_list_t mouse_enter_views; + std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(), + mMouseHoverViews.begin(), mMouseHoverViews.end(), + std::back_inserter(mouse_enter_views)); + for (view_handle_list_t::iterator it = mouse_enter_views.begin(); + it != mouse_enter_views.end(); + ++it) + { + LLView* viewp = it->get(); + if (viewp) + { + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); + } + } + + // call onMouseLeave() on all views which no longer contain the mouse cursor + view_handle_list_t mouse_leave_views; + std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(), + mouse_hover_set.begin(), mouse_hover_set.end(), + std::back_inserter(mouse_leave_views)); + for (view_handle_list_t::iterator it = mouse_leave_views.begin(); + it != mouse_leave_views.end(); + ++it) + { + LLView* viewp = it->get(); + if (viewp) + { + LLRect view_screen_rect = viewp->calcScreenRect(); + viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask); + } + } + + // store resulting hover set for next frame + swap(mMouseHoverViews, mouse_hover_set); + if( mouse_captor ) { // Pass hover events to object capturing mouse events. @@ -2638,167 +2672,297 @@ BOOL LLViewerWindow::handlePerFrameHover() // Show a new tool tip (or update one that is alrady shown) BOOL tool_tip_handled = FALSE; std::string tool_tip_msg; - F32 tooltip_delay = gSavedSettings.getF32( "ToolTipDelay" ); - //HACK: hack for tool-based tooltips which need to pop up more quickly - //Also for show xui names as tooltips debug mode - if ((mouse_captor && !mouse_captor->isView()) || LLUI::sShowXUINames) - { - tooltip_delay = gSavedSettings.getF32( "DragAndDropToolTipDelay" ); - } - if( handled && - gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay && - !mWindow->isCursorHidden() ) + if( handled + && !mWindow->isCursorHidden() + && mToolTip) { LLRect screen_sticky_rect; - LLMouseHandler *mh; + LLMouseHandler *tooltip_source = NULL; S32 local_x, local_y; if (mouse_captor) { mouse_captor->screenPointToLocal(x, y, &local_x, &local_y); - mh = mouse_captor; + tooltip_source = mouse_captor; } else if (handled_by_top_ctrl) { top_ctrl->screenPointToLocal(x, y, &local_x, &local_y); - mh = top_ctrl; + tooltip_source = top_ctrl; } else { local_x = x; local_y = y; - mh = mRootView; + tooltip_source = mRootView; } - BOOL tooltip_vis = FALSE; - if (shouldShowToolTipFor(mh)) + F32 tooltip_delay = gSavedSettings.getF32( "ToolTipDelay" ); + //HACK: hack for tool-based tooltips which need to pop up more quickly + //Also for show xui names as tooltips debug mode + if ((gFocusMgr.getMouseCapture() + && !gFocusMgr.getMouseCapture()->isView()) + || LLUI::sShowXUINames) { - tool_tip_handled = mh->handleToolTip(local_x, local_y, tool_tip_msg, &screen_sticky_rect ); + tooltip_delay = gSavedSettings.getF32( "DragAndDropToolTipDelay" ); + } + + + BOOL tooltip_vis = FALSE; + if (shouldShowToolTipFor(tooltip_source)) + { + tool_tip_handled = tooltip_source->handleToolTip(local_x, local_y, tool_tip_msg, &screen_sticky_rect ); + // if we actually got a tooltip back... if( tool_tip_handled && !tool_tip_msg.empty() ) { - mToolTipStickyRect = screen_sticky_rect; - mToolTip->setWrappedText( tool_tip_msg, 200 ); - mToolTip->reshapeToFitText(); - mToolTip->setOrigin( x, y ); - LLRect virtual_window_rect(0, getWindowHeight(), getWindowWidth(), 0); - mToolTip->translateIntoRect( virtual_window_rect, FALSE ); - tooltip_vis = TRUE; + if (mToolTip->getVisible() // already showing a tooltip + || gMouseIdleTimer.getElapsedTimeF32() > tooltip_delay) // mouse has been still long enough to show the tooltip + { + // if tooltip has changed or mouse has moved outside of "sticky" rectangle... + if (mLastToolTipMessage != tool_tip_msg + || !mToolTipStickyRect.pointInRect(x, y)) + { + //...update "sticky" rect and tooltip position + mToolTipStickyRect = screen_sticky_rect; + mToolTip->setOrigin( x, y ); + } + + // remember this tooltip so we know when it changes + mLastToolTipMessage = tool_tip_msg; + mToolTip->setWrappedText( tool_tip_msg, 200 ); + mToolTip->reshapeToFitText(); + LLRect virtual_window_rect(0, getWindowHeight(), getWindowWidth(), 0); + mToolTip->translateIntoRect( virtual_window_rect, FALSE ); + tooltip_vis = TRUE; + } } } - if (mToolTip) + // HACK: assuming tooltip background is in ToolTipBGColor, perform fade out + LLColor4 bg_color = LLUIColorTable::instance().getColor( "ToolTipBgColor" ); + if (tooltip_vis) { - mToolTip->setVisible( tooltip_vis ); + mToolTipFadeTimer.stop(); + mToolTip->setBackgroundColor(bg_color); } + else + { + if (!mToolTipFadeTimer.getStarted()) + { + mToolTipFadeTimer.start(); + } + F32 tool_tip_fade_time = gSavedSettings.getF32("ToolTipFadeTime"); + bg_color.mV[VALPHA] = clamp_rescale(mToolTipFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, bg_color.mV[VALPHA], 0.f); + mToolTip->setBackgroundColor(bg_color); + } + + // above interpolation of bg_color alpha is guaranteed to reach 0.f exactly + mToolTip->setVisible( bg_color.mV[VALPHA] != 0.f ); } - if (tool && tool != gToolNull && tool != LLToolCompInspect::getInstance() && tool != LLToolDragAndDrop::getInstance() && !gSavedSettings.getBOOL("FreezeTime")) + updateLayout(); + + mLastMousePoint = mCurrentMousePoint; + + // cleanup unused selections when no modal dialogs are open + if (LLModalDialog::activeCount() == 0) + { + LLViewerParcelMgr::getInstance()->deselectUnused(); + } + + if (LLModalDialog::activeCount() == 0) + { + LLSelectMgr::getInstance()->deselectUnused(); + } + + updatePicking(x, y, mask); +} + +void LLViewerWindow::updatePicking(S32 x, S32 y, MASK mask) +{ + // per frame picking - for tooltips and changing cursor over interactive objects + static S32 previous_x = -1; + static S32 previous_y = -1; + static BOOL mouse_moved_since_pick = FALSE; + + if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) + { + gDebugRaycastFaceHit = -1; + gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, + &gDebugRaycastFaceHit, + &gDebugRaycastIntersection, + &gDebugRaycastTexCoord, + &gDebugRaycastNormal, + &gDebugRaycastBinormal); + } + + + if ((previous_x != x) || (previous_y != y)) + mouse_moved_since_pick = TRUE; + + BOOL do_pick = FALSE; + + F32 picks_moving = gSavedSettings.getF32("PicksPerSecondMouseMoving"); + if ((mouse_moved_since_pick) && (picks_moving > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_moving)) + { + do_pick = TRUE; + } + + F32 picks_stationary = gSavedSettings.getF32("PicksPerSecondMouseStationary"); + if ((!mouse_moved_since_pick) && (picks_stationary > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_stationary)) + { + do_pick = TRUE; + } + + if (getCursorHidden()) + { + do_pick = FALSE; + } + + if(LLViewerMediaFocus::getInstance()->getFocus()) + { + // When in-world media is in focus, pick every frame so that browser mouse-overs, dragging scrollbars, etc. work properly. + do_pick = TRUE; + } + + if (do_pick) + { + mouse_moved_since_pick = FALSE; + mPickTimer.reset(); + pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE); + } + + previous_x = x; + previous_y = y; +} + +void LLViewerWindow::updateLayout() +{ + LLTool* tool = LLToolMgr::getInstance()->getCurrentTool(); + if (gFloaterTools != NULL + && tool != NULL + && tool != gToolNull + && tool != LLToolCompInspect::getInstance() + && tool != LLToolDragAndDrop::getInstance() + && !gSavedSettings.getBOOL("FreezeTime")) { LLMouseHandler *captor = gFocusMgr.getMouseCapture(); // With the null, inspect, or drag and drop tool, don't muck // with visibility. - if (gFloaterTools->isMinimized() || - (tool != LLToolPie::getInstance() // not default tool - && tool != LLToolCompGun::getInstance() // not coming out of mouselook - && !mSuppressToolbox // not override in third person - && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode - && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset - && (!captor || captor->isView())) // not dragging - ) + if (gFloaterTools->isMinimized() + || (tool != LLToolPie::getInstance() // not default tool + && tool != LLToolCompGun::getInstance() // not coming out of mouselook + && !mSuppressToolbox // not override in third person + && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode + && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset + && (!captor || captor->isView()))) // not dragging { // Force floater tools to be visible (unless minimized) if (!gFloaterTools->getVisible()) { - gFloaterTools->open(); /* Flawfinder: ignore */ + gFloaterTools->openFloater(); } // Update the location of the blue box tool popup LLCoordGL select_center_screen; - gFloaterTools->updatePopup( select_center_screen, mask ); + gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) ); } else { gFloaterTools->setVisible(FALSE); } - // In the future we may wish to hide the tools menu unless you - // are building. JC - //gMenuBarView->setItemVisible("Tools", gFloaterTools->getVisible()); - //gMenuBarView->arrange(); - } - if (gToolBar) - { - gToolBar->refresh(); + gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible()); } - if (gChatBar) + // Always update console + if(gConsole) { - gChatBar->refresh(); - } - - if (gOverlayBar) - { - gOverlayBar->refresh(); - } - - // Update rectangles for the various toolbars - if (gOverlayBar && gNotifyBoxView && gConsole && gToolBar) - { - LLRect bar_rect(-1, STATUS_BAR_HEIGHT, getWindowWidth()+1, -1); - - LLRect notify_box_rect = gNotifyBoxView->getRect(); - notify_box_rect.mBottom = bar_rect.mBottom; - gNotifyBoxView->reshape(notify_box_rect.getWidth(), notify_box_rect.getHeight()); - gNotifyBoxView->setRect(notify_box_rect); - - // make sure floaters snap to visible rect by adjusting floater view rect - LLRect floater_rect = gFloaterView->getRect(); - if (floater_rect.mBottom != bar_rect.mBottom+1) - { - floater_rect.mBottom = bar_rect.mBottom+1; - // Don't bounce the floaters up and down. - gFloaterView->reshapeFloater(floater_rect.getWidth(), floater_rect.getHeight(), - TRUE, ADJUST_VERTICAL_NO); - gFloaterView->setRect(floater_rect); - } - - // snap floaters to top of chat bar/button strip - LLView* chatbar_and_buttons = gOverlayBar->getChild("chatbar_and_buttons", TRUE); - // find top of chatbar and state buttons, if either are visible - if (chatbar_and_buttons && !chatbar_and_buttons->getLocalBoundingRect().isNull()) - { - // convert top/left corner of chatbar/buttons container to gFloaterView-relative coordinates - S32 top, left; - chatbar_and_buttons->localPointToOtherView( - chatbar_and_buttons->getLocalBoundingRect().mLeft, - chatbar_and_buttons->getLocalBoundingRect().mTop, - &left, - &top, - gFloaterView); - gFloaterView->setSnapOffsetBottom(top); - } - else if (gToolBar->getVisible()) - { - S32 top, left; - gToolBar->localPointToOtherView( - gToolBar->getLocalBoundingRect().mLeft, - gToolBar->getLocalBoundingRect().mTop, - &left, - &top, - gFloaterView); - gFloaterView->setSnapOffsetBottom(top); - } - else - { - gFloaterView->setSnapOffsetBottom(0); - } - - // Always update console LLRect console_rect = getChatConsoleRect(); - console_rect.mBottom = gHUDView->getRect().mBottom + getChatConsoleBottomPad(); gConsole->reshape(console_rect.getWidth(), console_rect.getHeight()); gConsole->setRect(console_rect); } +} - mLastMousePoint = mCurrentMousePoint; +void LLViewerWindow::updateMouseDelta() +{ + S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]); + S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]); + + //RN: fix for asynchronous notification of mouse leaving window not working + LLCoordWindow mouse_pos; + mWindow->getCursorPosition(&mouse_pos); + if (mouse_pos.mX < 0 || + mouse_pos.mY < 0 || + mouse_pos.mX > mWindowRect.getWidth() || + mouse_pos.mY > mWindowRect.getHeight()) + { + mMouseInWindow = FALSE; + } + else + { + mMouseInWindow = TRUE; + } + + LLVector2 mouse_vel; + + if (gSavedSettings.getBOOL("MouseSmooth")) + { + static F32 fdx = 0.f; + static F32 fdy = 0.f; + + F32 amount = 16.f; + fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f); + fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f); + + mCurrentMouseDelta.set(llround(fdx), llround(fdy)); + mouse_vel.setVec(fdx,fdy); + } + else + { + mCurrentMouseDelta.set(dx, dy); + mouse_vel.setVec((F32) dx, (F32) dy); + } + + mMouseVelocityStat.addValue(mouse_vel.magVec()); +} + +void LLViewerWindow::updateKeyboardFocus() +{ + // clean up current focus + LLUICtrl* cur_focus = dynamic_cast(gFocusMgr.getKeyboardFocus()); + if (cur_focus) + { + if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain()) + { + // don't release focus, just reassign so that if being given + // to a sibling won't call onFocusLost on all the ancestors + // gFocusMgr.releaseFocusIfNeeded(cur_focus); + + LLUICtrl* parent = cur_focus->getParentUICtrl(); + const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot(); + while(parent) + { + if (parent->isCtrl() && + (parent->hasTabStop() || parent == focus_root) && + !parent->getIsChrome() && + parent->isInVisibleChain() && + parent->isInEnabledChain()) + { + if (!parent->focusFirstItem()) + { + parent->setFocus(TRUE); + } + break; + } + parent = parent->getParentUICtrl(); + } + } + else if (cur_focus->isFocusRoot()) + { + // focus roots keep trying to delegate focus to their first valid descendant + // this assumes that focus roots are not valid focus holders on their own + cur_focus->focusFirstItem(); + } + } // last ditch force of edit menu to selection manager if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount()) @@ -2832,77 +2996,46 @@ BOOL LLViewerWindow::handlePerFrameHover() gFloaterView->syncFloaterTabOrder(); } - if (gSavedSettings.getBOOL("ChatBarStealsFocus") - && gChatBar - && gFocusMgr.getKeyboardFocus() == NULL - && gChatBar->isInVisibleChain()) - { - gChatBar->startChat(NULL); - } - - // cleanup unused selections when no modal dialogs are open - if (LLModalDialog::activeCount() == 0) - { - LLViewerParcelMgr::getInstance()->deselectUnused(); - } - - if (LLModalDialog::activeCount() == 0) - { - LLSelectMgr::getInstance()->deselectUnused(); - } - - if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST)) - { - gDebugRaycastFaceHit = -1; - gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, - &gDebugRaycastFaceHit, - &gDebugRaycastIntersection, - &gDebugRaycastTexCoord, - &gDebugRaycastNormal, - &gDebugRaycastBinormal); - } - - - // per frame picking - for tooltips and changing cursor over interactive objects - static S32 previous_x = -1; - static S32 previous_y = -1; - static BOOL mouse_moved_since_pick = FALSE; - - if ((previous_x != x) || (previous_y != y)) - mouse_moved_since_pick = TRUE; - - BOOL do_pick = FALSE; - - F32 picks_moving = gSavedSettings.getF32("PicksPerSecondMouseMoving"); - if ((mouse_moved_since_pick) && (picks_moving > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_moving)) - { - do_pick = TRUE; - } - - F32 picks_stationary = gSavedSettings.getF32("PicksPerSecondMouseStationary"); - if ((!mouse_moved_since_pick) && (picks_stationary > 0.0) && (mPickTimer.getElapsedTimeF32() > 1.0f / picks_stationary)) - { - do_pick = TRUE; - } - - if (getCursorHidden()) - { - do_pick = FALSE; - } - - if (do_pick) - { - mouse_moved_since_pick = FALSE; - mPickTimer.reset(); - pickAsync(getCurrentMouseX(), getCurrentMouseY(), mask, hoverPickCallback, TRUE); - } - - previous_x = x; - previous_y = y; - - return handled; + if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this + LLSideTray::getInstance()->highlightFocused(); } +void LLViewerWindow::updateWorldViewRect(bool use_full_window) +{ + if (!LLSideTray::instanceCreated()) return; + + // start off using whole window to render world + LLRect new_world_rect = mWindowRect; + + if (use_full_window == false) + { + // pull in right side of world view based on sidetray + LLSideTray* sidetray = LLSideTray::getInstance(); + if (sidetray->getVisible()) + { + new_world_rect.mRight -= llround((F32)sidetray->getTrayWidth() * mDisplayScale.mV[VX]); + } + + // push top of world view below nav bar + if (LLNavigationBar::getInstance()->getVisible()) + { + LLNavigationBar* barp = LLNavigationBar::getInstance(); + LLRect nav_bar_rect; + if(barp->localRectToOtherView(barp->getLocalRect(), &nav_bar_rect, mRootView)) + { + new_world_rect.mTop = llround((F32)LLNavigationBar::getInstance()->getRect().mBottom * mDisplayScale.mV[VY]); + } + } + } + + if (mWorldViewRect != new_world_rect) + { + mWorldViewRect = new_world_rect; + gResizeScreenTexture = TRUE; + LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRect.getHeight() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); + } +} /* static */ void LLViewerWindow::hoverPickCallback(const LLPickInfo& pick_info) @@ -3164,7 +3297,7 @@ void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback } // push back pick info object - BOOL in_build_mode = gFloaterTools && gFloaterTools->getVisible(); + BOOL in_build_mode = LLFloaterReg::instanceVisible("build"); if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha) { // build mode allows interaction with all transparent objects @@ -3179,10 +3312,10 @@ void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback { mPickScreenRegion.setCenterAndSize(x, y_from_bot, PICK_DIAMETER, PICK_DIAMETER); - if (mPickScreenRegion.mLeft < 0) mPickScreenRegion.translate(-mPickScreenRegion.mLeft, 0); - if (mPickScreenRegion.mBottom < 0) mPickScreenRegion.translate(0, -mPickScreenRegion.mBottom); - if (mPickScreenRegion.mRight > mWindowRect.getWidth() ) mPickScreenRegion.translate(mWindowRect.getWidth() - mPickScreenRegion.mRight, 0); - if (mPickScreenRegion.mTop > mWindowRect.getHeight() ) mPickScreenRegion.translate(0, mWindowRect.getHeight() - mPickScreenRegion.mTop); + if (mPickScreenRegion.mLeft < mWorldViewRect.mLeft) mPickScreenRegion.translate(mWorldViewRect.mLeft - mPickScreenRegion.mLeft, 0); + if (mPickScreenRegion.mBottom < mWorldViewRect.mBottom) mPickScreenRegion.translate(0, mWorldViewRect.mBottom - mPickScreenRegion.mBottom); + if (mPickScreenRegion.mRight > mWorldViewRect.mRight ) mPickScreenRegion.translate(mWorldViewRect.mRight - mPickScreenRegion.mRight, 0); + if (mPickScreenRegion.mTop > mWorldViewRect.mTop ) mPickScreenRegion.translate(0, mWorldViewRect.mTop - mPickScreenRegion.mTop); } // set frame buffer region for picking results @@ -3207,80 +3340,9 @@ void LLViewerWindow::schedulePick(LLPickInfo& pick_info) return; } - llassert_always(pick_info.mScreenRegion.notNull()); + llassert_always(pick_info.mScreenRegion.notEmpty()); mPicks.push_back(pick_info); - /*S32 scaled_x = llround((F32)pick_info.mMousePt.mX * mDisplayScale.mV[VX]); - S32 scaled_y = llround((F32)pick_info.mMousePt.mY * mDisplayScale.mV[VY]); - - // Default to not hitting anything - LLCamera pick_camera; - pick_camera.setOrigin(LLViewerCamera::getInstance()->getOrigin()); - pick_camera.setOriginAndLookAt(LLViewerCamera::getInstance()->getOrigin(), - LLViewerCamera::getInstance()->getUpAxis(), - LLViewerCamera::getInstance()->getOrigin() + mouseDirectionGlobal(pick_info.mMousePt.mX, pick_info.mMousePt.mY)); - pick_camera.setView(0.5f*DEG_TO_RAD); - pick_camera.setNear(LLViewerCamera::getInstance()->getNear()); - pick_camera.setFar(LLViewerCamera::getInstance()->getFar()); - pick_camera.setAspect(1.f); - - // save our drawing state - // *TODO: should we be saving using the new method here using - // glh_get_current_projection/glh_set_current_projection? -brad - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - // clear work area - { - LLGLState scissor_state(GL_SCISSOR_TEST); - scissor_state.enable(); - glScissor(pick_info.mScreenRegion.mLeft, pick_info.mScreenRegion.mBottom, pick_info.mScreenRegion.getWidth(), pick_info.mScreenRegion.getHeight()); - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - //glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - // build perspective transform and picking viewport - // Perform pick on a PICK_DIAMETER x PICK_DIAMETER pixel region around cursor point. - // Don't limit the select distance for this pick. - LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - PICK_HALF_WIDTH, scaled_y - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER, FALSE); - - // render for object picking - - // make viewport big enough to handle antialiased frame buffers - gGLViewport[0] = pick_info.mScreenRegion.mLeft; - gGLViewport[1] = pick_info.mScreenRegion.mBottom; - gGLViewport[2] = pick_info.mScreenRegion.getWidth(); - gGLViewport[3] = pick_info.mScreenRegion.getHeight(); - - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - LLViewerCamera::updateFrustumPlanes(pick_camera); - stop_glerror(); - - // Draw the objects so the user can select them. - // The starting ID is 1, since land is zero. - LLRect pick_region; - pick_region.setOriginAndSize(pick_info.mMousePt.mX - PICK_HALF_WIDTH, - pick_info.mMousePt.mY - PICK_HALF_WIDTH, PICK_DIAMETER, PICK_DIAMETER); - gObjectList.renderObjectsForSelect(pick_camera, pick_region, FALSE, pick_info.mPickTransparent); - - stop_glerror(); - - // restore drawing state - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - setup3DRender(); - setup2DRender(); - setupViewport();*/ - // delay further event processing until we receive results of pick mWindow->delayInputProcessing(); } @@ -3449,16 +3511,16 @@ LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const // find vertical field of view F32 fov = LLViewerCamera::getInstance()->getView(); - // find screen resolution - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + // find world view center in scaled ui coordinates + F32 center_x = (F32)getWorldViewRect().getCenterX() / mDisplayScale.mV[VX]; + F32 center_y = (F32)getWorldViewRect().getCenterY() / mDisplayScale.mV[VY]; // calculate pixel distance to screen - F32 distance = (height / 2.f) / (tan(fov / 2.f)); + F32 distance = ((F32)getWorldViewHeight() / (mDisplayScale.mV[VY] * 2.f)) / (tan(fov / 2.f)); // calculate click point relative to middle of screen - F32 click_x = x - width / 2.f; - F32 click_y = y - height / 2.f; + F32 click_x = x - center_x; + F32 click_y = y - center_y; // compute mouse vector LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis() @@ -3473,12 +3535,15 @@ LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const { // find screen resolution - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + S32 height = llround((F32)getWorldViewHeight() / mDisplayScale.mV[VY]); + + // find world view center + F32 center_x = (F32)getWorldViewRect().getCenterX() / mDisplayScale.mV[VX]; + F32 center_y = (F32)getWorldViewRect().getCenterY() / mDisplayScale.mV[VY]; // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5 - F32 hud_x = -((F32)x - (F32)width/2.f) / height; - F32 hud_y = ((F32)y - (F32)height/2.f) / height; + F32 hud_x = -((F32)x - center_x) / height; + F32 hud_y = ((F32)y - center_y) / height; return LLVector3(0.f, hud_x/gAgent.mHUDCurZoom, hud_y/gAgent.mHUDCurZoom); } @@ -3492,12 +3557,16 @@ LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect(); // find screen resolution - S32 height = getWindowHeight(); - S32 width = getWindowWidth(); + S32 height = llround((F32)getWorldViewHeight() / mDisplayScale.mV[VY]); + S32 width = llround((F32)getWorldViewWidth() / mDisplayScale.mV[VX]); + + // find world view center + F32 center_x = (F32)getWorldViewRect().getCenterX() / mDisplayScale.mV[VX]; + F32 center_y = (F32)getWorldViewRect().getCenterY() / mDisplayScale.mV[VY]; // calculate click point relative to middle of screen - F32 click_x = (((F32)x / (F32)width) - 0.5f) * fov_width * -1.f; - F32 click_y = (((F32)y / (F32)height) - 0.5f) * fov_height; + F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f; + F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height; // compute mouse vector LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f); @@ -3841,7 +3910,6 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p glClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); setup3DRender(); - setupViewport(); LLFontGL::setFontDisplay(FALSE) ; LLHUDText::setDisplayText(FALSE) ; @@ -3902,7 +3970,6 @@ BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 p mDisplayScale.setVec(display_scale) ; mWindowRect = window_rect; setup3DRender(); - setupViewport(); gDisplaySwapBuffers = FALSE; gDepthDirty = TRUE; @@ -3946,6 +4013,9 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei // PRE SNAPSHOT gDisplaySwapBuffers = FALSE; + // if not showing ui, use full window to render world view + updateWorldViewRect(!show_ui); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); setCursor(UI_CURSOR_WAIT); @@ -4070,7 +4140,6 @@ BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei LLViewerCamera::getInstance()->setZoomParameters(scale_factor, subimage_x+(subimage_y*llceil(scale_factor))); setup3DRender(); - setupViewport(); gObjectList.renderPickList(gViewerWindow->getVirtualWindowRect(), FALSE, FALSE); } else @@ -4214,33 +4283,21 @@ void LLViewerWindow::destroyWindow() void LLViewerWindow::drawMouselookInstructions() { - // Draw instructions for mouselook ("Press ESC to leave Mouselook" in a box at the top of the screen.) - const std::string instructions = "Press ESC to leave Mouselook."; - const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF ); - - const S32 INSTRUCTIONS_PAD = 5; - LLRect instructions_rect; - instructions_rect.setLeftTopAndSize( - INSTRUCTIONS_PAD, - getWindowHeight() - INSTRUCTIONS_PAD, - font->getWidth( instructions ) + 2 * INSTRUCTIONS_PAD, - llround(font->getLineHeight() + 2 * INSTRUCTIONS_PAD)); - - { - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.color4f( 0.9f, 0.9f, 0.9f, 1.0f ); - gl_rect_2d( instructions_rect ); - } + // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.) + const std::string instructions = LLTrans::getString("LeaveMouselook"); + const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Huge", LLFontGL::BOLD)); + //to be on top of Bottom bar when it is opened + const S32 INSTRUCTIONS_PAD = 50; + font->renderUTF8( instructions, 0, - instructions_rect.mLeft + INSTRUCTIONS_PAD, - instructions_rect.mTop - INSTRUCTIONS_PAD, - LLColor4( 0.0f, 0.0f, 0.0f, 1.f ), - LLFontGL::LEFT, LLFontGL::TOP); + mWorldViewRect.getCenterX(), + mWorldViewRect.mBottom + INSTRUCTIONS_PAD, + LLColor4( 0.0f, 0.0f, 0.0f, 0.6f ), + LLFontGL::HCENTER, LLFontGL::TOP); } - S32 LLViewerWindow::getWindowHeight() const { return mVirtualWindowRect.getHeight(); @@ -4251,6 +4308,46 @@ S32 LLViewerWindow::getWindowWidth() const return mVirtualWindowRect.getWidth(); } +void* LLViewerWindow::getPlatformWindow() const +{ + return mWindow->getPlatformWindow(); +} + +void* LLViewerWindow::getMediaWindow() const +{ + return mWindow->getMediaWindow(); +} + +void LLViewerWindow::focusClient() const +{ + return mWindow->focusClient(); +} + +LLRootView* LLViewerWindow::getRootView() const +{ + return mRootView; +} + +LLRect LLViewerWindow::getVirtualWorldViewRect() const +{ + LLRect world_view_rect = mWorldViewRect; + world_view_rect.mLeft = llround((F32)world_view_rect.mLeft / mDisplayScale.mV[VX]); + world_view_rect.mRight = llround((F32)world_view_rect.mRight / mDisplayScale.mV[VX]); + world_view_rect.mBottom = llround((F32)world_view_rect.mBottom / mDisplayScale.mV[VY]); + world_view_rect.mTop = llround((F32)world_view_rect.mTop / mDisplayScale.mV[VY]); + return world_view_rect; +} + +S32 LLViewerWindow::getWorldViewHeight() const +{ + return mWorldViewRect.getHeight(); +} + +S32 LLViewerWindow::getWorldViewWidth() const +{ + return mWorldViewRect.getWidth(); +} + S32 LLViewerWindow::getWindowDisplayHeight() const { return mWindowRect.getHeight(); @@ -4261,27 +4358,48 @@ S32 LLViewerWindow::getWindowDisplayWidth() const return mWindowRect.getWidth(); } -void LLViewerWindow::setupViewport(S32 x_offset, S32 y_offset) +void LLViewerWindow::setup2DRender() { - gGLViewport[0] = x_offset; - gGLViewport[1] = y_offset; + // setup ortho camera + gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight()); + setup2DViewport(); +} + +void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset) +{ + gGLViewport[0] = mWindowRect.mLeft + x_offset; + gGLViewport[1] = mWindowRect.mBottom + y_offset; gGLViewport[2] = mWindowRect.getWidth(); gGLViewport[3] = mWindowRect.getHeight(); glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); } + void LLViewerWindow::setup3DRender() { - LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, 0, 0, mWindowRect.getWidth(), mWindowRect.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f); + // setup perspective camera + LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRect.mLeft, mWorldViewRect.mBottom, mWorldViewRect.getWidth(), mWorldViewRect.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f); + setup3DViewport(); } -void LLViewerWindow::setup2DRender() +void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset) { - gl_state_for_2d(mWindowRect.getWidth(), mWindowRect.getHeight()); + if (LLRenderTarget::getCurrentBoundTarget() != NULL) + { + // don't use translation component of mWorldViewRect, as we are already in a properly sized render target + gGLViewport[0] = x_offset; + gGLViewport[1] = y_offset; + } + else + { + gGLViewport[0] = mWorldViewRect.mLeft + x_offset; + gGLViewport[1] = mWorldViewRect.mBottom + y_offset; + } + gGLViewport[2] = mWorldViewRect.getWidth(); + gGLViewport[3] = mWorldViewRect.getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); } - - void LLViewerWindow::setShowProgress(const BOOL show) { if (mProgressView) @@ -4295,7 +4413,6 @@ BOOL LLViewerWindow::getShowProgress() const return (mProgressView && mProgressView->getVisible()); } - void LLViewerWindow::moveProgressViewToFront() { if( mProgressView && mRootView ) @@ -4356,7 +4473,7 @@ void LLViewerWindow::stopGL(BOOL save_state) //Note: --bao //if not necessary, do not change the order of the function calls in this function. //if change something, make sure it will not break anything. - //especially be careful to put anything behind gImageList.destroyGL(save_state); + //especially be careful to put anything behind gTextureList.destroyGL(save_state); if (!gGLManager.mIsDisabled) { llinfos << "Shutting down GL..." << llendl; @@ -4381,7 +4498,7 @@ void LLViewerWindow::stopGL(BOOL save_state) LLVOAvatar::destroyGL(); stop_glerror(); - LLDynamicTexture::destroyGL(); + LLViewerDynamicTexture::destroyGL(); stop_glerror(); if (gPipeline.isInit()) @@ -4399,9 +4516,9 @@ void LLViewerWindow::stopGL(BOOL save_state) gPostProcess->invalidate(); } - gImageList.destroyGL(save_state); + gTextureList.destroyGL(save_state); stop_glerror(); - + gGLManager.mIsDisabled = TRUE; stop_glerror(); @@ -4414,7 +4531,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) //Note: --bao //if not necessary, do not change the order of the function calls in this function. //if change something, make sure it will not break anything. - //especially, be careful to put something before gImageList.restoreGL(); + //especially, be careful to put something before gTextureList.restoreGL(); if (gGLManager.mIsDisabled) { llinfos << "Restoring GL..." << llendl; @@ -4422,8 +4539,9 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) initGLDefaults(); LLGLState::restoreGL(); - gImageList.restoreGL(); - + + gTextureList.restoreGL(); + // for future support of non-square pixels, and fonts that are properly stretched //LLFontGL::destroyDefaultFonts(); initFonts(); @@ -4434,7 +4552,7 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) LLManipTranslate::restoreGL(); gBumpImageList.restoreGL(); - LLDynamicTexture::restoreGL(); + LLViewerDynamicTexture::restoreGL(); LLVOAvatar::restoreGL(); gResizeScreenTexture = TRUE; @@ -4463,12 +4581,16 @@ void LLViewerWindow::restoreGL(const std::string& progress_message) void LLViewerWindow::initFonts(F32 zoom_factor) { LLFontGL::destroyAllGL(); - LLFontGL::initDefaultFonts( gSavedSettings.getF32("FontScreenDPI"), + // Initialize with possibly different zoom factor + LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"), mDisplayScale.mV[VX] * zoom_factor, mDisplayScale.mV[VY] * zoom_factor, gDirUtilp->getAppRODataDir(), - LLUICtrlFactory::getXUIPaths()); + LLUI::getXUIPaths()); + // Force font reloads, which can be very slow + LLFontGL::loadDefaultFonts(); } + void LLViewerWindow::toggleFullscreen(BOOL show_progress) { if (mWindow) @@ -4501,6 +4623,11 @@ void LLViewerWindow::getTargetWindow(BOOL& fullscreen, S32& width, S32& height) } } +void LLViewerWindow::requestResolutionUpdate() +{ + mResDirty = true; +} + void LLViewerWindow::requestResolutionUpdate(bool fullscreen_checked) { mResDirty = true; @@ -4534,7 +4661,7 @@ BOOL LLViewerWindow::checkSettings() // force aspect ratio if (mIsFullscreenChecked) { - LLViewerCamera::getInstance()->setAspect( getDisplayAspectRatio() ); + LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() ); } mResDirty = false; @@ -4605,9 +4732,9 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized"); mWantFullscreen = fullscreen; mShowFullscreenProgress = show_progress_bar; - gSavedSettings.setBOOL("FullScreen", mWantFullscreen); + gSavedSettings.setBOOL("WindowFullScreen", mWantFullscreen); - gResizeScreenTexture = TRUE; + //gResizeScreenTexture = TRUE; BOOL old_fullscreen = mWindow->getFullscreen(); if (!old_fullscreen && fullscreen && !LLStartUp::canGoFullscreen()) @@ -4635,12 +4762,12 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, } // Close floaters that don't handle settings change - LLFloaterSnapshot::hide(0); + LLFloaterReg::hideInstance("snapshot"); BOOL result_first_try = FALSE; BOOL result_second_try = FALSE; - LLUICtrl* keyboard_focus = gFocusMgr.getKeyboardFocus(); + LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus(); send_agent_pause(); llinfos << "Stopping GL during changeDisplaySettings" << llendl; stopGL(); @@ -4753,6 +4880,21 @@ F32 LLViewerWindow::getDisplayAspectRatio() const } +F32 LLViewerWindow::getWorldViewAspectRatio() const +{ + F32 world_aspect = (F32)mWorldViewRect.getWidth() / (F32)mWorldViewRect.getHeight(); + //F32 window_aspect = (F32)mWindowRect.getWidth() / (F32)mWindowRect.getHeight(); + if (mWindow->getFullscreen()) + { + return world_aspect * mWindow->getPixelAspectRatio(); + } + else + { + llinfos << "World aspect ratio: " << world_aspect << llendl; + return world_aspect; + } +} + void LLViewerWindow::drawPickBuffer() const { mHoverPick.drawPickBuffer(); @@ -4798,8 +4940,9 @@ void LLViewerWindow::calcDisplayScale() S32 LLViewerWindow::getChatConsoleBottomPad() { S32 offset = 0; - if( gToolBar && gToolBar->getVisible() ) - offset += TOOL_BAR_HEIGHT; + + if(LLBottomTray::instanceExists()) + offset += LLBottomTray::getInstance()->getRect().getHeight(); return offset; } @@ -4818,7 +4961,9 @@ LLRect LLViewerWindow::getChatConsoleRect() console_rect.mLeft += CONSOLE_PADDING_LEFT; - if (gSavedSettings.getBOOL("ChatFullWidth")) + static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth"); + + if (CHAT_FULL_WIDTH) { console_rect.mRight -= CONSOLE_PADDING_RIGHT; } @@ -4857,63 +5002,6 @@ bool LLViewerWindow::onAlert(const LLSD& notify) } //////////////////////////////////////////////////////////////////////////// - -LLBottomPanel::LLBottomPanel(const LLRect &rect) : - LLPanel(LLStringUtil::null, rect, FALSE), - mIndicator(NULL) -{ - // bottom panel is focus root, so Tab moves through the toolbar and button bar, and overlay - setFocusRoot(TRUE); - // flag this panel as chrome so buttons don't grab keyboard focus - setIsChrome(TRUE); - - mFactoryMap["toolbar"] = LLCallbackMap(createToolBar, NULL); - mFactoryMap["overlay"] = LLCallbackMap(createOverlayBar, NULL); - mFactoryMap["hud"] = LLCallbackMap(createHUD, NULL); - LLUICtrlFactory::getInstance()->buildPanel(this, "panel_bars.xml", &getFactoryMap()); - - setOrigin(rect.mLeft, rect.mBottom); - reshape(rect.getWidth(), rect.getHeight()); -} - -void LLBottomPanel::setFocusIndicator(LLView * indicator) -{ - mIndicator = indicator; -} - -void LLBottomPanel::draw() -{ - if(mIndicator) - { - BOOL hasFocus = gFocusMgr.childHasKeyboardFocus(this); - mIndicator->setVisible(hasFocus); - mIndicator->setEnabled(hasFocus); - } - LLPanel::draw(); -} - -void* LLBottomPanel::createHUD(void* data) -{ - delete gHUDView; - gHUDView = new LLHUDView(); - return gHUDView; -} - - -void* LLBottomPanel::createOverlayBar(void* data) -{ - delete gOverlayBar; - gOverlayBar = new LLOverlayBar(); - return gOverlayBar; -} - -void* LLBottomPanel::createToolBar(void* data) -{ - delete gToolBar; - gToolBar = new LLToolBar(); - return gToolBar; -} - // // LLPickInfo // @@ -4957,10 +5045,6 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos, { } -LLPickInfo::~LLPickInfo() -{ -} - void LLPickInfo::fetchResults() { @@ -4979,59 +5063,14 @@ void LLPickInfo::fetchResults() NULL, -1, mPickTransparent, &face_hit, &intersection, &uv, &normal, &binormal); - // read back colors and depth values from buffer - //glReadPixels(mScreenRegion.mLeft, mScreenRegion.mBottom, mScreenRegion.getWidth(), mScreenRegion.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, mPickBuffer); - //glReadPixels(mScreenRegion.mLeft, mScreenRegion.mBottom, mScreenRegion.getWidth(), mScreenRegion.getHeight(), GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, mPickDepthBuffer ); - - // find pick region that is fully onscreen - LLCoordGL scaled_pick_point;; - scaled_pick_point.mX = llclamp(llround((F32)mMousePt.mX * gViewerWindow->getDisplayScale().mV[VX]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayWidth() - PICK_HALF_WIDTH); - scaled_pick_point.mY = llclamp(llround((F32)mMousePt.mY * gViewerWindow->getDisplayScale().mV[VY]), PICK_HALF_WIDTH, gViewerWindow->getWindowDisplayHeight() - PICK_HALF_WIDTH); - //S32 pixel_index = PICK_HALF_WIDTH * PICK_DIAMETER + PICK_HALF_WIDTH; - //S32 pick_id = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2]; - //F32 depth = mPickDepthBuffer[pixel_index]; - - //S32 x_offset = mMousePt.mX - llround((F32)scaled_pick_point.mX / gViewerWindow->getDisplayScale().mV[VX]); - //S32 y_offset = mMousePt.mY - llround((F32)scaled_pick_point.mY / gViewerWindow->getDisplayScale().mV[VY]); - mPickPt = mMousePt; - // we hit nothing, scan surrounding pixels for something useful - /*if (!pick_id) - { - S32 closest_distance = 10000; - //S32 closest_pick_name = 0; - for (S32 col = 0; col < PICK_DIAMETER; col++) - { - for (S32 row = 0; row < PICK_DIAMETER; row++) - { - S32 distance_squared = (llabs(col - x_offset - PICK_HALF_WIDTH) * llabs(col - x_offset - PICK_HALF_WIDTH)) + (llabs(row - y_offset - PICK_HALF_WIDTH) * llabs(row - y_offset - PICK_HALF_WIDTH)); - pixel_index = row * PICK_DIAMETER + col; - S32 test_name = (U32)mPickBuffer[(pixel_index * 4) + 0] << 16 | (U32)mPickBuffer[(pixel_index * 4) + 1] << 8 | (U32)mPickBuffer[(pixel_index * 4) + 2]; - if (test_name && distance_squared < closest_distance) - { - closest_distance = distance_squared; - pick_id = test_name; - depth = mPickDepthBuffer[pixel_index]; - mPickPt.mX = mMousePt.mX + (col - PICK_HALF_WIDTH); - mPickPt.mY = mMousePt.mY + (row - PICK_HALF_WIDTH); - } - } - } - }*/ - - U32 te_offset = face_hit > -1 ? face_hit : 0; - //pick_id &= 0x000fffff; //unproject relative clicked coordinate from window coordinate using GL LLViewerObject* objectp = hit_object; - //if (pick_id == (S32)GL_NAME_PARCEL_WALL) - //{ - // mPickType = PICK_PARCEL_WALL; - //} if (hit_icon && (!objectp || icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec())) @@ -5075,20 +5114,6 @@ void LLPickInfo::fetchResults() mObjectID = objectp->mID; mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset; - /*glh::matrix4f newModel((F32*)LLViewerCamera::getInstance()->getModelview().mMatrix); - - for(U32 i = 0; i < 16; ++i) - { - modelview[i] = newModel.m[i]; - projection[i] = LLViewerCamera::getInstance()->getProjection().mMatrix[i/4][i%4]; - } - glGetIntegerv( GL_VIEWPORT, viewport ); - - winX = ((F32)mPickPt.mX) * gViewerWindow->getDisplayScale().mV[VX]; - winY = ((F32)mPickPt.mY) * gViewerWindow->getDisplayScale().mV[VY]; - - gluUnProject( winX, winY, depth, modelview, projection, viewport, &posX, &posY, &posZ);*/ - mPosGlobal = gAgent.getPosGlobalFromAgent(intersection); if (mWantSurfaceInfo) @@ -5114,15 +5139,11 @@ void LLPickInfo::updateXYCoords() if (mObjectFace > -1) { const LLTextureEntry* tep = getObject()->getTE(mObjectFace); - LLPointer imagep = gImageList.getImage(tep->getID()); + LLPointer imagep = LLViewerTextureManager::getFetchedTexture(tep->getID()); if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull()) { - LLCoordGL coords; - - coords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); - coords.mY = llround(mUVCoords.mV[VY] * (F32)imagep->getHeight()); - - gViewerWindow->getWindow()->convertCoords(coords, &mXYCoords); + mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth()); + mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight()); } } } diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 509a7c4884..7afb77bed8 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -44,12 +44,13 @@ #include "v3dmath.h" #include "v2math.h" -#include "llwindow.h" +#include "llwindowcallbacks.h" #include "lltimer.h" #include "llstat.h" -#include "llalertdialog.h" #include "llnotifications.h" #include "llmousehandler.h" +#include "llcursortypes.h" +#include "llhandle.h" class LLView; class LLViewerObject; @@ -60,6 +61,8 @@ class LLVelocityBar; class LLTextBox; class LLImageRaw; class LLHUDIcon; +class LLWindow; +class LLRootView; #define PICK_HALF_WIDTH 5 #define PICK_DIAMETER (2 * PICK_HALF_WIDTH + 1) @@ -74,7 +77,6 @@ public: BOOL pick_transparent, BOOL pick_surface_info, void (*pick_callback)(const LLPickInfo& pick_info)); - ~LLPickInfo(); void fetchResults(); LLPointer getObject() const; @@ -181,15 +183,28 @@ public: /*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg); /*virtual*/ void handlePauseWatchdog(LLWindow *window); /*virtual*/ void handleResumeWatchdog(LLWindow *window); - + /*virtual*/ std::string translateString(const char* tag); + /*virtual*/ std::string translateString(const char* tag, + const std::map& args); + + // signal on bottom tray width changed + typedef boost::function bottom_tray_callback_t; + typedef boost::signals2::signal bottom_tray_signal_t; + bottom_tray_signal_t mOnBottomTrayWidthChanged; + boost::signals2::connection setOnBottomTrayWidthChanged(bottom_tray_callback_t cb) { return mOnBottomTrayWidthChanged.connect(cb); } // // ACCESSORS // - LLView* getRootView() const { return mRootView; } + LLRootView* getRootView() const; // Window in raw pixels as seen on screen. const LLRect& getWindowRect() const { return mWindowRect; }; + // portion of window that shows 3d world + const LLRect& getWorldViewRect() const { return mWorldViewRect; }; + LLRect getVirtualWorldViewRect() const; + S32 getWorldViewHeight() const; + S32 getWorldViewWidth() const; S32 getWindowDisplayHeight() const; S32 getWindowDisplayWidth() const; @@ -200,9 +215,9 @@ public: S32 getWindowWidth() const; LLWindow* getWindow() const { return mWindow; } - void* getPlatformWindow() const { return mWindow->getPlatformWindow(); } - void* getMediaWindow() const { return mWindow->getMediaWindow(); } - void focusClient() const { return mWindow->focusClient(); }; + void* getPlatformWindow() const; + void* getMediaWindow() const; + void focusClient() const; LLCoordGL getLastMouse() const { return mLastMousePoint; } S32 getLastMouseX() const { return mLastMousePoint.mX; } @@ -221,7 +236,8 @@ public: const LLPickInfo& getLastPick() const { return mLastPick; } const LLPickInfo& getHoverPick() const { return mHoverPick; } - void setupViewport(S32 x_offset = 0, S32 y_offset = 0); + void setup2DViewport(S32 x_offset = 0, S32 y_offset = 0); + void setup3DViewport(S32 x_offset = 0, S32 y_offset = 0); void setup3DRender(); void setup2DRender(); @@ -261,7 +277,14 @@ public: void updateObjectUnderCursor(); - BOOL handlePerFrameHover(); // Once per frame, update UI based on mouse position + void updateUI(); // Once per frame, update UI based on mouse position, calls following update* functions + void updateLayout(); + void updateMouseDelta(); + void updateKeyboardFocus(); + void updatePicking(S32 x, S32 y, MASK mask); + + void updateWorldViewRect(bool use_full_window=false); + void updateBottomTrayRect(); BOOL handleKey(KEY key, MASK mask); void handleScrollWheel (S32 clicks); @@ -349,11 +372,13 @@ public: // handle shutting down GL and bringing it back up void requestResolutionUpdate(bool fullscreen_checked); + void requestResolutionUpdate(); // doesn't affect fullscreen BOOL checkSettings(); void restartDisplay(BOOL show_progress_bar); BOOL changeDisplaySettings(BOOL fullscreen, LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar); BOOL getIgnoreDestroyWindow() { return mIgnoreActivate; } F32 getDisplayAspectRatio() const; + F32 getWorldViewAspectRatio() const; const LLVector2& getDisplayScale() const { return mDisplayScale; } void calcDisplayScale(); @@ -382,7 +407,8 @@ protected: BOOL mShowFullscreenProgress; LLRect mWindowRect; LLRect mVirtualWindowRect; - LLView* mRootView; // a view of size mWindowRect, containing all child views + LLRect mWorldViewRect; // specifies area of screen where we render the 3D world + LLRootView* mRootView; // a view of size mWindowRect, containing all child views LLVector2 mDisplayScale; LLCoordGL mCurrentMousePoint; // last mouse position in GL coords @@ -395,12 +421,16 @@ protected: LLProgressView *mProgressView; + LLFrameTimer mToolTipFadeTimer; LLTextBox* mToolTip; + std::string mLastToolTipMessage; BOOL mToolTipBlocked; // True after a key press or a mouse button event. False once the mouse moves again. LLRect mToolTipStickyRect; // Once a tool tip is shown, it will stay visible until the mouse leaves this rect. BOOL mMouseInWindow; // True if the mouse is over our window or if we have captured the mouse. BOOL mFocusCycleMode; + typedef std::set > view_handle_set_t; + view_handle_set_t mMouseHoverViews; // Variables used for tool override switching based on modifier keys. JC MASK mLastMask; // used to detect changes in modifier mask @@ -435,36 +465,16 @@ protected: static std::string sMovieBaseName; }; -class LLBottomPanel : public LLPanel -{ -public: - LLBottomPanel(const LLRect& rect); - void setFocusIndicator(LLView * indicator); - LLView * getFocusIndicator() { return mIndicator; } - /*virtual*/ void draw(); - - static void* createHUD(void* data); - static void* createOverlayBar(void* data); - static void* createToolBar(void* data); - -protected: - LLView * mIndicator; -}; -extern LLBottomPanel * gBottomPanel; - void toggle_flying(void*); void toggle_first_person(); void toggle_build(void*); void reset_viewer_state_on_sim(void); void update_saved_window_size(const std::string& control,S32 delta_width, S32 delta_height); - - // // Globals // -extern LLVelocityBar* gVelocityBar; extern LLViewerWindow* gViewerWindow; extern LLFrameTimer gMouseIdleTimer; // how long has it been since the mouse last moved? diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp index e52fec7909..f26ba6f46e 100644 --- a/indra/newview/llvlcomposition.cpp +++ b/indra/newview/llvlcomposition.cpp @@ -39,8 +39,8 @@ #include "v3math.h" #include "llsurface.h" #include "lltextureview.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "noise.h" #include "llregionhandle.h" // for from_region_handle @@ -106,7 +106,7 @@ void LLVLComposition::setDetailTextureID(S32 corner, const LLUUID& id) { return; } - mDetailTextures[corner] = gImageList.getImage(id); + mDetailTextures[corner] = LLViewerTextureManager::getFetchedTexture(id); mDetailTextures[corner]->setNoDelete() ; mRawImages[corner] = NULL; } @@ -229,7 +229,7 @@ BOOL LLVLComposition::generateComposition() { if (mDetailTextures[i]->getDiscardLevel() < 0) { - mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail + mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); // in case we are at low detail mDetailTextures[i]->addTextureStats(BASE_SIZE*BASE_SIZE); return FALSE; } @@ -237,8 +237,8 @@ BOOL LLVLComposition::generateComposition() (mDetailTextures[i]->getWidth() < BASE_SIZE || mDetailTextures[i]->getHeight() < BASE_SIZE))) { - S32 width = mDetailTextures[i]->getWidth(0); - S32 height = mDetailTextures[i]->getHeight(0); + S32 width = mDetailTextures[i]->getFullWidth(); + S32 height = mDetailTextures[i]->getFullHeight(); S32 min_dim = llmin(width, height); S32 ddiscard = 0; while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) @@ -246,7 +246,7 @@ BOOL LLVLComposition::generateComposition() ddiscard++; min_dim /= 2; } - mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_TERRAIN); // in case we are at low detail + mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_TERRAIN); // in case we are at low detail mDetailTextures[i]->setMinDiscardLevel(ddiscard); return FALSE; } @@ -280,7 +280,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, { // Read back a raw image for this discard level, if it exists mRawImages[i] = new LLImageRaw; - S32 min_dim = llmin(mDetailTextures[i]->getWidth(0), mDetailTextures[i]->getHeight(0)); + S32 min_dim = llmin(mDetailTextures[i]->getFullWidth(), mDetailTextures[i]->getFullHeight()); S32 ddiscard = 0; while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL) { @@ -336,7 +336,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, // // - LLViewerImage *texturep; + LLViewerTexture *texturep; U32 tex_width, tex_height, tex_comps; U32 tex_stride; F32 tex_x_scalef, tex_y_scalef; @@ -455,7 +455,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y, for (S32 i = 0; i < 4; i++) { // Un-boost detatil textures (will get re-boosted if rendering in high detail) - mDetailTextures[i]->setBoostLevel(LLViewerImage::BOOST_NONE); + mDetailTextures[i]->setBoostLevel(LLViewerTexture::BOOST_NONE); mDetailTextures[i]->setMinDiscardLevel(MAX_DISCARD_LEVEL + 1); } @@ -467,7 +467,7 @@ LLUUID LLVLComposition::getDetailTextureID(S32 corner) return mDetailTextures[corner]->getID(); } -LLViewerImage* LLVLComposition::getDetailTexture(S32 corner) +LLViewerFetchedTexture* LLVLComposition::getDetailTexture(S32 corner) { return mDetailTextures[corner]; } diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h index 6d5db3c050..d1b3dc4495 100644 --- a/indra/newview/llvlcomposition.h +++ b/indra/newview/llvlcomposition.h @@ -34,7 +34,7 @@ #define LL_LLVLCOMPOSITION_H #include "llviewerlayer.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLSurface; @@ -62,7 +62,7 @@ public: CORNER_COUNT = 4 }; LLUUID getDetailTextureID(S32 corner); - LLViewerImage* getDetailTexture(S32 corner); + LLViewerFetchedTexture* getDetailTexture(S32 corner); F32 getStartHeight(S32 corner); F32 getHeightRange(S32 corner); @@ -79,7 +79,7 @@ protected: LLSurface *mSurfacep; BOOL mTexturesLoaded; - LLPointer mDetailTextures[CORNER_COUNT]; + LLPointer mDetailTextures[CORNER_COUNT]; LLPointer mRawImages[CORNER_COUNT]; F32 mStartHeight[CORNER_COUNT]; diff --git a/indra/newview/llvlmanager.cpp b/indra/newview/llvlmanager.cpp index 177093c4d1..07ef262668 100644 --- a/indra/newview/llvlmanager.cpp +++ b/indra/newview/llvlmanager.cpp @@ -40,7 +40,6 @@ #include "patch_dct.h" #include "llviewerregion.h" #include "llframetimer.h" -#include "llagent.h" #include "llsurface.h" LLVLManager gVLManager; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 983a580fea..018cce4b49 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -1,5 +1,5 @@ /** - * @file llvoavatar.cpp + * @File llvoavatar.cpp * @brief Implementation of LLVOAvatar class which is a derivation fo LLViewerObject * * $LicenseInfo:firstyear=2001&license=viewergpl$ @@ -37,10 +37,12 @@ #include #include -#include "audioengine.h" +#include "llaudioengine.h" #include "noise.h" #include "llagent.h" // Get state values from here +#include "llagentwearables.h" +#include "llanimationstates.h" #include "llviewercontrol.h" #include "lldrawpoolavatar.h" #include "lldriverparam.h" @@ -50,11 +52,11 @@ #include "llheadrotmotion.h" #include "llhudeffecttrail.h" #include "llhudmanager.h" -#include "llinventoryview.h" #include "llkeyframefallmotion.h" #include "llkeyframestandmotion.h" #include "llkeyframewalkmotion.h" #include "llmutelist.h" +#include "llmoveview.h" #include "llnotify.h" #include "llquantize.h" #include "llregionhandle.h" @@ -63,21 +65,22 @@ #include "llsprite.h" #include "lltargetingmotion.h" #include "lltexlayer.h" -#include "lltoolgrab.h" // for needsRenderBeam -#include "lltoolmgr.h" // for needsRenderBeam #include "lltoolmorph.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewermenu.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerstats.h" +#include "llvoavatarself.h" #include "llvovolume.h" #include "llworld.h" #include "pipeline.h" #include "llviewershadermgr.h" #include "llsky.h" #include "llanimstatelabels.h" +#include "lltrans.h" + #include "llgesturemgr.h" //needed to trigger the voice gesticulations #include "llvoiceclient.h" #include "llvoicevisualizer.h" // Ventrella @@ -136,8 +139,7 @@ const S32 MIN_REQUIRED_PIXEL_AREA_PELVIS_FIX = 40; const S32 TEX_IMAGE_SIZE_SELF = 512; const S32 TEX_IMAGE_AREA_SELF = TEX_IMAGE_SIZE_SELF * TEX_IMAGE_SIZE_SELF; -const S32 TEX_IMAGE_SIZE_OTHER = TEX_IMAGE_SIZE_SELF / 4; // The size of local textures for other (!mIsSelf) avatars -const S32 TEX_IMAGE_AREA_OTHER = TEX_IMAGE_SIZE_OTHER * TEX_IMAGE_SIZE_OTHER; +const S32 TEX_IMAGE_SIZE_OTHER = 512 / 4; // The size of local textures for other (!isSelf()) avatars const F32 HEAD_MOVEMENT_AVG_TIME = 0.9f; @@ -168,32 +170,27 @@ const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0); enum ERenderName { RENDER_NAME_NEVER, - RENDER_NAME_FADE, - RENDER_NAME_ALWAYS + RENDER_NAME_ALWAYS, + RENDER_NAME_FADE }; //----------------------------------------------------------------------------- // Callback data //----------------------------------------------------------------------------- -struct LLAvatarTexData -{ - LLAvatarTexData( const LLUUID& id, ETextureIndex index ) - : mAvatarID(id), mIndex(index) {} - LLUUID mAvatarID; - ETextureIndex mIndex; -}; struct LLTextureMaskData { - LLTextureMaskData( const LLUUID& id ) - : mAvatarID(id), mLastDiscardLevel(S32_MAX) {} + LLTextureMaskData( const LLUUID& id ) : + mAvatarID(id), + mLastDiscardLevel(S32_MAX) + {} LLUUID mAvatarID; S32 mLastDiscardLevel; }; /********************************************************************************* ** ** - ** Begin LLVOAvatar Support classes + ** Begin private LLVOAvatar Support classes ** **/ @@ -249,85 +246,6 @@ private: bone_info_list_t mBoneInfoList; }; - -//------------------------------------------------------------------------ -// LLVOAvatarXmlInfo -// One instance (in LLVOAvatar) with common data parsed from the XML files -//------------------------------------------------------------------------ -class LLVOAvatarXmlInfo -{ - friend class LLVOAvatar; -public: - LLVOAvatarXmlInfo(); - ~LLVOAvatarXmlInfo(); - -private: - BOOL parseXmlSkeletonNode(LLXmlTreeNode* root); - BOOL parseXmlMeshNodes(LLXmlTreeNode* root); - BOOL parseXmlColorNodes(LLXmlTreeNode* root); - BOOL parseXmlLayerNodes(LLXmlTreeNode* root); - BOOL parseXmlDriverNodes(LLXmlTreeNode* root); - - struct LLVOAvatarMeshInfo - { - typedef std::pair morph_info_pair_t; - typedef std::vector morph_info_list_t; - - LLVOAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {} - ~LLVOAvatarMeshInfo() - { - morph_info_list_t::iterator iter; - for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++) - { - delete iter->first; - } - mPolyMorphTargetInfoList.clear(); - } - - std::string mType; - S32 mLOD; - std::string mMeshFileName; - std::string mReferenceMeshName; - F32 mMinPixelArea; - morph_info_list_t mPolyMorphTargetInfoList; - }; - typedef std::vector mesh_info_list_t; - mesh_info_list_t mMeshInfoList; - - typedef std::vector skeletal_distortion_info_list_t; - skeletal_distortion_info_list_t mSkeletalDistortionInfoList; - - struct LLVOAvatarAttachmentInfo - { - LLVOAvatarAttachmentInfo() - : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE), - mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {} - std::string mName; - std::string mJointName; - LLVector3 mPosition; - LLVector3 mRotationEuler; - S32 mGroup; - S32 mAttachmentID; - S32 mPieMenuSlice; - BOOL mVisibleFirstPerson; - BOOL mIsHUDAttachment; - BOOL mHasPosition; - BOOL mHasRotation; - }; - typedef std::vector attachment_info_list_t; - attachment_info_list_t mAttachmentInfoList; - - LLTexGlobalColorInfo *mTexSkinColorInfo; - LLTexGlobalColorInfo *mTexHairColorInfo; - LLTexGlobalColorInfo *mTexEyeColorInfo; - - typedef std::vector layer_info_list_t; - layer_info_list_t mLayerInfoList; - - typedef std::vector driver_info_list_t; - driver_info_list_t mDriverInfoList; -}; - //----------------------------------------------------------------------------- // class LLBodyNoiseMotion //----------------------------------------------------------------------------- @@ -492,7 +410,7 @@ public: virtual LLMotionInitStatus onInitialize(LLCharacter *character) { mCharacter = character; - bool success = true; + BOOL success = true; if ( !mChestState->setJoint( character->getJoint( "mChest" ) ) ) { success = false; } @@ -651,15 +569,11 @@ private: //----------------------------------------------------------------------------- LLXmlTree LLVOAvatar::sXMLTree; LLXmlTree LLVOAvatar::sSkeletonXMLTree; -BOOL LLVOAvatar::sDebugAvatarRotation = FALSE; LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL; -LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL; +LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL; LLVOAvatarDictionary *LLVOAvatar::sAvatarDictionary = NULL; S32 LLVOAvatar::sFreezeCounter = 0; S32 LLVOAvatar::sMaxVisible = 50; -LLMap< LLGLenum, LLGLuint*> LLVOAvatar::sScratchTexNames; -LLMap< LLGLenum, F32*> LLVOAvatar::sScratchTexLastBindTime; -S32 LLVOAvatar::sScratchTexBytes = 0; F32 LLVOAvatar::sRenderDistance = 256.f; S32 LLVOAvatar::sNumVisibleAvatars = 0; S32 LLVOAvatar::sNumLODChangesThisFrame = 0; @@ -730,8 +644,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNameMute(FALSE), mRenderGroupTitles(sRenderGroupTitles), mNameAppearance(FALSE), - mLastRegionHandle(0), - mRegionCrossingCount(0), mFirstTEMessageReceived( FALSE ), mFirstAppearanceMessageReceived( FALSE ), mCulled( FALSE ), @@ -742,36 +654,29 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mNeedsSkin(FALSE), mUpdatePeriod(1), mFullyLoadedInitialized(FALSE), - mHasBakedHair( FALSE ) + mSupportsAlphaLayers(FALSE) { LLMemType mt(LLMemType::MTYPE_AVATAR); //VTResume(); // VTune // mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline - const bool needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job + const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim ); lldebugs << "LLVOAvatar Constructor (0x" << this << ") id:" << mID << llendl; mPelvisp = NULL; - for( S32 i=0; ibind(mShadowImagep.get()); + mShadowImagep = LLViewerTextureManager::getFetchedTextureFromFile("foot_shadow.j2c"); + gGL.getTexUnit(0)->bind(mShadowImagep); mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP); mInAir = FALSE; @@ -837,146 +730,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id, mOohMorph = NULL; mAahMorph = NULL; - //------------------------------------------------------------------------- - // initialize joint, mesh and shape members - //------------------------------------------------------------------------- - mRoot.setName( "mRoot" ); - - for (LLVOAvatarDictionary::mesh_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); - iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - iter++) - { - const EMeshIndex mesh_index = iter->first; - const LLVOAvatarDictionary::MeshDictionaryEntry *mesh_dict = iter->second; - - LLViewerJoint* joint = new LLViewerJoint(); - joint->setName(mesh_dict->mName); - joint->setMeshID(mesh_index); - mMeshLOD.push_back(joint); - - /* mHairLOD.setName("mHairLOD"); - mHairMesh0.setName("mHairMesh0"); - mHairMesh0.setMeshID(MESH_ID_HAIR); - mHairMesh1.setName("mHairMesh1"); */ - for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) - { - LLViewerJointMesh* mesh = new LLViewerJointMesh(); - std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); - // We pre-pended an m - need to capitalize first character for camelCase - mesh_name[1] = toupper(mesh_name[1]); - mesh->setName(mesh_name); - mesh->setMeshID(mesh_index); - mesh->setPickName(mesh_dict->mPickName); - switch((int)mesh_index) - { - case MESH_ID_HAIR: - mesh->setIsTransparent(TRUE); - break; - case MESH_ID_SKIRT: - mesh->setIsTransparent(TRUE); - break; - case MESH_ID_EYEBALL_LEFT: - case MESH_ID_EYEBALL_RIGHT: - mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); - break; - } - - joint->mMeshParts.push_back(mesh); - } - } - - //------------------------------------------------------------------------- - // associate baked textures with meshes - //------------------------------------------------------------------------- - for (LLVOAvatarDictionary::mesh_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); - iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); - iter++) - { - const EMeshIndex mesh_index = iter->first; - const LLVOAvatarDictionary::MeshDictionaryEntry *mesh_dict = iter->second; - const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; - - // Skip it if there's no associated baked texture. - if (baked_texture_index == BAKED_NUM_INDICES) continue; - - for (std::vector::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); - iter != mMeshLOD[mesh_index]->mMeshParts.end(); iter++) - { - LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter; - mBakedTextureData[(int)baked_texture_index].mMeshes.push_back(mesh); - } - } - - - //------------------------------------------------------------------------- - // register motions - //------------------------------------------------------------------------- - if (LLCharacter::sInstances.size() == 1) - { - LLKeyframeMotion::setVFS(gStaticVFS); - registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); - registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create ); - registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create ); - registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create ); - registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create ); - registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create ); - - // motions without a start/stop bit - registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); - registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); - registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); - registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); - registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); - registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); - registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); - registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); - registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); - registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); - registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); - registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); - - } - - if (gNoRender) - { - return; - } - buildCharacter(); - - // preload specific motions here - createMotion( ANIM_AGENT_CUSTOMIZE); - createMotion( ANIM_AGENT_CUSTOMIZE_DONE); - - //VTPause(); // VTune - - mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) ); mCurrentGesticulationLevel = 0; + } //------------------------------------------------------------------------ @@ -986,46 +741,43 @@ LLVOAvatar::~LLVOAvatar() { lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl; - if (mIsSelf) + if (isSelf()) { gAgent.setAvatarObject(NULL); } mRoot.removeAllChildren(); - delete [] mSkeleton; - mSkeleton = NULL; - - delete mScreenp; - mScreenp = NULL; - - delete [] mCollisionVolumes; - mCollisionVolumes = NULL; - + deleteAndClearArray(mSkeleton); + deleteAndClearArray(mCollisionVolumes); mNumJoints = 0; - for (U32 i = 0; i < mBakedTextureData.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - delete mBakedTextureData[i].mTexLayerSet; - mBakedTextureData[i].mTexLayerSet = NULL; + deleteAndClear(mBakedTextureDatas[i].mTexLayerSet); + mBakedTextureDatas[i].mMeshes.clear(); + + for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin(); + iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++) + { + LLMaskedMorph* masked_morph = (*iter2); + delete masked_morph; + } } std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer()); mAttachmentPoints.clear(); - delete mTexSkinColor; - mTexSkinColor = NULL; - delete mTexHairColor; - mTexHairColor = NULL; - delete mTexEyeColor; - mTexEyeColor = NULL; + deleteAndClear(mTexSkinColor); + deleteAndClear(mTexHairColor); + deleteAndClear(mTexEyeColor); std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer()); mMeshes.clear(); for (std::vector::iterator jointIter = mMeshLOD.begin(); - jointIter != mMeshLOD.end(); jointIter++) + jointIter != mMeshLOD.end(); jointIter++) { LLViewerJoint* joint = (LLViewerJoint *) *jointIter; std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer()); @@ -1036,9 +788,6 @@ LLVOAvatar::~LLVOAvatar() mDead = TRUE; - // Clean up class data - LLVOAvatar::cullAvatarsByPixelArea(); - mAnimationSources.clear(); lldebugs << "LLVOAvatar Destructor end" << llendl; @@ -1052,10 +801,7 @@ void LLVOAvatar::markDead() mNameText = NULL; sNumVisibleChatBubbles--; } - mVoiceVisualizer->markDead(); - - mBeam = NULL; LLViewerObject::markDead(); } @@ -1065,9 +811,9 @@ BOOL LLVOAvatar::isFullyBaked() if (mIsDummy) return TRUE; if (getNumTEs() == 0) return FALSE; - for (U32 i = 0; i < mBakedTextureData.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - if (!isTextureDefined(mBakedTextureData[i].mTextureIndex) + if (!isTextureDefined(mBakedTextureDatas[i].mTextureIndex) && ( (i != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) ) ) { return FALSE; @@ -1078,19 +824,21 @@ BOOL LLVOAvatar::isFullyBaked() void LLVOAvatar::deleteLayerSetCaches(bool clearAll) { - for (U32 i = 0; i < mBakedTextureData.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - if (mBakedTextureData[i].mTexLayerSet) + if (mBakedTextureDatas[i].mTexLayerSet) { - if ((i != BAKED_HAIR || mIsSelf) && !clearAll) // Backwards compatibility - can be removed after hair baking is mandatory on the grid + // ! BACKWARDS COMPATIBILITY ! + // Can be removed after hair baking is mandatory on the grid + if ((i != BAKED_HAIR || isSelf()) && !clearAll) { - mBakedTextureData[i].mTexLayerSet->deleteCaches(); + mBakedTextureDatas[i].mTexLayerSet->deleteCaches(); } } - if (mBakedTextureData[i].mMaskTexName) + if (mBakedTextureDatas[i].mMaskTexName) { - glDeleteTextures(1, (GLuint*)&(mBakedTextureData[i].mMaskTexName)); - mBakedTextureData[i].mMaskTexName = 0 ; + glDeleteTextures(1, (GLuint*)&(mBakedTextureDatas[i].mMaskTexName)); + mBakedTextureDatas[i].mMaskTexName = 0 ; } } } @@ -1101,20 +849,14 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) BOOL res = TRUE; grey_avatars = 0; for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; if( inst->isDead() ) { continue; } -// else -// if( inst->getPixelArea() < MIN_PIXEL_AREA_FOR_COMPOSITE ) -// { -// return res; // Assumes sInstances is sorted by pixel area. -// } - else - if( !inst->isFullyBaked() ) + else if( !inst->isFullyBaked() ) { res = FALSE; if (inst->mHasGrey) @@ -1126,19 +868,13 @@ BOOL LLVOAvatar::areAllNearbyInstancesBaked(S32& grey_avatars) return res; } -// static -void LLVOAvatar::dumpScratchTextureByteCount() -{ - llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; -} - // static void LLVOAvatar::dumpBakedStatus() { LLVector3d camera_pos_global = gAgent.getCameraPositionGlobal(); for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; llinfos << "Avatar "; @@ -1190,18 +926,17 @@ void LLVOAvatar::dumpBakedStatus() { llcont << " Unbaked ("; - for (LLVOAvatarDictionary::baked_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + for (LLVOAvatarDictionary::BakedTextures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); iter++) { - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = iter->second; + const LLVOAvatarDictionary::BakedEntry *baked_dict = iter->second; const ETextureIndex index = baked_dict->mTextureIndex; if (!inst->isTextureDefined(index)) { llcont << " " << LLVOAvatarDictionary::getInstance()->getTexture(index)->mName; } } - llcont << " ) " << inst->getUnbakedPixelAreaRank(); if( inst->isCulled() ) { @@ -1215,17 +950,15 @@ void LLVOAvatar::dumpBakedStatus() //static void LLVOAvatar::restoreGL() { - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + LLVOAvatar* self = gAgent.getAvatarObject(); + if (!self) + return; + self->setCompositeUpdatesEnabled(TRUE); + for (U32 i = 0; i < self->mBakedTextureDatas.size(); i++) { - LLVOAvatar* inst = (LLVOAvatar*) *iter; - inst->setCompositeUpdatesEnabled( TRUE ); - for (U32 i = 0; i < inst->mBakedTextureData.size(); i++) - { - inst->invalidateComposite( inst->mBakedTextureData[i].mTexLayerSet, FALSE ); - } - inst->updateMeshTextures(); + self->invalidateComposite(self->mBakedTextureDatas[i].mTexLayerSet, FALSE); } + self->updateMeshTextures(); } //static @@ -1240,7 +973,7 @@ void LLVOAvatar::destroyGL() void LLVOAvatar::resetImpostors() { for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; avatar->mImpostor.release(); @@ -1254,33 +987,15 @@ void LLVOAvatar::deleteCachedImages(bool clearAll) { lldebugs << "Deleting layer set caches" << llendl; for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; inst->deleteLayerSetCaches(clearAll); } LLTexLayerSet::sHasCaches = FALSE; } - - for( LLGLuint* namep = sScratchTexNames.getFirstData(); - namep; - namep = sScratchTexNames.getNextData() ) - { - LLImageGL::deleteTextures(1, (U32 *)namep ); - stop_glerror(); - } - - if( sScratchTexBytes ) - { - lldebugs << "Clearing Scratch Textures " << (sScratchTexBytes/1024) << "KB" << llendl; - - sScratchTexNames.deleteAllData(); - LLVOAvatar::sScratchTexLastBindTime.deleteAllData(); - LLImageGL::sGlobalTextureMemoryInBytes -= sScratchTexBytes; - sScratchTexBytes = 0; - } - - gTexStaticImageList.deleteCachedImages(); + LLVOAvatarSelf::deleteScratchTextures(); + LLTexLayerStaticImageList::getInstance()->deleteCachedImages(); } @@ -1382,20 +1097,168 @@ void LLVOAvatar::initClass() { llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; } - + if (!sAvatarXmlInfo->parseXmlMorphNodes(root)) + { + llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl; + } } void LLVOAvatar::cleanupClass() { - delete sAvatarXmlInfo; - sAvatarXmlInfo = NULL; - delete sAvatarSkeletonInfo; - sAvatarSkeletonInfo = NULL; + deleteAndClear(sAvatarXmlInfo); sSkeletonXMLTree.cleanup(); sXMLTree.cleanup(); } +void LLVOAvatar::initInstance(void) +{ + //------------------------------------------------------------------------- + // initialize joint, mesh and shape members + //------------------------------------------------------------------------- + mRoot.setName( "mRoot" ); + + for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); + iter++) + { + const EMeshIndex mesh_index = iter->first; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; + LLViewerJoint* joint = new LLViewerJoint(); + joint->setName(mesh_dict->mName); + joint->setMeshID(mesh_index); + mMeshLOD.push_back(joint); + + /* mHairLOD.setName("mHairLOD"); + mHairMesh0.setName("mHairMesh0"); + mHairMesh0.setMeshID(MESH_ID_HAIR); + mHairMesh1.setName("mHairMesh1"); */ + for (U32 lod = 0; lod < mesh_dict->mLOD; lod++) + { + LLViewerJointMesh* mesh = new LLViewerJointMesh(); + std::string mesh_name = "m" + mesh_dict->mName + boost::lexical_cast(lod); + // We pre-pended an m - need to capitalize first character for camelCase + mesh_name[1] = toupper(mesh_name[1]); + mesh->setName(mesh_name); + mesh->setMeshID(mesh_index); + mesh->setPickName(mesh_dict->mPickName); + mesh->setIsTransparent(FALSE); + switch((int)mesh_index) + { + case MESH_ID_HAIR: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_SKIRT: + mesh->setIsTransparent(TRUE); + break; + case MESH_ID_EYEBALL_LEFT: + case MESH_ID_EYEBALL_RIGHT: + mesh->setSpecular( LLColor4( 1.0f, 1.0f, 1.0f, 1.0f ), 1.f ); + break; + } + + joint->mMeshParts.push_back(mesh); + } + } + + //------------------------------------------------------------------------- + // associate baked textures with meshes + //------------------------------------------------------------------------- + for (LLVOAvatarDictionary::Meshes::const_iterator iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); + iter++) + { + const EMeshIndex mesh_index = iter->first; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = iter->second; + const EBakedTextureIndex baked_texture_index = mesh_dict->mBakedID; + // Skip it if there's no associated baked texture. + if (baked_texture_index == BAKED_NUM_INDICES) continue; + + for (std::vector::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin(); + iter != mMeshLOD[mesh_index]->mMeshParts.end(); iter++) + { + LLViewerJointMesh* mesh = (LLViewerJointMesh*) *iter; + mBakedTextureDatas[(int)baked_texture_index].mMeshes.push_back(mesh); + } + } + + + //------------------------------------------------------------------------- + // register motions + //------------------------------------------------------------------------- + if (LLCharacter::sInstances.size() == 1) + { + LLKeyframeMotion::setVFS(gStaticVFS); + registerMotion( ANIM_AGENT_BUSY, LLNullMotion::create ); + registerMotion( ANIM_AGENT_CROUCH, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_CROUCHWALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_EXPRESS_AFRAID, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_ANGER, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_BORED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_CRY, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_DISDAIN, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_EMBARRASSED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_FROWN, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_KISS, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_LAUGH, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_OPEN_MOUTH, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_REPULSED, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SAD, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SHRUG, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SMILE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_SURPRISE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_TONGUE_OUT, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_TOOTHSMILE, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_WINK, LLEmote::create ); + registerMotion( ANIM_AGENT_EXPRESS_WORRY, LLEmote::create ); + registerMotion( ANIM_AGENT_RUN, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_STAND, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_1, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_2, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_3, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STAND_4, LLKeyframeStandMotion::create ); + registerMotion( ANIM_AGENT_STANDUP, LLKeyframeFallMotion::create ); + registerMotion( ANIM_AGENT_TURNLEFT, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_TURNRIGHT, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_WALK, LLKeyframeWalkMotion::create ); + + // motions without a start/stop bit + registerMotion( ANIM_AGENT_BODY_NOISE, LLBodyNoiseMotion::create ); + registerMotion( ANIM_AGENT_BREATHE_ROT, LLBreatheMotionRot::create ); + registerMotion( ANIM_AGENT_EDITING, LLEditingMotion::create ); + registerMotion( ANIM_AGENT_EYE, LLEyeMotion::create ); + registerMotion( ANIM_AGENT_FEMALE_WALK, LLKeyframeWalkMotion::create ); + registerMotion( ANIM_AGENT_FLY_ADJUST, LLFlyAdjustMotion::create ); + registerMotion( ANIM_AGENT_HAND_MOTION, LLHandMotion::create ); + registerMotion( ANIM_AGENT_HEAD_ROT, LLHeadRotMotion::create ); + registerMotion( ANIM_AGENT_PELVIS_FIX, LLPelvisFixMotion::create ); + registerMotion( ANIM_AGENT_SIT_FEMALE, LLKeyframeMotion::create ); + registerMotion( ANIM_AGENT_TARGET, LLTargetingMotion::create ); + registerMotion( ANIM_AGENT_WALK_ADJUST, LLWalkAdjustMotion::create ); + + } + + if (gNoRender) + { + return; + } + + buildCharacter(); + + if (gNoRender) + { + return; + } + + // preload specific motions here + createMotion( ANIM_AGENT_CUSTOMIZE); + createMotion( ANIM_AGENT_CUSTOMIZE_DONE); + + //VTPause(); // VTune + + mVoiceVisualizer->setVoiceEnabled( gVoiceClient->getVoiceEnabled( mID ) ); +} + const LLVector3 LLVOAvatar::getRenderPosition() const { if (mDrawable.isNull() || mDrawable->getGeneration() < 0) @@ -1461,7 +1324,7 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++) { update_min_max(newMin, newMax, - mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation()); + mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation()); } } @@ -1469,8 +1332,8 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax) //stretch bounding box by attachments for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + iter != mAttachmentPoints.end(); + ++iter) { LLViewerJointAttachment* attachment = iter->second; @@ -1535,11 +1398,9 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, - LLVector3* bi_normal - ) + LLVector3* bi_normal) { - - if (mIsSelf && !gAgent.needsRenderAvatar() || !LLPipeline::sPickAvatar) + if (isSelf() && !gAgent.needsRenderAvatar() || !LLPipeline::sPickAvatar) { return FALSE; } @@ -1668,7 +1529,6 @@ BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent return FALSE; } joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]); - joint->setName( info->mName ); } @@ -1679,10 +1539,8 @@ BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent } joint->setPosition(info->mPos); - joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY], info->mRot.mV[VZ], LLQuaternion::XYZ)); - joint->setScale(info->mScale); @@ -1751,18 +1609,6 @@ BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info) } } - // add special-purpose "screen" joint - if (mIsSelf) - { - mScreenp = new LLViewerJoint("mScreen", NULL); - // for now, put screen at origin, as it is only used during special - // HUD rendering mode - F32 aspect = LLViewerCamera::getInstance()->getAspect(); - LLVector3 scale(1.f, aspect, 1.f); - mScreenp->setScale(scale); - mScreenp->setWorldPosition(LLVector3::zero); - } - return TRUE; } @@ -1811,11 +1657,11 @@ void LLVOAvatar::buildCharacter() // clear mesh data //------------------------------------------------------------------------- for (std::vector::iterator jointIter = mMeshLOD.begin(); - jointIter != mMeshLOD.end(); jointIter++) + jointIter != mMeshLOD.end(); jointIter++) { LLViewerJoint* joint = (LLViewerJoint*) *jointIter; for (std::vector::iterator meshIter = joint->mMeshParts.begin(); - meshIter != joint->mMeshParts.end(); meshIter++) + meshIter != joint->mMeshParts.end(); meshIter++) { LLViewerJointMesh * mesh = (LLViewerJointMesh *) *meshIter; mesh->setMesh(NULL); @@ -1839,9 +1685,9 @@ void LLVOAvatar::buildCharacter() // gPrintMessagesThisFrame = TRUE; lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl; - if ( ! status ) + if (!status) { - if ( mIsSelf ) + if (isSelf()) { llerrs << "Unable to load user's avatar" << llendl; } @@ -1878,23 +1724,23 @@ void LLVOAvatar::buildCharacter() // Make sure "well known" pointers exist //------------------------------------------------------------------------- if (!(mPelvisp && - mTorsop && - mChestp && - mNeckp && - mHeadp && - mSkullp && - mHipLeftp && - mHipRightp && - mKneeLeftp && - mKneeRightp && - mAnkleLeftp && - mAnkleRightp && - mFootLeftp && - mFootRightp && - mWristLeftp && - mWristRightp && - mEyeLeftp && - mEyeRightp)) + mTorsop && + mChestp && + mNeckp && + mHeadp && + mSkullp && + mHipLeftp && + mHipRightp && + mKneeLeftp && + mKneeRightp && + mAnkleLeftp && + mAnkleRightp && + mFootLeftp && + mFootRightp && + mWristLeftp && + mWristRightp && + mEyeLeftp && + mEyeRightp)) { llerrs << "Failed to create avatar." << llendl; return; @@ -1940,197 +1786,6 @@ void LLVOAvatar::buildCharacter() mIsBuilt = TRUE; stop_glerror(); - //------------------------------------------------------------------------- - // build the attach and detach menus - //------------------------------------------------------------------------- - if (mIsSelf) - { - // *TODO: Translate - gAttachBodyPartPieMenus[0] = NULL; - gAttachBodyPartPieMenus[1] = new LLPieMenu(std::string("Right Arm >")); - gAttachBodyPartPieMenus[2] = new LLPieMenu(std::string("Head >")); - gAttachBodyPartPieMenus[3] = new LLPieMenu(std::string("Left Arm >")); - gAttachBodyPartPieMenus[4] = NULL; - gAttachBodyPartPieMenus[5] = new LLPieMenu(std::string("Left Leg >")); - gAttachBodyPartPieMenus[6] = new LLPieMenu(std::string("Torso >")); - gAttachBodyPartPieMenus[7] = new LLPieMenu(std::string("Right Leg >")); - - gDetachBodyPartPieMenus[0] = NULL; - gDetachBodyPartPieMenus[1] = new LLPieMenu(std::string("Right Arm >")); - gDetachBodyPartPieMenus[2] = new LLPieMenu(std::string("Head >")); - gDetachBodyPartPieMenus[3] = new LLPieMenu(std::string("Left Arm >")); - gDetachBodyPartPieMenus[4] = NULL; - gDetachBodyPartPieMenus[5] = new LLPieMenu(std::string("Left Leg >")); - gDetachBodyPartPieMenus[6] = new LLPieMenu(std::string("Torso >")); - gDetachBodyPartPieMenus[7] = new LLPieMenu(std::string("Right Leg >")); - - for (S32 i = 0; i < 8; i++) - { - if (gAttachBodyPartPieMenus[i]) - { - gAttachPieMenu->appendPieMenu( gAttachBodyPartPieMenus[i] ); - } - else - { - BOOL attachment_found = FALSE; - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getGroup() == i) - { - LLMenuItemCallGL* item; - item = new LLMenuItemCallGL(attachment->getName(), - NULL, - object_selected_and_point_valid); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", curiter->first); - - gAttachPieMenu->append(item); - - attachment_found = TRUE; - break; - - } - } - - if (!attachment_found) - { - gAttachPieMenu->appendSeparator(); - } - } - - if (gDetachBodyPartPieMenus[i]) - { - gDetachPieMenu->appendPieMenu( gDetachBodyPartPieMenus[i] ); - } - else - { - BOOL attachment_found = FALSE; - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getGroup() == i) - { - gDetachPieMenu->append(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, object_attached, attachment)); - - attachment_found = TRUE; - break; - } - } - - if (!attachment_found) - { - gDetachPieMenu->appendSeparator(); - } - } - } - - // add screen attachments - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getGroup() == 8) - { - LLMenuItemCallGL* item; - item = new LLMenuItemCallGL(attachment->getName(), - NULL, - object_selected_and_point_valid); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", curiter->first); - gAttachScreenPieMenu->append(item); - gDetachScreenPieMenu->append(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, object_attached, attachment)); - } - } - - for (S32 pass = 0; pass < 2; pass++) - { - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment() != (pass == 1)) - { - continue; - } - LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), - NULL, &object_selected_and_point_valid, - &attach_label, attachment); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", curiter->first); - gAttachSubMenu->append(item); - - gDetachSubMenu->append(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, object_attached, &detach_label, attachment)); - - } - if (pass == 0) - { - // put separator between non-hud and hud attachments - gAttachSubMenu->appendSeparator(); - gDetachSubMenu->appendSeparator(); - } - } - - for (S32 group = 0; group < 8; group++) - { - // skip over groups that don't have sub menus - if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group]) - { - continue; - } - - std::multimap attachment_pie_menu_map; - - // gather up all attachment points assigned to this group, and throw into map sorted by pie slice number - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if(attachment->getGroup() == group) - { - // use multimap to provide a partial order off of the pie slice key - S32 pie_index = attachment->getPieSlice(); - attachment_pie_menu_map.insert(std::make_pair(pie_index, curiter->first)); - } - } - - // add in requested order to pie menu, inserting separators as necessary - S32 cur_pie_slice = 0; - for (std::multimap::iterator attach_it = attachment_pie_menu_map.begin(); - attach_it != attachment_pie_menu_map.end(); ++attach_it) - { - S32 requested_pie_slice = attach_it->first; - S32 attach_index = attach_it->second; - while (cur_pie_slice < requested_pie_slice) - { - gAttachBodyPartPieMenus[group]->appendSeparator(); - gDetachBodyPartPieMenus[group]->appendSeparator(); - cur_pie_slice++; - } - - LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL); - if (attachment) - { - LLMenuItemCallGL* item = new LLMenuItemCallGL(attachment->getName(), - NULL, object_selected_and_point_valid); - gAttachBodyPartPieMenus[group]->append(item); - item->addListener(gMenuHolder->getListenerByName("Object.AttachToAvatar"), "on_click", attach_index); - gDetachBodyPartPieMenus[group]->append(new LLMenuItemCallGL(attachment->getName(), - &handle_detach_from_avatar, - object_attached, attachment)); - cur_pie_slice++; - } - } - } - } - mMeshValid = TRUE; } @@ -2151,7 +1806,7 @@ void LLVOAvatar::releaseMeshData() // cleanup mesh data for (std::vector::iterator iter = mMeshLOD.begin(); - iter != mMeshLOD.end(); iter++) + iter != mMeshLOD.end(); iter++) { LLViewerJoint* joint = (LLViewerJoint*) *iter; joint->setValid(FALSE, TRUE); @@ -2185,29 +1840,24 @@ void LLVOAvatar::releaseMeshData() //----------------------------------------------------------------------------- // restoreMeshData() //----------------------------------------------------------------------------- +// virtual void LLVOAvatar::restoreMeshData() { + llassert(!isSelf()); LLMemType mt(LLMemType::MTYPE_AVATAR); //llinfos << "Restoring" << llendl; mMeshValid = TRUE; updateJointLODs(); - if (mIsSelf) + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) { - updateAttachmentVisibility(gAgent.getCameraMode()); - } - else - { - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (!attachment->getIsHUDAttachment()) { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (!attachment->getIsHUDAttachment()) - { - attachment->setAttachmentVisibility(TRUE); - } + attachment->setAttachmentVisibility(TRUE); } } @@ -2393,9 +2043,9 @@ void LLVOAvatar::computeBodySize() // LLVOAvatar::processUpdateMessage() //------------------------------------------------------------------------ U32 LLVOAvatar::processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, const EObjectUpdateType update_type, - LLDataPacker *dp) + void **user_data, + U32 block_num, const EObjectUpdateType update_type, + LLDataPacker *dp) { LLMemType mt(LLMemType::MTYPE_AVATAR); @@ -2434,8 +2084,8 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) } } - -// setTEImage +static LLFastTimer::DeclareTimer FTM_AVATAR_UPDATE("Update Avatar"); +static LLFastTimer::DeclareTimer FTM_JOINT_UPDATE("Update Joints"); //------------------------------------------------------------------------ // idleUpdate() @@ -2443,7 +2093,7 @@ S32 LLVOAvatar::setTETexture(const U8 te, const LLUUID& uuid) BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) { LLMemType mt(LLMemType::MTYPE_AVATAR); - LLFastTimer t(LLFastTimer::FTM_AVATAR_UPDATE); + LLFastTimer t(FTM_AVATAR_UPDATE); if (isDead()) { @@ -2462,7 +2112,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // force asynchronous drawable update if(mDrawable.notNull() && !gNoRender) { - LLFastTimer t(LLFastTimer::FTM_JOINT_UPDATE); + LLFastTimer t(FTM_JOINT_UPDATE); if (mIsSitting && getParent()) { @@ -2491,7 +2141,7 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // set alpha flag depending on state //-------------------------------------------------------------------- - if (mIsSelf) + if (isSelf()) { LLViewerObject::idleUpdate(agent, world, time); @@ -2515,8 +2165,8 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) // animate the character // store off last frame's root position to be consistent with camera position LLVector3 root_pos_last = mRoot.getWorldPosition(); - bool detailed_update = updateCharacter(agent); - bool voice_enabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel(); + BOOL detailed_update = updateCharacter(agent); + BOOL voice_enabled = gVoiceClient->getVoiceEnabled( mID ) && gVoiceClient->inProximalChannel(); if (gNoRender) { @@ -2539,13 +2189,13 @@ BOOL LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time) void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) { // disable voice visualizer when in mouselook - mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(mIsSelf && gAgent.cameraMouselook()) ); + mVoiceVisualizer->setVoiceEnabled( voice_enabled && !(isSelf() && gAgent.cameraMouselook()) ); if ( voice_enabled ) { //---------------------------------------------------------------- // Only do gesture triggering for your own avatar, and only when you're in a proximal channel. //---------------------------------------------------------------- - if( mIsSelf ) + if( isSelf() ) { //---------------------------------------------------------------------------------------- // The following takes the voice signal and uses that to trigger gesticulations. @@ -2567,11 +2217,11 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) else { llinfos << "oops - CurrentGesticulationLevel can be only 0, 1, or 2" << llendl; } // this is the call that Karl S. created for triggering gestures from within the code. - gGestureManager.triggerAndReviseString( gestureString ); + LLGestureManager::instance().triggerAndReviseString( gestureString ); } } - } //if( mIsSelf ) + } //if( isSelf() ) //----------------------------------------------------------------------------------------------------------------- // If the avatar is speaking, then the voice amplitude signal is passed to the voice visualizer. @@ -2580,9 +2230,9 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) // Notice the calls to "gAwayTimer.reset()". This resets the timer that determines how long the avatar has been // "away", so that the avatar doesn't lapse into away-mode (and slump over) while the user is still talking. //----------------------------------------------------------------------------------------------------------------- - if ( gVoiceClient->getIsSpeaking( mID ) ) + if (gVoiceClient->getIsSpeaking( mID )) { - if ( ! mVoiceVisualizer->getCurrentlySpeaking() ) + if (!mVoiceVisualizer->getCurrentlySpeaking()) { mVoiceVisualizer->setStartSpeaking(); @@ -2591,7 +2241,7 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) mVoiceVisualizer->setSpeakingAmplitude( gVoiceClient->getCurrentPower( mID ) ); - if( mIsSelf ) + if( isSelf() ) { gAgent.clearAFK(); } @@ -2624,6 +2274,8 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled) }//if ( voiceEnabled ) } +static LLFastTimer::DeclareTimer FTM_ATTACHMENT_UPDATE("Update Attachments"); + void LLVOAvatar::idleUpdateMisc(bool detailed_update) { if (LLVOAvatar::sJointDebug) @@ -2645,7 +2297,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) // update attachments positions if (detailed_update || !sUseImpostors) { - LLFastTimer t(LLFastTimer::FTM_ATTACHMENT_UPDATE); + LLFastTimer t(FTM_ATTACHMENT_UPDATE); for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); iter != mAttachmentPoints.end(); ) { @@ -2654,8 +2306,8 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update) LLViewerObject *attached_object = attachment->getObject(); BOOL visibleAttachment = visible || (attached_object && - !(attached_object->mDrawable->getSpatialBridge() && - attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); + !(attached_object->mDrawable->getSpatialBridge() && + attached_object->mDrawable->getSpatialBridge()->getRadius() < 2.0)); if (visibleAttachment && attached_object && !attached_object->isDead() && attachment->getValid()) { @@ -2751,7 +2403,7 @@ void LLVOAvatar::idleUpdateAppearanceAnimation() } } updateVisualParams(); - if (mIsSelf) + if (isSelf()) { gAgent.sendAgentSetAppearance(); } @@ -2852,7 +2504,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() particle_parameters.mPartData.mStartColor = LLColor4(1, 1, 1, 0.5f); particle_parameters.mPartData.mEndColor = LLColor4(1, 1, 1, 0.0f); particle_parameters.mPartData.mStartScale.mV[VX] = 0.8f; - LLViewerImage* cloud = gImageList.getImageFromFile("cloud-particle.j2c"); + LLViewerTexture* cloud = LLViewerTextureManager::getFetchedTextureFromFile("cloud-particle.j2c"); particle_parameters.mPartImageID = cloud->getID(); particle_parameters.mMaxAge = 0.f; particle_parameters.mPattern = LLPartSysData::LL_PART_SRC_PATTERN_ANGLE_CONE; @@ -2947,16 +2599,17 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) BOOL visible_avatar = isVisible() || mNeedsAnimUpdate; BOOL visible_chat = gSavedSettings.getBOOL("UseChatBubbles") && (mChats.size() || mTyping); BOOL render_name = visible_chat || - (visible_avatar && - ((sRenderName == RENDER_NAME_ALWAYS) || - (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); + (visible_avatar && + ((sRenderName == RENDER_NAME_ALWAYS) || + (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. - if (mIsSelf) + if (isSelf()) { render_name = render_name - && !gAgent.cameraMouselook() - && (visible_chat || !gSavedSettings.getBOOL("RenderNameHideSelf")); + && !gAgent.cameraMouselook() + && (visible_chat || (gSavedSettings.getBOOL("RenderNameShowSelf") + && gSavedSettings.getS32("AvatarNameTagMode") )); } if ( render_name ) @@ -3013,7 +2666,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) new_name = TRUE; } - LLColor4 avatar_name_color = gColors.getColor( "AvatarNameColor" ); + LLColor4 avatar_name_color = LLUIColorTable::instance().getColor( "AvatarNameColor" ); avatar_name_color.setAlpha(alpha); mNameText->setColor(avatar_name_color); @@ -3056,7 +2709,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) BOOL is_busy = mSignaledAnimations.find(ANIM_AGENT_BUSY) != mSignaledAnimations.end(); BOOL is_appearance = mSignaledAnimations.find(ANIM_AGENT_CUSTOMIZE) != mSignaledAnimations.end(); BOOL is_muted; - if (mIsSelf) + if (isSelf()) { is_muted = FALSE; } @@ -3101,7 +2754,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) line += " ("; if (is_away) { - line += "Away"; + line += LLTrans::getString("AvatarAway"); need_comma = TRUE; } if (is_busy) @@ -3110,7 +2763,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { line += ", "; } - line += "Busy"; + line += LLTrans::getString("AvatarBusy"); need_comma = TRUE; } if (is_muted) @@ -3119,7 +2772,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) { line += ", "; } - line += "Muted"; + line += LLTrans::getString("AvatarMuted"); need_comma = TRUE; } line += ")"; @@ -3127,7 +2780,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) if (is_appearance) { line += "\n"; - line += "(Editing Appearance)"; + line += LLTrans::getString("AvatarEditingAppearance"); } mNameAway = is_away; mNameBusy = is_busy; @@ -3155,7 +2808,7 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) std::deque::iterator chat_iter = mChats.begin(); mNameText->clearString(); - LLColor4 new_chat = gColors.getColor( "AvatarNameColor" ); + LLColor4 new_chat = LLUIColorTable::instance().getColor( "AvatarNameColor" ); LLColor4 normal_chat = lerp(new_chat, LLColor4(0.8f, 0.8f, 0.8f, 1.f), 0.7f); LLColor4 old_chat = lerp(normal_chat, LLColor4(0.6f, 0.6f, 0.6f, 1.f), 0.7f); if (mTyping && mChats.size() >= MAX_BUBBLE_CHAT_UTTERANCES) @@ -3169,15 +2822,15 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) LLFontGL::StyleFlags style; switch(chat_iter->mChatType) { - case CHAT_TYPE_WHISPER: - style = LLFontGL::ITALIC; - break; - case CHAT_TYPE_SHOUT: - style = LLFontGL::BOLD; - break; - default: - style = LLFontGL::NORMAL; - break; + case CHAT_TYPE_WHISPER: + style = LLFontGL::ITALIC; + break; + case CHAT_TYPE_SHOUT: + style = LLFontGL::BOLD; + break; + default: + style = LLFontGL::NORMAL; + break; } if (chat_fade_amt < 1.f) { @@ -3202,15 +2855,15 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) S32 dot_count = (llfloor(mTypingTimer.getElapsedTimeF32() * 3.f) + 2) % 3 + 1; switch(dot_count) { - case 1: - mNameText->addLine(".", new_chat); - break; - case 2: - mNameText->addLine("..", new_chat); - break; - case 3: - mNameText->addLine("...", new_chat); - break; + case 1: + mNameText->addLine(".", new_chat); + break; + case 2: + mNameText->addLine("..", new_chat); + break; + case 3: + mNameText->addLine("...", new_chat); + break; } } @@ -3244,75 +2897,12 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) } } +//-------------------------------------------------------------------- +// draw tractor beam when editing objects +//-------------------------------------------------------------------- +// virtual void LLVOAvatar::idleUpdateTractorBeam() { - //-------------------------------------------------------------------- - // draw tractor beam when editing objects - //-------------------------------------------------------------------- - if (!mIsSelf) - { - return; - } - - // This is only done for yourself (maybe it should be in the agent?) - if (!needsRenderBeam() || !mIsBuilt) - { - mBeam = NULL; - } - else if (!mBeam || mBeam->isDead()) - { - // VEFFECT: Tractor Beam - mBeam = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM); - mBeam->setColor(LLColor4U(gAgent.getEffectColor())); - mBeam->setSourceObject(this); - mBeamTimer.reset(); - } - - if (!mBeam.isNull()) - { - LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); - - if (gAgent.mPointAt.notNull()) - { - // get point from pointat effect - mBeam->setPositionGlobal(gAgent.mPointAt->getPointAtPosGlobal()); - mBeam->triggerLocal(); - } - else if (selection->getFirstRootObject() && - selection->getSelectType() != SELECT_TYPE_HUD) - { - LLViewerObject* objectp = selection->getFirstRootObject(); - mBeam->setTargetObject(objectp); - } - else - { - mBeam->setTargetObject(NULL); - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - if (tool->isEditing()) - { - if (tool->getEditingObject()) - { - mBeam->setTargetObject(tool->getEditingObject()); - } - else - { - mBeam->setPositionGlobal(tool->getEditingPointGlobal()); - } - } - else - { - const LLPickInfo& pick = gViewerWindow->getLastPick(); - mBeam->setPositionGlobal(pick.mPosGlobal); - } - - } - if (mBeamTimer.getElapsedTimeF32() > 0.25f) - { - mBeam->setColor(LLColor4U(gAgent.getEffectColor())); - mBeam->setNeedsSendToSim(TRUE); - mBeamTimer.reset(); - } - } } void LLVOAvatar::idleUpdateBelowWater() @@ -3344,16 +2934,6 @@ void LLVOAvatar::slamPosition() BOOL LLVOAvatar::updateCharacter(LLAgent &agent) { LLMemType mt(LLMemType::MTYPE_AVATAR); - // update screen joint size - - if (mScreenp) - { - F32 aspect = LLViewerCamera::getInstance()->getAspect(); - LLVector3 scale(1.f, aspect, 1.f); - mScreenp->setScale(scale); - mScreenp->updateWorldMatrixChildren(); - resetHUDAttachments(); - } // clear debug text mDebugText.clear(); @@ -3386,7 +2966,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) if (gNoRender) { // Hack if we're running drones... - if (mIsSelf) + if (isSelf()) { gAgent.setPositionAgent(getPositionAgent()); } @@ -3415,7 +2995,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // the rest should only be done occasionally for far away avatars //-------------------------------------------------------------------- - if (visible && !mIsSelf && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) + if (visible && !isSelf() && !mIsDummy && sUseImpostors && !mNeedsAnimUpdate && !sFreezeCounter) { F32 impostor_area = 256.f*512.f*(8.125f - LLVOAvatar::sLODFactor*8.f); if (LLMuteList::getInstance()->isMuted(getID())) @@ -3457,7 +3037,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } // change animation time quanta based on avatar render load - if (!mIsSelf && !mIsDummy) + if (!isSelf() && !mIsDummy) { F32 time_quantum = clamp_rescale((F32)sInstances.size(), 10.f, 35.f, 0.f, 0.25f); F32 pixel_area_scale = clamp_rescale(mPixelArea, 100, 5000, 1.f, 0.f); @@ -3526,7 +3106,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) LLVector3d root_pos; LLVector3d ground_under_pelvis; - if (mIsSelf) + if (isSelf()) { gAgent.setPositionAgent(getRenderPosition()); } @@ -3535,8 +3115,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) resolveHeightGlobal(root_pos, ground_under_pelvis, normal); F32 foot_to_ground = (F32) (root_pos.mdV[VZ] - mPelvisToFoot - ground_under_pelvis.mdV[VZ]); - BOOL in_air = ( (!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || - foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); + BOOL in_air = ((!LLWorld::getInstance()->getRegionFromPosGlobal(ground_under_pelvis)) || + foot_to_ground > FOOT_GROUND_COLLISION_TOLERANCE); if (in_air && !mInAir) { @@ -3571,7 +3151,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // more than 90 from the view, if necessary, flip the velocity vector. LLVector3 primDir; - if (mIsSelf) + if (isSelf()) { primDir = agent.getAtAxis() - projected_vec(agent.getAtAxis(), agent.getReferenceUpVector()); primDir.normalize(); @@ -3591,7 +3171,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) } } LLVector3 fwdDir = lerp(primDir, velDir, clamp_rescale(speed, 0.5f, 2.0f, 0.0f, 1.0f)); - if (mIsSelf && gAgent.cameraMouselook()) + if (isSelf() && gAgent.cameraMouselook()) { // make sure fwdDir stays in same general direction as primdir if (gAgent.getFlying()) @@ -3619,18 +3199,10 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) F32 root_roll, root_pitch, root_yaw; root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw); - if (sDebugAvatarRotation) - { - llinfos << "root_roll " << RAD_TO_DEG * root_roll - << " root_pitch " << RAD_TO_DEG * root_pitch - << " root_yaw " << RAD_TO_DEG * root_yaw - << llendl; - } - // When moving very slow, the pelvis is allowed to deviate from the // forward direction to allow it to hold it's position while the torso // and head turn. Once in motion, it must conform however. - BOOL self_in_mouselook = mIsSelf && gAgent.cameraMouselook(); + BOOL self_in_mouselook = isSelf() && gAgent.cameraMouselook(); LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV ); F32 pelvis_rot_threshold = clamp_rescale(speed, 0.1f, 1.0f, PELVIS_ROT_THRESHOLD_SLOW, PELVIS_ROT_THRESHOLD_FAST); @@ -3647,7 +3219,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) // from the forward direction, but if roll or pitch are off even // a little bit we need to correct the rotation. if(root_roll < 1.f * DEG_TO_RAD - && root_pitch < 5.f * DEG_TO_RAD) + && root_pitch < 5.f * DEG_TO_RAD) { // smaller correction vector means pelvis follows prim direction more closely if (!mTurning && angle > pelvis_rot_threshold*0.75f) @@ -3681,7 +3253,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent) fwdDir = leftDir % upDir; LLQuaternion wQv( fwdDir, leftDir, upDir ); - if (mIsSelf && mTurning) + if (isSelf() && mTurning) { if ((fwdDir % pelvisDir) * upDir > 0.f) { @@ -3890,9 +3462,9 @@ void LLVOAvatar::updateVisibility() visible = FALSE; } - if( mIsSelf ) + if(isSelf()) { - if( !gAgent.areWearablesLoaded()) + if (!gAgentWearables.areWearablesLoaded()) { visible = FALSE; } @@ -3997,27 +3569,6 @@ void LLVOAvatar::updateVisibility() mVisible = visible; } -//------------------------------------------------------------------------ -// needsRenderBeam() -//------------------------------------------------------------------------ -BOOL LLVOAvatar::needsRenderBeam() -{ - if (gNoRender) - { - return FALSE; - } - LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); - - BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); - if (LLToolGrab::getInstance()->getEditingObject() && - LLToolGrab::getInstance()->getEditingObject()->isAttachment()) - { - // don't render selection beam on hud objects - is_touching_or_grabbing = FALSE; - } - return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); -} - //----------------------------------------------------------------------------- // renderSkinned() //----------------------------------------------------------------------------- @@ -4051,7 +3602,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry(); } - if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry(); mMeshLOD[MESH_ID_HEAD]->updateJointGeometry(); @@ -4101,7 +3652,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) return num_indices; } - if (mIsSelf && !gAgent.needsRenderAvatar()) + if (isSelf() && !gAgent.needsRenderAvatar()) { return num_indices; } @@ -4151,17 +3702,10 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) if (pass == AVATAR_RENDER_PASS_SINGLE) { - const bool should_alpha_mask = mHasBakedHair && isTextureDefined(TEX_HEAD_BAKED) && isTextureDefined(TEX_UPPER_BAKED) - && isTextureDefined(TEX_LOWER_BAKED) - && mBakedTextureData[BAKED_HEAD].mIsLoaded - && mBakedTextureData[BAKED_UPPER].mIsLoaded && mBakedTextureData[BAKED_LOWER].mIsLoaded - && mBakedTextureData[BAKED_HEAD].mIsUsed - && mBakedTextureData[BAKED_UPPER].mIsUsed && mBakedTextureData[BAKED_LOWER].mIsUsed - && !LLDrawPoolAlpha::sShowDebugAlpha // Don't alpha mask if "Highlight Transparent" checked - && !(isSelf() && gAgent.cameraCustomizeAvatar()); // don't alpha mask if in customize mode + const bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha; // Don't alpha mask if "Highlight Transparent" checked LLGLState test(GL_ALPHA_TEST, should_alpha_mask); - + if (should_alpha_mask) { gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.5f); @@ -4170,7 +3714,7 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass) BOOL first_pass = TRUE; if (!LLDrawPoolAvatar::sSkipOpaque) { - if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy) { @@ -4221,7 +3765,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); } - if (!mIsSelf || gAgent.needsRenderHead() || LLPipeline::sShadowRender) + if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender) { if (LLPipeline::sImpostorRender) { @@ -4235,7 +3779,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass) } // Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair) // TODO: 1.25 will be able to switch this logic back to calling isTextureVisible(); - if (getTEImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) + if (getImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha) { num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy); first_pass = FALSE; @@ -4261,7 +3805,7 @@ U32 LLVOAvatar::renderRigid() return 0; } - if (mIsSelf && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) + if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) { return 0; } @@ -4274,10 +3818,7 @@ U32 LLVOAvatar::renderRigid() if (isTextureVisible(TEX_EYES_BAKED) || mIsDummy) { // If the meshes need to be drawn, enable alpha masking but not blending - bool should_alpha_mask = mHasBakedHair - && mBakedTextureData[BAKED_EYES].mIsLoaded - && mBakedTextureData[BAKED_EYES].mIsUsed - && !(isSelf() && gAgent.cameraCustomizeAvatar()); + bool should_alpha_mask = mSupportsAlphaLayers && !LLDrawPoolAlpha::sShowDebugAlpha; LLGLState test(GL_ALPHA_TEST, should_alpha_mask); @@ -4304,7 +3845,7 @@ U32 LLVOAvatar::renderFootShadows() return 0; } - if (mIsSelf && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) + if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead())) { return 0; } @@ -4316,7 +3857,7 @@ U32 LLVOAvatar::renderFootShadows() // Don't render foot shadows if your lower body is completely invisible. // (non-humanoid avatars rule!) - if (! isTextureVisible(TEX_LOWER_BAKED)) + if (!isTextureVisible(TEX_LOWER_BAKED)) { return 0; } @@ -4334,7 +3875,7 @@ U32 LLVOAvatar::renderFootShadows() LLGLDepthTest test(GL_TRUE, GL_FALSE); //render foot shadows LLGLEnable blend(GL_BLEND); - gGL.getTexUnit(0)->bind(mShadowImagep.get()); + gGL.getTexUnit(0)->bind(mShadowImagep); glColor4fv(mShadow0Facep->getRenderColor().mV); mShadow0Facep->renderIndexed(foot_mask); glColor4fv(mShadow1Facep->getRenderColor().mV); @@ -4391,7 +3932,7 @@ void LLVOAvatar::updateTextures(LLAgent &agent) return; } - if( mIsSelf ) + if( isSelf() ) { render_avatar = TRUE; } @@ -4400,66 +3941,32 @@ void LLVOAvatar::updateTextures(LLAgent &agent) render_avatar = isVisible() && !mCulled; } - std::vector layer_baked; - for (U32 i = 0; i < mBakedTextureData.size(); i++) + std::vector layer_baked; + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - layer_baked.push_back(isTextureDefined(mBakedTextureData[i].mTextureIndex)); + layer_baked.push_back(isTextureDefined(mBakedTextureDatas[i].mTextureIndex)); // bind the texture so that they'll be decoded slightly // inefficient, we can short-circuit this if we have to - if( render_avatar && !gGLManager.mIsDisabled ) + if (render_avatar && !gGLManager.mIsDisabled) { - if (layer_baked[i] && !mBakedTextureData[i].mIsLoaded) + if (layer_baked[i] && !mBakedTextureDatas[i].mIsLoaded) { - gGL.getTexUnit(0)->bind(getTEImage( mBakedTextureData[i].mTextureIndex )); + gGL.getTexUnit(0)->bind(getImage( mBakedTextureDatas[i].mTextureIndex )); } } } - /* - // JAMESDEBUG - if (mIsSelf) - { - S32 null_count = 0; - S32 default_count = 0; - for (U32 i = 0; i < getNumTEs(); i++) - { - const LLTextureEntry* te = getTE(i); - if (te) - { - if (te->getID() == LLUUID::null) - { - null_count++; - } - else if (te->getID() == IMG_DEFAULT_AVATAR) - { - default_count++; - } - } - } - llinfos << "JAMESDEBUG my avatar TE null " << null_count << " default " << default_count << llendl; - } - */ - mMaxPixelArea = 0.f; mMinPixelArea = 99999999.f; mHasGrey = FALSE; // debug for (U32 index = 0; index < getNumTEs(); index++) { - LLViewerImage *imagep = getTEImage(index); + LLViewerFetchedTexture *imagep = LLViewerTextureManager::staticCastToFetchedTexture(getImage(index), TRUE); if (imagep) { - // Debugging code - maybe non-self avatars are downloading textures? - //llinfos << "avatar self " << mIsSelf << " tex " << i - // << " decode " << imagep->getDecodePriority() - // << " boost " << boost_avatar - // << " size " << imagep->getWidth() << "x" << imagep->getHeight() - // << " discard " << imagep->getDiscardLevel() - // << " desired " << imagep->getDesiredDiscardLevel() - // << llendl; - const LLTextureEntry *te = getTE(index); - F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); - S32 boost_level = mIsSelf ? LLViewerImage::BOOST_AVATAR_BAKED_SELF : LLViewerImage::BOOST_AVATAR_BAKED; + const F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); + const S32 boost_level = getAvatarBakedBoostLevel(); // Spam if this is a baked texture, not set to default image, without valid host info if (isIndexBakedTexture((ETextureIndex)index) @@ -4467,15 +3974,15 @@ void LLVOAvatar::updateTextures(LLAgent &agent) && !imagep->getTargetHost().isOk()) { LL_WARNS_ONCE("Texture") << "LLVOAvatar::updateTextures No host for texture " - << imagep->getID() << " for avatar " - << (mIsSelf ? "" : getID().asString()) - << " on host " << getRegion()->getHost() << llendl; + << imagep->getID() << " for avatar " + << (isSelf() ? "" : getID().asString()) + << " on host " << getRegion()->getHost() << llendl; } /* switch(index) case TEX_HEAD_BODYPAINT: addLocalTextureStats( LOCTEX_HEAD_BODYPAINT, imagep, texel_area_ratio, render_avatar, head_baked ); */ - const LLVOAvatarDictionary::TextureDictionaryEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)index); + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture((ETextureIndex)index); if (texture_dict->mIsUsedByBakedTexture) { const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; @@ -4506,42 +4013,15 @@ void LLVOAvatar::updateTextures(LLAgent &agent) } -void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerImage* imagep, - F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked ) +void LLVOAvatar::addLocalTextureStats( ETextureIndex idx, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) { - if (!isIndexLocalTexture(idx)) return; - - if (!covered_by_baked && render_avatar) // render_avatar is always true if mIsSelf - { - if (getLocalTextureID(idx) != IMG_DEFAULT_AVATAR) - { - F32 desired_pixels; - if( mIsSelf ) - { - desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_SELF ); - imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR_SELF); - } - else - { - desired_pixels = llmin(mPixelArea, (F32)TEX_IMAGE_AREA_OTHER ); - imagep->setBoostLevel(LLViewerImage::BOOST_AVATAR); - } - imagep->addTextureStats( desired_pixels / texel_area_ratio ); - if (imagep->getDiscardLevel() < 0) - { - mHasGrey = TRUE; // for statistics gathering - } - } - else - { - // texture asset is missing - mHasGrey = TRUE; // for statistics gathering - } - } + // No local texture stats for non-self avatars + return; } -void LLVOAvatar::addBakedTextureStats( LLViewerImage* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) +void LLVOAvatar::addBakedTextureStats( LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level) { mMaxPixelArea = llmax(pixel_area, mMaxPixelArea); mMinPixelArea = llmin(pixel_area, mMinPixelArea); @@ -4549,6 +4029,29 @@ void LLVOAvatar::addBakedTextureStats( LLViewerImage* imagep, F32 pixel_area, F3 imagep->setBoostLevel(boost_level); } +//virtual +void LLVOAvatar::setImage(const U8 te, LLViewerTexture *imagep) +{ + setTEImage(te, imagep); +} + +//virtual +LLViewerTexture* LLVOAvatar::getImage(const U8 te) const +{ + return getTEImage(te); +} +//virtual +const LLTextureEntry* LLVOAvatar::getTexEntry(const U8 te_num) const +{ + return getTE(te_num); +} + +//virtual +void LLVOAvatar::setTexEntry(const U8 index, const LLTextureEntry &te) +{ + setTE(index, te); +} + //----------------------------------------------------------------------------- // resolveHeight() //----------------------------------------------------------------------------- @@ -4690,7 +4193,7 @@ void LLVOAvatar::processAnimationStateChanges() } // clear source information for animations which have been stopped - if (mIsSelf) + if (isSelf()) { AnimSourceIterator source_it = mAnimationSources.begin(); @@ -4732,7 +4235,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL { // RN: uncomment this to play on typing sound at fixed volume once sound engine is fixed // to support both spatialized and non-spatialized instances of the same sound - //if (mIsSelf) + //if (isSelf()) //{ // gAudiop->triggerSound(LLUUID(gSavedSettings.getString("UISndTyping")), 1.0f, LLAudioEngine::AUDIO_TYPE_UI); //} @@ -4746,7 +4249,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL } else if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) { - mIsSitting = TRUE; + sitDown(TRUE); } @@ -4763,7 +4266,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL { if (anim_id == ANIM_AGENT_SIT_GROUND_CONSTRAINED) { - mIsSitting = FALSE; + sitDown(FALSE); } stopMotion(anim_id); result = TRUE; @@ -4775,7 +4278,7 @@ BOOL LLVOAvatar::processSingleAnimationStateChange( const LLUUID& anim_id, BOOL //----------------------------------------------------------------------------- // isAnyAnimationSignaled() //----------------------------------------------------------------------------- -BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) +BOOL LLVOAvatar::isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const { for (S32 i = 0; i < num_anims; i++) { @@ -4818,7 +4321,7 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) } } - if (mIsSelf && id == ANIM_AGENT_AWAY) + if (isSelf() && id == ANIM_AGENT_AWAY) { gAgent.setAFK(); } @@ -4831,7 +4334,7 @@ BOOL LLVOAvatar::startMotion(const LLUUID& id, F32 time_offset) //----------------------------------------------------------------------------- BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) { - if (mIsSelf) + if (isSelf()) { gAgent.onAnimStop(id); } @@ -4851,25 +4354,9 @@ BOOL LLVOAvatar::stopMotion(const LLUUID& id, BOOL stop_immediate) //----------------------------------------------------------------------------- // stopMotionFromSource() //----------------------------------------------------------------------------- +// virtual void LLVOAvatar::stopMotionFromSource(const LLUUID& source_id) { - if (!mIsSelf) - { - return; - } - AnimSourceIterator motion_it; - - for(motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end();) - { - gAgent.sendAnimationRequest( motion_it->second, ANIM_REQUEST_STOP ); - mAnimationSources.erase(motion_it++); - } - - LLViewerObject* object = gObjectList.findObject(source_id); - if (object) - { - object->mFlags &= ~FLAGS_ANIM_SOURCE; - } } //----------------------------------------------------------------------------- @@ -4917,7 +4404,7 @@ S32 LLVOAvatar::getCollisionVolumeID(std::string &name) //----------------------------------------------------------------------------- // addDebugText() //----------------------------------------------------------------------------- - void LLVOAvatar::addDebugText(const std::string& text) +void LLVOAvatar::addDebugText(const std::string& text) { mDebugText.append(1, '\n'); mDebugText.append(text); @@ -4937,15 +4424,7 @@ const LLUUID& LLVOAvatar::getID() // RN: avatar joints are multi-rooted to include screen-based attachments LLJoint *LLVOAvatar::getJoint( const std::string &name ) { - LLJoint* jointp = NULL; - if (mScreenp) - { - jointp = mScreenp->findJoint(name); - } - if (!jointp) - { - jointp = mRoot.findJoint(name); - } + LLJoint* jointp = mRoot.findJoint(name); return jointp; } @@ -5075,8 +4554,7 @@ LLVector3 LLVOAvatar::getPosAgentFromGlobal(const LLVector3d &position) //----------------------------------------------------------------------------- BOOL LLVOAvatar::allocateCharacterJoints( U32 num ) { - delete [] mSkeleton; - mSkeleton = NULL; + deleteAndClearArray(mSkeleton); mNumJoints = 0; mSkeleton = new LLViewerJoint[num]; @@ -5100,8 +4578,7 @@ BOOL LLVOAvatar::allocateCharacterJoints( U32 num ) //----------------------------------------------------------------------------- BOOL LLVOAvatar::allocateCollisionVolumes( U32 num ) { - delete [] mCollisionVolumes; - mCollisionVolumes = NULL; + deleteAndClearArray(mCollisionVolumes); mNumCollisionVolumes = 0; mCollisionVolumes = new LLViewerJointCollisionVolume[num]; @@ -5131,22 +4608,20 @@ LLJoint *LLVOAvatar::getCharacterJoint( U32 num ) //----------------------------------------------------------------------------- // requestStopMotion() //----------------------------------------------------------------------------- +// virtual void LLVOAvatar::requestStopMotion( LLMotion* motion ) { // Only agent avatars should handle the stop motion notifications. - if ( mIsSelf ) - { - // Notify agent that motion has stopped - gAgent.requestStopMotion( motion ); - } } //----------------------------------------------------------------------------- // loadAvatar() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar"); + BOOL LLVOAvatar::loadAvatar() { -// LLFastTimer t(LLFastTimer::FTM_LOAD_AVATAR); +// LLFastTimer t(FTM_LOAD_AVATAR); // avatar_skeleton.xml if( !buildSkeleton(sAvatarSkeletonInfo) ) @@ -5217,62 +4692,55 @@ BOOL LLVOAvatar::loadAvatar() if (sAvatarXmlInfo->mLayerInfoList.empty()) { llwarns << "avatar file: missing node" << llendl; + return FALSE; } - else + + if (sAvatarXmlInfo->mMorphMaskInfoList.empty()) { - LLVOAvatarXmlInfo::layer_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mLayerInfoList.begin(); - iter != sAvatarXmlInfo->mLayerInfoList.end(); iter++) + llwarns << "avatar file: missing node" << llendl; + return FALSE; + } + + // avatar_lad.xml : + for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin(); + iter != sAvatarXmlInfo->mMorphMaskInfoList.end(); + iter++) + { + LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter; + + EBakedTextureIndex baked = LLVOAvatarDictionary::findBakedByRegionName(info->mRegion); + if (baked != BAKED_NUM_INDICES) { - LLTexLayerSetInfo *info = *iter; - LLTexLayerSet* layer_set = new LLTexLayerSet( this ); - if (!layer_set->setInfo(info)) + LLPolyMorphTarget *morph_param; + const std::string *name = &info->mName; + morph_param = (LLPolyMorphTarget *)(getVisualParam(name->c_str())); + if (morph_param) { - stop_glerror(); - delete layer_set; - llwarns << "avatar file: layer_set->parseData() failed" << llendl; - return FALSE; - } - bool found_baked_entry = false; - for (LLVOAvatarDictionary::baked_map_t::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - baked_iter++) - { - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = baked_iter->second; - if (layer_set->isBodyRegion(baked_dict->mName)) - { - mBakedTextureData[baked_iter->first].mTexLayerSet = layer_set; - found_baked_entry = true; - break; - } - } - if (!found_baked_entry) - { - llwarns << " has invalid body_region attribute" << llendl; - delete layer_set; - return FALSE; + BOOL invert = info->mInvert; + addMaskedMorph(baked, morph_param, invert, info->mLayer); } } + } + + loadLayersets(); // avatar_lad.xml : + for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin(); + iter != sAvatarXmlInfo->mDriverInfoList.end(); + iter++) { - LLVOAvatarXmlInfo::driver_info_list_t::iterator iter; - for (iter = sAvatarXmlInfo->mDriverInfoList.begin(); - iter != sAvatarXmlInfo->mDriverInfoList.end(); iter++) + LLDriverParamInfo *info = *iter; + LLDriverParam* driver_param = new LLDriverParam( this ); + if (driver_param->setInfo(info)) { - LLDriverParamInfo *info = *iter; - LLDriverParam* driver_param = new LLDriverParam( this ); - if (driver_param->setInfo(info)) - { - addVisualParam( driver_param ); - } - else - { - delete driver_param; - llwarns << "avatar file: driver_param->parseData() failed" << llendl; - return FALSE; - } + addVisualParam( driver_param ); + } + else + { + delete driver_param; + llwarns << "avatar file: driver_param->parseData() failed" << llendl; + return FALSE; } } @@ -5287,7 +4755,7 @@ BOOL LLVOAvatar::loadSkeletonNode () mRoot.addChild( &mSkeleton[0] ); for (std::vector::iterator iter = mMeshLOD.begin(); - iter != mMeshLOD.end(); iter++) + iter != mMeshLOD.end(); iter++) { LLViewerJoint *joint = (LLViewerJoint *) *iter; joint->mUpdateXform = FALSE; @@ -5438,12 +4906,12 @@ BOOL LLVOAvatar::loadMeshNodes() switch(lod) case 0: mesh = &mHairMesh0; */ - for (LLVOAvatarDictionary::mesh_map_t::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); + for (LLVOAvatarDictionary::Meshes::const_iterator mesh_iter = LLVOAvatarDictionary::getInstance()->getMeshes().begin(); mesh_iter != LLVOAvatarDictionary::getInstance()->getMeshes().end(); mesh_iter++) { const EMeshIndex mesh_index = mesh_iter->first; - const LLVOAvatarDictionary::MeshDictionaryEntry *mesh_dict = mesh_iter->second; + const LLVOAvatarDictionary::MeshEntry *mesh_dict = mesh_iter->second; if (type.compare(mesh_dict->mName) == 0) { mesh_id = mesh_index; @@ -5538,6 +5006,23 @@ BOOL LLVOAvatar::loadMeshNodes() return TRUE; } +//----------------------------------------------------------------------------- +// loadLayerSets() +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::loadLayersets() +{ + BOOL success = TRUE; + for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin(); + layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); + layerset_iter++) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + LLTexLayerSetInfo *layerset_info = *layerset_iter; + layerset_info->createVisualParams(this); + } + return success; +} + //----------------------------------------------------------------------------- // updateVisualParams() //----------------------------------------------------------------------------- @@ -5602,9 +5087,9 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent) } // We always want to look good to ourselves - if( mIsSelf ) + if( isSelf() ) { - mPixelArea = llmax( mPixelArea, F32(TEX_IMAGE_SIZE_SELF / 16) ); + mPixelArea = llmax( mPixelArea, F32(getTexImageSize() / 16) ); } } @@ -5620,7 +5105,7 @@ BOOL LLVOAvatar::updateJointLODs() F32 area_scale = 0.16f; { - if (mIsSelf) + if (isSelf()) { if(gAgent.cameraCustomizeAvatar() || gAgent.cameraMouselook()) { @@ -5689,9 +5174,10 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline) //----------------------------------------------------------------------------- // updateGeometry() //----------------------------------------------------------------------------- +static LLFastTimer::DeclareTimer FTM_UPDATE_AVATAR("Update Avatar"); BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_AVATAR); + LLFastTimer ftm(FTM_UPDATE_AVATAR); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_AVATAR))) { return TRUE; @@ -5736,7 +5222,7 @@ void LLVOAvatar::updateShadowFaces() sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f); LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f); - if (mShadowImagep->getHasGLTexture()) + if (mShadowImagep->hasValidGLTexture()) { LLVector3 normal; LLVector3d shadow_pos; @@ -5749,7 +5235,7 @@ void LLVOAvatar::updateShadowFaces() // this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now // but we make an explicit ray trace call in expectation of future improvements resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), - gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); + gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos); foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ]; @@ -5758,7 +5244,7 @@ void LLVOAvatar::updateShadowFaces() // Render sprite sprite.setNormal(normal); - if (mIsSelf && gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) + if (isSelf() && gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) { sprite.setColor(0.f, 0.f, 0.f, 0.f); } @@ -5782,7 +5268,7 @@ void LLVOAvatar::updateShadowFaces() // this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now // but we make an explicit ray trace call in expectation of future improvements resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), - gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); + gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal); shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos); foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ]; @@ -5791,7 +5277,7 @@ void LLVOAvatar::updateShadowFaces() // Render sprite sprite.setNormal(normal); - if (mIsSelf && gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) + if (isSelf() && gAgent.getCameraMode() == CAMERA_MODE_MOUSELOOK) { sprite.setColor(0.f, 0.f, 0.f, 0.f); } @@ -5816,9 +5302,9 @@ void LLVOAvatar::updateShadowFaces() //----------------------------------------------------------------------------- void LLVOAvatar::updateSexDependentLayerSets( BOOL set_by_user ) { - invalidateComposite( mBakedTextureData[BAKED_HEAD].mTexLayerSet, set_by_user ); - invalidateComposite( mBakedTextureData[BAKED_UPPER].mTexLayerSet, set_by_user ); - invalidateComposite( mBakedTextureData[BAKED_LOWER].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, set_by_user ); updateMeshTextures(); } @@ -5838,33 +5324,13 @@ void LLVOAvatar::hideSkirt() mMeshLOD[MESH_ID_SKIRT]->setVisible(FALSE, TRUE); } - -//----------------------------------------------------------------------------- -// requestLayerSetUpdate() -//----------------------------------------------------------------------------- -void LLVOAvatar::requestLayerSetUpdate(ETextureIndex index ) -{ - /* switch(index) - case LOCTEX_UPPER_BODYPAINT: - case LOCTEX_UPPER_SHIRT: - if( mUpperBodyLayerSet ) - mUpperBodyLayerSet->requestUpdate(); */ - const LLVOAvatarDictionary::TextureDictionaryEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) - return; - const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; - if (mBakedTextureData[baked_index].mTexLayerSet) - { - mBakedTextureData[baked_index].mTexLayerSet->requestUpdate(); - } -} - -void LLVOAvatar::setParent(LLViewerObject* parent) +BOOL LLVOAvatar::setParent(LLViewerObject* parent) { + BOOL ret ; if (parent == NULL) { getOffObject(); - LLViewerObject::setParent(parent); + ret = LLViewerObject::setParent(parent); if (isSelf()) { gAgent.resetCamera(); @@ -5872,9 +5338,13 @@ void LLVOAvatar::setParent(LLViewerObject* parent) } else { - LLViewerObject::setParent(parent); - sitOnObject(parent); + ret = LLViewerObject::setParent(parent); + if(ret) + { + sitOnObject(parent); + } } + return ret ; } void LLVOAvatar::addChild(LLViewerObject *childp) @@ -5913,13 +5383,13 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi //----------------------------------------------------------------------------- // attachObject() //----------------------------------------------------------------------------- -BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) +LLViewerJointAttachment *LLVOAvatar::attachObject(LLViewerObject *viewer_object) { LLViewerJointAttachment* attachment = getTargetAttachmentPoint(viewer_object); if (!attachment || !attachment->addObject(viewer_object)) { - return FALSE; + return 0; } if (viewer_object->isSelected()) @@ -5928,16 +5398,7 @@ BOOL LLVOAvatar::attachObject(LLViewerObject *viewer_object) LLSelectMgr::getInstance()->updatePointAt(); } - if (mIsSelf) - { - updateAttachmentVisibility(gAgent.getCameraMode()); - - // Then make sure the inventory is in sync with the avatar. - gInventory.addChangedMask( LLInventoryObserver::LABEL, attachment->getItemID() ); - gInventory.notifyObservers(); - } - - return TRUE; + return attachment; } //----------------------------------------------------------------------------- @@ -5995,7 +5456,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) { LLUUID item_id = attachment->getItemID(); attachment->removeObject(viewer_object); - if (mIsSelf) + if (isSelf()) { // the simulator should automatically handle // permission revocation @@ -6017,7 +5478,7 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) } lldebugs << "Detaching object " << viewer_object->mID << " from " << attachment->getName() << llendl; - if (mIsSelf) + if (isSelf()) { // Then make sure the inventory is in sync with the avatar. gInventory.addChangedMask(LLInventoryObserver::LABEL, item_id); @@ -6027,15 +5488,45 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object) } } - return FALSE; } +//----------------------------------------------------------------------------- +// sitDown() +//----------------------------------------------------------------------------- +void LLVOAvatar::sitDown(BOOL bSitting) +{ + mIsSitting = bSitting; + if (isSelf()) + { + // Update Movement Controls according to own Sitting mode + LLFloaterMove::setSittingMode(bSitting); + } +} + //----------------------------------------------------------------------------- // sitOnObject() //----------------------------------------------------------------------------- void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) { + if (isSelf()) + { + // Might be first sit + LLFirstUse::useSit(); + + gAgent.setFlying(FALSE); + gAgent.setThirdPersonHeadOffset(LLVector3::zero); + //interpolate to new camera position + gAgent.startCameraAnimation(); + // make sure we are not trying to autopilot + gAgent.stopAutoPilot(); + gAgent.setupSitCamera(); + if (gAgent.getForceMouselook()) + { + gAgent.changeCameraToMouselook(); + } + } + if (mDrawable.isNull()) { return; @@ -6050,27 +5541,13 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object) mDrawable->mXform.setRotation(mDrawable->getWorldRotation() * inv_obj_rot); gPipeline.markMoved(mDrawable, TRUE); - mIsSitting = TRUE; + sitDown(TRUE); mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject mRoot.setPosition(getPosition()); mRoot.updateWorldMatrixChildren(); stopMotion(ANIM_AGENT_BODY_NOISE); - if (mIsSelf) - { - // Might be first sit - LLFirstUse::useSit(); - - gAgent.setFlying(FALSE); - gAgent.setThirdPersonHeadOffset(LLVector3::zero); - //interpolate to new camera position - gAgent.startCameraAnimation(); - // make sure we are not trying to autopilot - gAgent.stopAutoPilot(); - gAgent.setupSitCamera(); - if (gAgent.mForceMouselook) gAgent.changeCameraToMouselook(); - } } //----------------------------------------------------------------------------- @@ -6111,7 +5588,8 @@ void LLVOAvatar::getOffObject() gPipeline.markMoved(mDrawable, TRUE); - mIsSitting = FALSE; + sitDown(FALSE); + mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject mRoot.setPosition(cur_position_world); mRoot.setRotation(cur_rotation_world); @@ -6119,7 +5597,7 @@ void LLVOAvatar::getOffObject() startMotion(ANIM_AGENT_BODY_NOISE); - if (mIsSelf) + if (isSelf()) { LLQuaternion av_rot = gAgent.getFrameAgent().getQuaternion(); LLQuaternion obj_rot = sit_object ? sit_object->getRenderRotation() : LLQuaternion::DEFAULT; @@ -6160,146 +5638,24 @@ LLVOAvatar* LLVOAvatar::findAvatarFromAttachment( LLViewerObject* obj ) return NULL; } -//----------------------------------------------------------------------------- -// isWearingAttachment() -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isWearingAttachment( const LLUUID& inv_item_id ) +// warning: order(N) not order(1) +S32 LLVOAvatar::getAttachmentCount() { - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) - { - return TRUE; - } - } - return FALSE; + S32 count = mAttachmentPoints.size(); + return count; } -//----------------------------------------------------------------------------- -// getWornAttachment() -//----------------------------------------------------------------------------- -LLViewerObject* LLVOAvatar::getWornAttachment( const LLUUID& inv_item_id ) +LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) const { - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) - { - return attachment->getObject(); - } - } - return NULL; -} - -const std::string LLVOAvatar::getAttachedPointName(const LLUUID& inv_item_id) -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if( attachment->getItemID() == inv_item_id ) - { - return attachment->getName(); - } - } - - return LLStringUtil::null; -} - - -//----------------------------------------------------------------------------- -// static -// onLocalTextureLoaded() -//----------------------------------------------------------------------------- - -void LLVOAvatar::onLocalTextureLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) -{ - //llinfos << "onLocalTextureLoaded: " << src_vi->getID() << llendl; - - const LLUUID& src_id = src_vi->getID(); - LLAvatarTexData *data = (LLAvatarTexData *)userdata; - if (success) - { - LLVOAvatar *self = (LLVOAvatar *)gObjectList.findObject(data->mAvatarID); - if (self) - { - ETextureIndex index = data->mIndex; - if (!self->isIndexLocalTexture(index)) return; - LocalTextureData &local_tex_data = self->mLocalTextureData[index]; - if(!local_tex_data.mIsBakedReady && - local_tex_data.mImage.notNull() && - (local_tex_data.mImage->getID() == src_id) && - discard_level < local_tex_data.mDiscard) - { - local_tex_data.mDiscard = discard_level; - if ( self->isSelf() && !gAgent.cameraCustomizeAvatar() ) - { - self->requestLayerSetUpdate( index ); - } - else if( self->isSelf() && gAgent.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } - self->updateMeshTextures(); - } - } - } - else if (final) - { - LLVOAvatar *self = (LLVOAvatar *)gObjectList.findObject(data->mAvatarID); - if (self) - { - ETextureIndex index = data->mIndex; - if (!self->isIndexLocalTexture(index)) return; - LocalTextureData &local_tex_data = self->mLocalTextureData[index]; - // Failed: asset is missing - if(!local_tex_data.mIsBakedReady && - local_tex_data.mImage.notNull() && - local_tex_data.mImage->getID() == src_id) - { - local_tex_data.mDiscard = 0; - self->requestLayerSetUpdate( index ); - self->updateMeshTextures(); - } - } - } - - if( final || !success ) - { - delete data; - } -} - -void LLVOAvatar::updateComposites() -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - if ( mBakedTextureData[i].mTexLayerSet - && ((i != BAKED_SKIRT) || isWearingWearableType( WT_SKIRT )) ) - { - mBakedTextureData[i].mTexLayerSet->updateComposite(); - } - } -} - -LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) -{ - if( color_name=="skin_color" && mTexSkinColor ) + if (color_name=="skin_color" && mTexSkinColor) { return mTexSkinColor->getColor(); } - else - if( color_name=="hair_color" && mTexHairColor ) + else if(color_name=="hair_color" && mTexHairColor) { return mTexHairColor->getColor(); } - if( color_name=="eye_color" && mTexEyeColor ) + if(color_name=="eye_color" && mTexEyeColor) { return mTexEyeColor->getColor(); } @@ -6310,282 +5666,64 @@ LLColor4 LLVOAvatar::getGlobalColor( const std::string& color_name ) } } - +// virtual void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL set_by_user ) { - if( !layerset || !layerset->getUpdatesEnabled() ) - { - return; - } - - /* Debug spam. JC - const char* layer_name = ""; - if (layerset == mHeadLayerSet) - { - layer_name = "head"; - } - else if (layerset == mUpperBodyLayerSet) - { - layer_name = "upperbody"; - } - else if (layerset == mLowerBodyLayerSet) - { - layer_name = "lowerbody"; - } - else if (layerset == mEyesLayerSet) - { - layer_name = "eyes"; - } - else if (layerset == mHairLayerSet) - { - layer_name = "hair"; - } - else if (layerset == mSkirtLayerSet) - { - layer_name = "skirt"; - } - else - { - layer_name = "unknown"; - } - llinfos << "LLVOAvatar::invalidComposite() " << layer_name << llendl; - */ - - layerset->requestUpdate(); - - if( set_by_user ) - { - llassert( mIsSelf ); - - ETextureIndex baked_te = getBakedTE( layerset ); - setTEImage( baked_te, gImageList.getImage(IMG_DEFAULT_AVATAR) ); - layerset->requestUpload(); - } } void LLVOAvatar::invalidateAll() { - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - invalidateComposite(mBakedTextureData[i].mTexLayerSet, TRUE); - } - updateMeshTextures(); } -void LLVOAvatar::onGlobalColorChanged( LLTexGlobalColor* global_color, BOOL set_by_user ) +// virtual +void LLVOAvatar::setCompositeUpdatesEnabled( BOOL b ) { - if( global_color == mTexSkinColor ) +} + +void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL set_by_user ) +{ + if (global_color == mTexSkinColor) { -// llinfos << "invalidateComposite cause: onGlobalColorChanged( skin color )" << llendl; - invalidateComposite( mBakedTextureData[BAKED_HEAD].mTexLayerSet, set_by_user ); - invalidateComposite( mBakedTextureData[BAKED_UPPER].mTexLayerSet, set_by_user ); - invalidateComposite( mBakedTextureData[BAKED_LOWER].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_UPPER].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_LOWER].mTexLayerSet, set_by_user ); } - else - if( global_color == mTexHairColor ) + else if (global_color == mTexHairColor) { -// llinfos << "invalidateComposite cause: onGlobalColorChanged( hair color )" << llendl; - invalidateComposite( mBakedTextureData[BAKED_HEAD].mTexLayerSet, set_by_user ); - invalidateComposite( mBakedTextureData[BAKED_HAIR].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_HEAD].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_HAIR].mTexLayerSet, set_by_user ); // ! BACKWARDS COMPATIBILITY ! // Fix for dealing with avatars from viewers that don't bake hair. - if (!isTextureDefined(mBakedTextureData[BAKED_HAIR].mTextureIndex)) + if (!isTextureDefined(mBakedTextureDatas[BAKED_HAIR].mTextureIndex)) { LLColor4 color = mTexHairColor->getColor(); - for (U32 i = 0; i < mBakedTextureData[BAKED_HAIR].mMeshes.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) { - mBakedTextureData[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); } } - } - else - if( global_color == mTexEyeColor ) + } + else if (global_color == mTexEyeColor) { // llinfos << "invalidateComposite cause: onGlobalColorChanged( eyecolor )" << llendl; - invalidateComposite( mBakedTextureData[BAKED_EYES].mTexLayerSet, set_by_user ); + invalidateComposite( mBakedTextureDatas[BAKED_EYES].mTexLayerSet, set_by_user ); } updateMeshTextures(); } -void LLVOAvatar::forceBakeAllTextures(bool slam_for_debug) -{ - llinfos << "TAT: forced full rebake. " << llendl; - - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - ETextureIndex baked_index = mBakedTextureData[i].mTextureIndex; - LLTexLayerSet* layer_set = getLayerSet(baked_index); - if (layer_set) - { - if (slam_for_debug) - { - layer_set->setUpdatesEnabled(TRUE); - layer_set->cancelUpload(); - } - - BOOL set_by_user = TRUE; - invalidateComposite(layer_set, set_by_user); - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); - } - else - { - llwarns << "TAT: NO LAYER SET FOR " << (S32)baked_index << llendl; - } - } - - // Don't know if this is needed - updateMeshTextures(); -} - - -// static -void LLVOAvatar::processRebakeAvatarTextures(LLMessageSystem* msg, void**) -{ - LLUUID texture_id; - msg->getUUID("TextureData", "TextureID", texture_id); - - LLVOAvatar* self = gAgent.getAvatarObject(); - if (!self) return; - - // If this is a texture corresponding to one of our baked entries, - // just rebake that layer set. - BOOL found = FALSE; - - /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = - TEX_HEAD_BAKED, - TEX_UPPER_BAKED, */ - for (LLVOAvatarDictionary::texture_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - iter++) - { - const ETextureIndex index = iter->first; - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = iter->second; - if (text_dict->mIsBakedTexture) - { - if (texture_id == self->getTEImage(index)->getID()) - { - LLTexLayerSet* layer_set = self->getLayerSet(index); - if (layer_set) - { - llinfos << "TAT: rebake - matched entry " << (S32)index << llendl; - // Apparently set_by_user == force upload - BOOL set_by_user = TRUE; - self->invalidateComposite(layer_set, set_by_user); - found = TRUE; - LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); - } - } - } - } - - // If texture not found, rebake all entries. - if (!found) - { - self->forceBakeAllTextures(); - } - else - { - // Not sure if this is necessary, but forceBakeAllTextures() does it. - self->updateMeshTextures(); - } -} - - -BOOL LLVOAvatar::getLocalTextureRaw(ETextureIndex index, LLImageRaw* image_raw) -{ - if (!isIndexLocalTexture(index)) return FALSE; - - BOOL success = FALSE; - - if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) - { - success = TRUE; - } - else - { - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if(local_tex_data.mImage->readBackRaw(-1, image_raw, false)) - { - success = TRUE; - } - else - { - // No data loaded yet - setLocalTexture( (ETextureIndex)index, getTEImage( index ), FALSE ); - } - } - return success; -} - -BOOL LLVOAvatar::getLocalTextureGL(ETextureIndex index, LLImageGL** image_gl_pp) -{ - if (!isIndexLocalTexture(index)) return FALSE; - - BOOL success = FALSE; - *image_gl_pp = NULL; - - if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) - { - success = TRUE; - } - else - { - LocalTextureData &local_tex_data = mLocalTextureData[index]; - *image_gl_pp = local_tex_data.mImage; - success = TRUE; - } - - if( !success ) - { -// llinfos << "getLocalTextureGL(" << index << ") had no data" << llendl; - } - return success; -} - -const LLUUID& LLVOAvatar::getLocalTextureID(ETextureIndex index) -{ - if (!isIndexLocalTexture(index)) return IMG_DEFAULT_AVATAR; - - if (mLocalTextureData[index].mImage.notNull()) - { - return mLocalTextureData[index].mImage->getID(); - } - else - { - return IMG_DEFAULT_AVATAR; - } -} - -// static -void LLVOAvatar::dumpTotalLocalTextureByteCount() -{ - S32 total_gl_bytes = 0; - for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) - { - LLVOAvatar* cur = (LLVOAvatar*) *iter; - S32 gl_bytes = 0; - cur->getLocalTextureByteCount(&gl_bytes ); - total_gl_bytes += gl_bytes; - } - llinfos << "Total Avatar LocTex GL:" << (total_gl_bytes/1024) << "KB" << llendl; -} - -BOOL LLVOAvatar::isVisible() +BOOL LLVOAvatar::isVisible() const { return mDrawable.notNull() && (mDrawable->isVisible() || mIsDummy); } - // call periodically to keep isFullyLoaded up to date. // returns true if the value has changed. BOOL LLVOAvatar::updateIsFullyLoaded() { // a "heuristic" to determine if we have enough avatar data to render // (to avoid rendering a "Ruth" - DEV-3168) - BOOL loading = FALSE; // do we have a shape? @@ -6594,48 +5732,18 @@ BOOL LLVOAvatar::updateIsFullyLoaded() loading = TRUE; } - // - if (mIsSelf) - { - if (!isTextureDefined(TEX_HAIR)) - { - loading = TRUE; - } - } - else if (!isTextureDefined(TEX_LOWER_BAKED) || !isTextureDefined(TEX_UPPER_BAKED) || !isTextureDefined(TEX_HEAD_BAKED)) + if (!isTextureDefined(TEX_LOWER_BAKED) || + !isTextureDefined(TEX_UPPER_BAKED) || + !isTextureDefined(TEX_HEAD_BAKED)) { loading = TRUE; } - // special case to keep nudity off orientation island - - // this is fragilely dependent on the compositing system, - // which gets available textures in the following order: - // - // 1) use the baked texture - // 2) use the layerset - // 3) use the previously baked texture - // - // on orientation island case (3) can show naked skin. - // so we test for that here: - // - // if we were previously unloaded, and we don't have enough - // texture info for our shirt/pants, stay unloaded: - if (!mPreviousFullyLoaded) - { - if ((!isLocalTextureDataAvailable(mBakedTextureData[BAKED_LOWER].mTexLayerSet)) && - (!isTextureDefined(TEX_LOWER_BAKED))) - { - loading = TRUE; - } + return processFullyLoadedChange(loading); +} - if ((!isLocalTextureDataAvailable(mBakedTextureData[BAKED_UPPER].mTexLayerSet)) && - (!isTextureDefined(TEX_UPPER_BAKED))) - { - loading = TRUE; - } - } - - +BOOL LLVOAvatar::processFullyLoadedChange(bool loading) +{ // we wait a little bit before giving the all clear, // to let textures settle down const F32 PAUSE = 1.f; @@ -6659,8 +5767,7 @@ BOOL LLVOAvatar::updateIsFullyLoaded() return changed; } - -BOOL LLVOAvatar::isFullyLoaded() +BOOL LLVOAvatar::isFullyLoaded() const { if (gSavedSettings.getBOOL("RenderUnloadedAvatar")) return TRUE; @@ -6672,177 +5779,11 @@ BOOL LLVOAvatar::isFullyLoaded() //----------------------------------------------------------------------------- // findMotion() //----------------------------------------------------------------------------- -LLMotion* LLVOAvatar::findMotion(const LLUUID& id) +LLMotion* LLVOAvatar::findMotion(const LLUUID& id) const { return mMotionController.findMotion(id); } -// Counts the memory footprint of local textures. -void LLVOAvatar::getLocalTextureByteCount( S32* gl_bytes ) -{ - *gl_bytes = 0; - for( S32 i = 0; i < TEX_NUM_INDICES; i++ ) - { - if (!isIndexLocalTexture((ETextureIndex)i)) continue; - LLViewerImage* image_gl = mLocalTextureData[(ETextureIndex)i].mImage; - if( image_gl ) - { - S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); - - if( image_gl->getHasGLTexture() ) - { - *gl_bytes += bytes; - } - } - } -} - - -BOOL LLVOAvatar::bindScratchTexture( LLGLenum format ) -{ - U32 texture_bytes = 0; - GLuint gl_name = getScratchTexName( format, &texture_bytes ); - if( gl_name ) - { - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); - stop_glerror(); - - F32* last_bind_time = LLVOAvatar::sScratchTexLastBindTime.getIfThere( format ); - if( last_bind_time ) - { - if( *last_bind_time != LLImageGL::sLastFrameTime ) - { - *last_bind_time = LLImageGL::sLastFrameTime; - LLImageGL::updateBoundTexMem(texture_bytes); - } - } - else - { - LLImageGL::updateBoundTexMem(texture_bytes); - LLVOAvatar::sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) ); - } - - - return TRUE; - } - else - { - return FALSE; - } -} - - -LLGLuint LLVOAvatar::getScratchTexName( LLGLenum format, U32* texture_bytes ) -{ - S32 components; - GLenum internal_format; - switch( format ) - { - case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break; - case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break; - case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; - case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break; - case GL_RGB: components = 3; internal_format = GL_RGB8; break; - case GL_RGBA: components = 4; internal_format = GL_RGBA8; break; - default: llassert(0); components = 4; internal_format = GL_RGBA8; break; - } - - *texture_bytes = components * SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT; - - if( LLVOAvatar::sScratchTexNames.checkData( format ) ) - { - return *( LLVOAvatar::sScratchTexNames.getData( format ) ); - } - else - { - - LLGLSUIDefault gls_ui; - - U32 name = 0; - LLImageGL::generateTextures(1, &name ); - stop_glerror(); - - gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name); - stop_glerror(); - - LLImageGL::setManualImage( - GL_TEXTURE_2D, 0, internal_format, - SCRATCH_TEX_WIDTH, SCRATCH_TEX_HEIGHT, - format, GL_UNSIGNED_BYTE, NULL ); - stop_glerror(); - - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); - gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); - stop_glerror(); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - stop_glerror(); - - LLVOAvatar::sScratchTexNames.addData( format, new LLGLuint( name ) ); - - LLVOAvatar::sScratchTexBytes += *texture_bytes; - LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes; - return name; - } -} - - - -//----------------------------------------------------------------------------- -// setLocalTextureTE() -//----------------------------------------------------------------------------- -void LLVOAvatar::setLocTexTE( U8 te, LLViewerImage* image, BOOL set_by_user ) -{ - if( !mIsSelf ) - { - llassert( 0 ); - return; - } - - if( te >= TEX_NUM_INDICES ) - { - llassert(0); - return; - } - - if( getTEImage( te )->getID() == image->getID() ) - { - return; - } - - if (isIndexBakedTexture((ETextureIndex)te)) - { - llassert(0); - return; - } - - LLTexLayerSet* layer_set = getLayerSet((ETextureIndex)te); - if (layer_set) - { - invalidateComposite(layer_set, set_by_user); - } - - setTEImage( te, image ); - updateMeshTextures(); - - if( gAgent.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } -} - -void LLVOAvatar::setupComposites() -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - bool layer_baked = isTextureDefined(mBakedTextureData[i].mTextureIndex); - if (mBakedTextureData[i].mTexLayerSet) - { - mBakedTextureData[i].mTexLayerSet->setUpdatesEnabled( !layer_baked ); - } - } -} - //----------------------------------------------------------------------------- // updateMeshTextures() // Uses the current TE values to set the meshes' and layersets' textures. @@ -6855,25 +5796,25 @@ void LLVOAvatar::updateMeshTextures() // if user has never specified a texture, assign the default for (U32 i=0; i < getNumTEs(); i++) { - const LLViewerImage* te_image = getTEImage(i); + const LLViewerTexture* te_image = getImage(i); if(!te_image || te_image->getID().isNull() || (te_image->getID() == IMG_DEFAULT)) { - setTEImage(i, gImageList.getImage(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR)); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. + setImage(i, LLViewerTextureManager::getFetchedTexture(i == TEX_HAIR ? IMG_DEFAULT : IMG_DEFAULT_AVATAR)); // IMG_DEFAULT_AVATAR = a special texture that's never rendered. } } - const BOOL self_customizing = mIsSelf && gAgent.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures - const BOOL other_culled = !mIsSelf && mCulled; + const BOOL self_customizing = isSelf() && gAgent.cameraCustomizeAvatar(); // During face edit mode, we don't use baked textures + const BOOL other_culled = !isSelf() && mCulled; - std::vector is_layer_baked; - is_layer_baked.resize(mBakedTextureData.size(), false); + std::vector is_layer_baked; + is_layer_baked.resize(mBakedTextureDatas.size(), false); - std::vector use_lkg_baked_layer; // lkg = "last known good" - use_lkg_baked_layer.resize(mBakedTextureData.size(), false); + std::vector use_lkg_baked_layer; // lkg = "last known good" + use_lkg_baked_layer.resize(mBakedTextureDatas.size(), false); - for (U32 i=0; i < mBakedTextureData.size(); i++) + for (U32 i=0; i < mBakedTextureDatas.size(); i++) { - is_layer_baked[i] = isTextureDefined(mBakedTextureData[i].mTextureIndex); + is_layer_baked[i] = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); if (!other_culled) { @@ -6881,21 +5822,21 @@ void LLVOAvatar::updateMeshTextures() // use the last-known good baked texture until it finish the first // render of the new layerset. use_lkg_baked_layer[i] = (!is_layer_baked[i] - && (mBakedTextureData[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) - && mBakedTextureData[i].mTexLayerSet - && !mBakedTextureData[i].mTexLayerSet->getComposite()->isInitialized()); + && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) + && mBakedTextureDatas[i].mTexLayerSet + && !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()); if (use_lkg_baked_layer[i]) { - mBakedTextureData[i].mTexLayerSet->setUpdatesEnabled(TRUE); + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE); } } else { use_lkg_baked_layer[i] = (!is_layer_baked[i] - && mBakedTextureData[i].mLastTextureIndex != IMG_DEFAULT_AVATAR); - if (mBakedTextureData[i].mTexLayerSet) + && mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR); + if (mBakedTextureDatas[i].mTexLayerSet) { - mBakedTextureData[i].mTexLayerSet->destroyComposite(); + mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); } } @@ -6908,28 +5849,28 @@ void LLVOAvatar::updateMeshTextures() llwarns << "updateMeshTextures: invalid host for object: " << getID() << llendl; } - for (U32 i=0; i < mBakedTextureData.size(); i++) + for (U32 i=0; i < mBakedTextureDatas.size(); i++) { if (use_lkg_baked_layer[i] && !self_customizing ) { - LLViewerImage* baked_img = gImageList.getImageFromHost( mBakedTextureData[i].mLastTextureIndex, target_host ); - mBakedTextureData[i].mIsUsed = TRUE; - for (U32 k=0; k < mBakedTextureData[i].mMeshes.size(); k++) + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTextureFromHost( mBakedTextureDatas[i].mLastTextureIndex, target_host ); + mBakedTextureDatas[i].mIsUsed = TRUE; + for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) { - mBakedTextureData[i].mMeshes[k]->setTexture( baked_img ); + mBakedTextureDatas[i].mMeshes[k]->setTexture( baked_img ); } } else if (!self_customizing && is_layer_baked[i]) { - LLViewerImage* baked_img = getTEImage( mBakedTextureData[i].mTextureIndex ); - if( baked_img->getID() == mBakedTextureData[i].mLastTextureIndex ) + LLViewerFetchedTexture* baked_img = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex ), TRUE) ; + if( baked_img->getID() == mBakedTextureDatas[i].mLastTextureIndex ) { // Even though the file may not be finished loading, we'll consider it loaded and use it (rather than doing compositing). useBakedTexture( baked_img->getID() ); } else { - mBakedTextureData[i].mIsLoaded = FALSE; + mBakedTextureDatas[i].mIsLoaded = FALSE; if ( (i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER) ) { baked_img->setLoadedCallback(onBakedTextureMasksLoaded, MORPH_MASK_REQUESTED_DISCARD, TRUE, TRUE, new LLTextureMaskData( mID )); @@ -6937,133 +5878,63 @@ void LLVOAvatar::updateMeshTextures() baked_img->setLoadedCallback(onBakedTextureLoaded, SWITCH_TO_BAKED_DISCARD, FALSE, FALSE, new LLUUID( mID ) ); } } - else if (mBakedTextureData[i].mTexLayerSet + else if (mBakedTextureDatas[i].mTexLayerSet && !other_culled - && (i != BAKED_HAIR || is_layer_baked[i] || mIsSelf)) // ! BACKWARDS COMPATIBILITY ! workaround for old viewers. + && (i != BAKED_HAIR || is_layer_baked[i] || isSelf())) // ! BACKWARDS COMPATIBILITY ! workaround for old viewers. { - mBakedTextureData[i].mTexLayerSet->createComposite(); - mBakedTextureData[i].mTexLayerSet->setUpdatesEnabled( TRUE ); - mBakedTextureData[i].mIsUsed = FALSE; - for (U32 k=0; k < mBakedTextureData[i].mMeshes.size(); k++) + mBakedTextureDatas[i].mTexLayerSet->createComposite(); + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( TRUE ); + mBakedTextureDatas[i].mIsUsed = FALSE; + for (U32 k=0; k < mBakedTextureDatas[i].mMeshes.size(); k++) { - mBakedTextureData[i].mMeshes[k]->setLayerSet( mBakedTextureData[i].mTexLayerSet ); + mBakedTextureDatas[i].mMeshes[k]->setLayerSet( mBakedTextureDatas[i].mTexLayerSet ); } } } // ! BACKWARDS COMPATIBILITY ! // Workaround for viewing avatars from old viewers that haven't baked hair textures. - // if (!isTextureDefined(mBakedTextureData[BAKED_HAIR].mTextureIndex)) if (!is_layer_baked[BAKED_HAIR] || self_customizing) { const LLColor4 color = mTexHairColor ? mTexHairColor->getColor() : LLColor4(1,1,1,1); - LLViewerImage* hair_img = getTEImage( TEX_HAIR ); - for (U32 i = 0; i < mBakedTextureData[BAKED_HAIR].mMeshes.size(); i++) + LLViewerTexture* hair_img = getImage( TEX_HAIR ); + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) { - mBakedTextureData[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); - mBakedTextureData[BAKED_HAIR].mMeshes[i]->setTexture( hair_img ); + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( color.mV[VX], color.mV[VY], color.mV[VZ], color.mV[VW] ); + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setTexture( hair_img ); } - mHasBakedHair = FALSE; } - else - { - mHasBakedHair = TRUE; - } - /* // Head - BOOL head_baked_ready = (is_layer_baked[BAKED_HEAD] && mBakedTextureData[BAKED_HEAD].mIsLoaded) || other_culled; - setLocalTexture( TEX_HEAD_BODYPAINT, getTEImage( TEX_HEAD_BODYPAINT ), head_baked_ready ); */ - for (LLVOAvatarDictionary::baked_map_t::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + // Turn on alpha masking correctly for yourself and other avatars on 1.23+ + mSupportsAlphaLayers = isSelf() || is_layer_baked[BAKED_HAIR]; + + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); baked_iter++) { const EBakedTextureIndex baked_index = baked_iter->first; - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = baked_iter->second; + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); local_tex_iter++) { const ETextureIndex texture_index = *local_tex_iter; - const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureData[baked_index].mIsLoaded) || other_culled; - setLocalTexture(texture_index, getTEImage(texture_index), is_baked_ready ); + const BOOL is_baked_ready = (is_layer_baked[baked_index] && mBakedTextureDatas[baked_index].mIsLoaded) || other_culled; + setLocalTexture(texture_index, getImage(texture_index), is_baked_ready ); } } removeMissingBakedTextures(); } +// virtual //----------------------------------------------------------------------------- // setLocalTexture() //----------------------------------------------------------------------------- -void LLVOAvatar::setLocalTexture( ETextureIndex index, LLViewerImage* tex, BOOL baked_version_ready ) +void LLVOAvatar::setLocalTexture( ETextureIndex type, LLViewerTexture* in_tex, BOOL baked_version_ready, U32 index ) { - if (!isIndexLocalTexture(index)) return; - - S32 desired_discard = mIsSelf ? 0 : 2; - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if (!baked_version_ready) - { - if (tex != local_tex_data.mImage || local_tex_data.mIsBakedReady) - { - local_tex_data.mDiscard = MAX_DISCARD_LEVEL+1; - } - if (tex->getID() != IMG_DEFAULT_AVATAR) - { - if (local_tex_data.mDiscard > desired_discard) - { - S32 tex_discard = tex->getDiscardLevel(); - if (tex_discard >= 0 && tex_discard <= desired_discard) - { - local_tex_data.mDiscard = tex_discard; - if( mIsSelf && !gAgent.cameraCustomizeAvatar() ) - { - requestLayerSetUpdate( index ); - } - else if( mIsSelf && gAgent.cameraCustomizeAvatar() ) - { - LLVisualParamHint::requestHintUpdates(); - } - } - else - { - tex->setLoadedCallback( onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), index) ); - } - } - tex->setMinDiscardLevel(desired_discard); - } - } - local_tex_data.mIsBakedReady = baked_version_ready; - local_tex_data.mImage = tex; -} - -//----------------------------------------------------------------------------- -// requestLayerSetUploads() -//----------------------------------------------------------------------------- -void LLVOAvatar::requestLayerSetUploads() -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - bool layer_baked = isTextureDefined(mBakedTextureData[i].mTextureIndex); - if ( !layer_baked && mBakedTextureData[i].mTexLayerSet ) - { - mBakedTextureData[i].mTexLayerSet->requestUpload(); - } - } -} - - -//----------------------------------------------------------------------------- -// setCompositeUpdatesEnabled() -//----------------------------------------------------------------------------- -void LLVOAvatar::setCompositeUpdatesEnabled( BOOL b ) -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - if (mBakedTextureData[i].mTexLayerSet ) - { - mBakedTextureData[i].mTexLayerSet->setUpdatesEnabled( b ); - } - } + // invalid for anyone but self + llassert(0); } void LLVOAvatar::addChat(const LLChat& chat) @@ -7095,184 +5966,85 @@ void LLVOAvatar::clearChat() mChats.clear(); } -S32 LLVOAvatar::getLocalDiscardLevel( ETextureIndex index ) +// adds a morph mask to the appropriate baked texture structure +void LLVOAvatar::addMaskedMorph(EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer) { - if (!isIndexLocalTexture(index)) return FALSE; - - LocalTextureData &local_tex_data = mLocalTextureData[index]; - if (index >= 0 - && getLocalTextureID(index) != IMG_DEFAULT_AVATAR - && !local_tex_data.mImage->isMissingAsset()) + if (index < BAKED_NUM_INDICES) { - return local_tex_data.mImage->getDiscardLevel(); - } - else - { - // We don't care about this (no image associated with the layer) treat as fully loaded. - return 0; + LLMaskedMorph *morph = new LLMaskedMorph(morph_target, invert, layer); + mBakedTextureDatas[index].mMaskedMorphs.push_front(morph); } } -//----------------------------------------------------------------------------- -// isLocalTextureDataFinal() -// Returns true if the highest quality discard level exists for every texture -// in the layerset. -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isLocalTextureDataFinal( LLTexLayerSet* layerset ) +// invalidates morph masks for a given layer. Don't pass a parameter to invalidate all morph masks. +void LLVOAvatar::invalidateMorphMasks(LLVOAvatarDefines::EBakedTextureIndex index) { - for (U32 i = 0; i < mBakedTextureData.size(); i++) + setMorphMasksValid(FALSE, index); +} + +// updates morph masks to be a value for a given layer. Don't pass an argument to set value for all morph masks +void LLVOAvatar::setMorphMasksValid(BOOL new_status, LLVOAvatarDefines::EBakedTextureIndex index) +{ + if (index == BAKED_NUM_INDICES) { - if (layerset == mBakedTextureData[i].mTexLayerSet) + for (U8 tex = 0; tex < (U8)BAKED_NUM_INDICES; tex++) { - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - local_tex_iter++) - { - if (getLocalDiscardLevel(*local_tex_iter) != 0) - { - return FALSE; - } - } - return TRUE; + mBakedTextureDatas[tex].mMorphMasksValid = new_status; } + } + else if (index < BAKED_NUM_INDICES) + { + mBakedTextureDatas[index].mMorphMasksValid = new_status; + } +} + +// returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise +BOOL LLVOAvatar::morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index) +{ + if (index >= BAKED_NUM_INDICES) + { + return FALSE; + } + + if (!mBakedTextureDatas[index].mMaskedMorphs.empty() && !mBakedTextureDatas[index].mMorphMasksValid) + { + return TRUE; } - llassert(0); return FALSE; } -//----------------------------------------------------------------------------- -// isLocalTextureDataAvailable() -// Returns true if at least the lowest quality discard level exists for every texture -// in the layerset. -//----------------------------------------------------------------------------- -BOOL LLVOAvatar::isLocalTextureDataAvailable( LLTexLayerSet* layerset ) +void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index) { - /* if( layerset == mBakedTextureData[BAKED_HEAD].mTexLayerSet ) - return getLocalDiscardLevel( TEX_HEAD_BODYPAINT ) >= 0; */ - for (LLVOAvatarDictionary::baked_map_t::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - baked_iter++) + if (index >= BAKED_NUM_INDICES) { - const EBakedTextureIndex baked_index = baked_iter->first; - if (layerset == mBakedTextureData[baked_index].mTexLayerSet) - { - bool ret = true; - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = baked_iter->second; - for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); - local_tex_iter != baked_dict->mLocalTextures.end(); - local_tex_iter++) - { - ret &= (getLocalDiscardLevel(*local_tex_iter) >= 0); - } - return ret; - } + llwarns << "invalid baked texture index passed to applyMorphMask" << llendl; + return; + } + + for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin(); + iter != mBakedTextureDatas[index].mMaskedMorphs.end(); iter++) + { + const LLMaskedMorph* maskedMorph = (*iter); + maskedMorph->mMorphTarget->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert); } - llassert(0); - return FALSE; } //----------------------------------------------------------------------------- -// getBakedTE() -// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.) -//----------------------------------------------------------------------------- -ETextureIndex LLVOAvatar::getBakedTE( LLTexLayerSet* layerset ) -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - if (layerset == mBakedTextureData[i].mTexLayerSet ) - { - return mBakedTextureData[i].mTextureIndex; - } - } - - llassert(0); - return TEX_HEAD_BAKED; -} - -//----------------------------------------------------------------------------- -// setNewBakedTexture() -// A new baked texture has been successfully uploaded and we can start using it now. -//----------------------------------------------------------------------------- -void LLVOAvatar::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - // Baked textures live on other sims. - LLHost target_host = getObjectHost(); - setTEImage( te, gImageList.getImageFromHost( uuid, target_host ) ); - updateMeshTextures(); - dirtyMesh(); - - - LLVOAvatar::cullAvatarsByPixelArea(); - - /* switch(te) - case TEX_HEAD_BAKED: - llinfos << "New baked texture: HEAD" << llendl; */ - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(te); - if (text_dict->mIsBakedTexture) - { - llinfos << "New baked texture: " << text_dict->mName << " UUID: " << uuid <mBakedTextureIndex].mTexLayerSet->requestUpdate(); - } - else - { - llwarns << "New baked texture: unknown te " << te << llendl; - } - - // dumpAvatarTEs( "setNewBakedTexture() send" ); - // RN: throttle uploads - if (!hasPendingBakedUploads()) - { - gAgent.sendAgentSetAppearance(); - } -} - -bool LLVOAvatar::hasPendingBakedUploads() -{ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - bool upload_pending = (mBakedTextureData[i].mTexLayerSet && mBakedTextureData[i].mTexLayerSet->getComposite()->uploadPending()); - if (upload_pending) - { - return true; - } - } - return false; -} - -//----------------------------------------------------------------------------- -// setCachedBakedTexture() -// A baked texture id was received from a cache query, make it active -//----------------------------------------------------------------------------- -void LLVOAvatar::setCachedBakedTexture( ETextureIndex te, const LLUUID& uuid ) -{ - setTETexture( te, uuid ); - - /* switch(te) - case TEX_HEAD_BAKED: - if( mHeadLayerSet ) - mHeadLayerSet->cancelUpload(); */ - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - if ( mBakedTextureData[i].mTextureIndex == te && mBakedTextureData[i].mTexLayerSet) - { - mBakedTextureData[i].mTexLayerSet->cancelUpload(); - } - } -} - -//----------------------------------------------------------------------------- -// releaseUnneccesaryTextures() +// releaseComponentTextures() // release any component texture UUIDs for which we have a baked texture +// ! BACKWARDS COMPATIBILITY ! +// This is only called for non-self avatars, it can be taken out once component +// textures aren't communicated by non-self avatars. //----------------------------------------------------------------------------- -void LLVOAvatar::releaseUnnecessaryTextures() +void LLVOAvatar::releaseComponentTextures() { - // Backwards Compat: detect if the baked hair texture actually wasn't sent, and if so set to default - if (isTextureDefined(TEX_HAIR_BAKED) && getTEImage(TEX_HAIR_BAKED)->getID() == getTEImage(TEX_SKIRT_BAKED)->getID()) + // ! BACKWARDS COMPATIBILITY ! + // Detect if the baked hair texture actually wasn't sent, and if so set to default + if (isTextureDefined(TEX_HAIR_BAKED) && getImage(TEX_HAIR_BAKED)->getID() == getImage(TEX_SKIRT_BAKED)->getID()) { - if (getTEImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE) + if (getImage(TEX_HAIR_BAKED)->getID() != IMG_INVISIBLE) { // Regression case of messaging system. Expected 21 textures, received 20. last texture is not valid so set to default setTETexture(TEX_HAIR_BAKED, IMG_DEFAULT_AVATAR); @@ -7281,7 +6053,7 @@ void LLVOAvatar::releaseUnnecessaryTextures() for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { - const LLVOAvatarDictionary::BakedDictionaryEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); + const LLVOAvatarDictionary::BakedEntry * bakedDicEntry = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)baked_index); // skip if this is a skirt and av is not wearing one, or if we don't have a baked texture UUID if (!isTextureDefined(bakedDicEntry->mTextureIndex) && ( (baked_index != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT) )) @@ -7297,111 +6069,68 @@ void LLVOAvatar::releaseUnnecessaryTextures() } } -//----------------------------------------------------------------------------- -// static -// onCustomizeStart() -//----------------------------------------------------------------------------- -void LLVOAvatar::onCustomizeStart() -{ - // We're no longer doing any baking or invalidating on entering - // appearance editing mode. Leaving function in place in case - // further changes require us to do something at this point - Nyx -} - -//----------------------------------------------------------------------------- -// static -// onCustomizeEnd() -//----------------------------------------------------------------------------- -void LLVOAvatar::onCustomizeEnd() -{ - LLVOAvatar *avatarp = gAgent.getAvatarObject(); - if (avatarp) - { - avatarp->invalidateAll(); - avatarp->requestLayerSetUploads(); - } -} - -void LLVOAvatar::onChangeSelfInvisible(BOOL newvalue) -{ - LLVOAvatar *avatarp = gAgent.getAvatarObject(); - if (avatarp) - { - if (newvalue) - { - // we have just requested to set the avatar's baked textures to invisible - avatarp->setInvisible(TRUE); - } - else - { - avatarp->setInvisible(FALSE); - } - } -} - - BOOL LLVOAvatar::teToColorParams( ETextureIndex te, const char* param_name[3] ) { switch( te ) { - case TEX_UPPER_SHIRT: - param_name[0] = "shirt_red"; - param_name[1] = "shirt_green"; - param_name[2] = "shirt_blue"; - break; + case TEX_UPPER_SHIRT: + param_name[0] = "shirt_red"; + param_name[1] = "shirt_green"; + param_name[2] = "shirt_blue"; + break; - case TEX_LOWER_PANTS: - param_name[0] = "pants_red"; - param_name[1] = "pants_green"; - param_name[2] = "pants_blue"; - break; + case TEX_LOWER_PANTS: + param_name[0] = "pants_red"; + param_name[1] = "pants_green"; + param_name[2] = "pants_blue"; + break; - case TEX_LOWER_SHOES: - param_name[0] = "shoes_red"; - param_name[1] = "shoes_green"; - param_name[2] = "shoes_blue"; - break; + case TEX_LOWER_SHOES: + param_name[0] = "shoes_red"; + param_name[1] = "shoes_green"; + param_name[2] = "shoes_blue"; + break; - case TEX_LOWER_SOCKS: - param_name[0] = "socks_red"; - param_name[1] = "socks_green"; - param_name[2] = "socks_blue"; - break; + case TEX_LOWER_SOCKS: + param_name[0] = "socks_red"; + param_name[1] = "socks_green"; + param_name[2] = "socks_blue"; + break; - case TEX_UPPER_JACKET: - case TEX_LOWER_JACKET: - param_name[0] = "jacket_red"; - param_name[1] = "jacket_green"; - param_name[2] = "jacket_blue"; - break; + case TEX_UPPER_JACKET: + case TEX_LOWER_JACKET: + param_name[0] = "jacket_red"; + param_name[1] = "jacket_green"; + param_name[2] = "jacket_blue"; + break; - case TEX_UPPER_GLOVES: - param_name[0] = "gloves_red"; - param_name[1] = "gloves_green"; - param_name[2] = "gloves_blue"; - break; + case TEX_UPPER_GLOVES: + param_name[0] = "gloves_red"; + param_name[1] = "gloves_green"; + param_name[2] = "gloves_blue"; + break; - case TEX_UPPER_UNDERSHIRT: - param_name[0] = "undershirt_red"; - param_name[1] = "undershirt_green"; - param_name[2] = "undershirt_blue"; - break; + case TEX_UPPER_UNDERSHIRT: + param_name[0] = "undershirt_red"; + param_name[1] = "undershirt_green"; + param_name[2] = "undershirt_blue"; + break; - case TEX_LOWER_UNDERPANTS: - param_name[0] = "underpants_red"; - param_name[1] = "underpants_green"; - param_name[2] = "underpants_blue"; - break; + case TEX_LOWER_UNDERPANTS: + param_name[0] = "underpants_red"; + param_name[1] = "underpants_green"; + param_name[2] = "underpants_blue"; + break; - case TEX_SKIRT: - param_name[0] = "skirt_red"; - param_name[1] = "skirt_green"; - param_name[2] = "skirt_blue"; - break; + case TEX_SKIRT: + param_name[0] = "skirt_red"; + param_name[1] = "skirt_green"; + param_name[2] = "skirt_blue"; + break; - default: - llassert(0); - return FALSE; + default: + llassert(0); + return FALSE; } return TRUE; @@ -7431,140 +6160,53 @@ LLColor4 LLVOAvatar::getClothesColor( ETextureIndex te ) return color; } - - +// static +LLColor4 LLVOAvatar::getDummyColor() +{ + return DUMMY_COLOR; +} void LLVOAvatar::dumpAvatarTEs( const std::string& context ) { /* const char* te_name[] = { "TEX_HEAD_BODYPAINT ", "TEX_UPPER_SHIRT ", */ - llinfos << (mIsSelf ? "Self: " : "Other: ") << context << llendl; - for (LLVOAvatarDictionary::texture_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + llinfos << (isSelf() ? "Self: " : "Other: ") << context << llendl; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); iter++) { - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = iter->second; - const LLViewerImage* te_image = getTEImage(iter->first); + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + const LLViewerTexture* te_image = getImage(iter->first); if( !te_image ) { - llinfos << " " << text_dict->mName << ": null ptr" << llendl; + llinfos << " " << texture_dict->mName << ": null ptr" << llendl; } else if( te_image->getID().isNull() ) { - llinfos << " " << text_dict->mName << ": null UUID" << llendl; + llinfos << " " << texture_dict->mName << ": null UUID" << llendl; } else if( te_image->getID() == IMG_DEFAULT ) { - llinfos << " " << text_dict->mName << ": IMG_DEFAULT" << llendl; + llinfos << " " << texture_dict->mName << ": IMG_DEFAULT" << llendl; } else if( te_image->getID() == IMG_DEFAULT_AVATAR ) { - llinfos << " " << text_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; + llinfos << " " << texture_dict->mName << ": IMG_DEFAULT_AVATAR" << llendl; } else { - llinfos << " " << text_dict->mName << ": " << te_image->getID() << llendl; + llinfos << " " << texture_dict->mName << ": " << te_image->getID() << llendl; } } } -//----------------------------------------------------------------------------- -// updateAttachmentVisibility() -//----------------------------------------------------------------------------- -void LLVOAvatar::updateAttachmentVisibility(U32 camera_mode) -{ - for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); ) - { - attachment_map_t::iterator curiter = iter++; - LLViewerJointAttachment* attachment = curiter->second; - if (attachment->getIsHUDAttachment()) - { - attachment->setAttachmentVisibility(TRUE); - } - else - { - switch (camera_mode) - { - case CAMERA_MODE_MOUSELOOK: - if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) - { - attachment->setAttachmentVisibility(TRUE); - } - else - { - attachment->setAttachmentVisibility(FALSE); - } - break; - default: - attachment->setAttachmentVisibility(TRUE); - break; - } - } - } -} - -// Given a texture entry, determine which wearable type owns it. -// static -LLUUID LLVOAvatar::getDefaultTEImageID(ETextureIndex index ) -{ - /* switch( index ) - case TEX_UPPER_SHIRT: return LLUUID( gSavedSettings.getString("UIImgDefaultShirtUUID") ); */ - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - const std::string &default_image_name = text_dict->mDefaultImageName; - if (default_image_name == "") - { - return IMG_DEFAULT_AVATAR; - } - else - { - return LLUUID(gSavedSettings.getString(default_image_name)); - } -} - - -void LLVOAvatar::setInvisible(BOOL newvalue) -{ - if (newvalue) - { - setCompositeUpdatesEnabled(FALSE); - for (U32 i = 0; i < mBakedTextureData.size(); i++ ) - { - setNewBakedTexture(mBakedTextureData[i].mTextureIndex, IMG_INVISIBLE); - } - gAgent.sendAgentSetAppearance(); - } - else - { - setCompositeUpdatesEnabled(TRUE); - invalidateAll(); - requestLayerSetUploads(); - gAgent.sendAgentSetAppearance(); - } -} - -LLColor4 LLVOAvatar::getDummyColor() -{ - return DUMMY_COLOR; -} - -// Given a texture entry, determine which wearable type owns it. -// static -EWearableType LLVOAvatar::getTEWearableType(ETextureIndex index ) -{ - /* switch(index) - case TEX_UPPER_SHIRT: - return WT_SHIRT; */ - return LLVOAvatarDictionary::getInstance()->getTexture(index)->mWearableType; -} - // Unlike most wearable functions, this works for both self and other. -BOOL LLVOAvatar::isWearingWearableType( EWearableType type ) +BOOL LLVOAvatar::isWearingWearableType(EWearableType type) const { if (mIsDummy) return TRUE; - switch( type ) + switch(type) { case WT_SHAPE: case WT_SKIN: @@ -7578,16 +6220,16 @@ BOOL LLVOAvatar::isWearingWearableType( EWearableType type ) /* switch(type) case WT_SHIRT: indicator_te = TEX_UPPER_SHIRT; */ - for (LLVOAvatarDictionary::texture_map_t::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + for (LLVOAvatarDictionary::Textures::const_iterator tex_iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); tex_iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); tex_iter++) { const LLVOAvatarDefines::ETextureIndex index = tex_iter->first; - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = tex_iter->second; - if (text_dict->mWearableType == type) + const LLVOAvatarDictionary::TextureEntry *texture_dict = tex_iter->second; + if (texture_dict->mWearableType == type) { // If you're checking your own clothing, check the component texture - if (mIsSelf) + if (isSelf()) { if (isTextureDefined(index)) { @@ -7604,23 +6246,10 @@ BOOL LLVOAvatar::isWearingWearableType( EWearableType type ) // NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing // this works for detecting a skirt (most important), but is ineffective at any piece of clothing that // gets baked into a texture that always exists (upper or lower). - const std::string name = text_dict->mName; - for (LLVOAvatarDictionary::baked_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); - iter++) + if (texture_dict->mIsUsedByBakedTexture) { - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = iter->second; - if (baked_dict->mName == name) - { - if (isTextureDefined(baked_dict->mTextureIndex)) - { - return TRUE; - } - else - { - return FALSE; - } - } + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return isTextureDefined(LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex); } return FALSE; } @@ -7628,41 +6257,6 @@ BOOL LLVOAvatar::isWearingWearableType( EWearableType type ) return FALSE; } -//----------------------------------------------------------------------------- -// updatedWearable( EWearableType type ) -// forces an update to any baked textures relevant to type. -// Should be called only on saving the wearable -//----------------------------------------------------------------------------- -void LLVOAvatar::wearableUpdated( EWearableType type ) -{ - for (LLVOAvatarDictionary::wearable_map_t::const_iterator wearable_iter = LLVOAvatarDictionary::getInstance()->getWearables().begin(); - wearable_iter != LLVOAvatarDictionary::getInstance()->getWearables().end(); - wearable_iter++) - { - const LLVOAvatarDictionary::WearableDictionaryEntry *wearable_dict = wearable_iter->second; - const LLVOAvatarDefines::EBakedTextureIndex index = wearable_iter->first; - if (wearable_dict) - { - for (LLVOAvatarDefines::wearables_vec_t::const_iterator type_iter = wearable_dict->mWearablesVec.begin(); - type_iter != wearable_dict->mWearablesVec.end(); - type_iter++) - { - const EWearableType comp_type = *type_iter; - if (comp_type == type) - { - if (mBakedTextureData[index].mTexLayerSet) - { - mBakedTextureData[index].mTexLayerSet->requestUpdate(); - mBakedTextureData[index].mTexLayerSet->requestUpload(); - } - break; - } - } - } - } -} - - //----------------------------------------------------------------------------- // clampAttachmentPositions() //----------------------------------------------------------------------------- @@ -7741,16 +6335,16 @@ void LLVOAvatar::onFirstTEMessageReceived() { mFirstTEMessageReceived = TRUE; - for (U32 i = 0; i < mBakedTextureData.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - bool layer_baked = isTextureDefined(mBakedTextureData[i].mTextureIndex); + const BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); // Use any baked textures that we have even if they haven't downloaded yet. // (That is, don't do a transition from unbaked to baked.) if (layer_baked) { - LLViewerImage* image = getTEImage( mBakedTextureData[i].mTextureIndex ); - mBakedTextureData[i].mLastTextureIndex = image->getID(); + LLViewerFetchedTexture* image = LLViewerTextureManager::staticCastToFetchedTexture(getImage( mBakedTextureDatas[i].mTextureIndex ), TRUE) ; + mBakedTextureDatas[i].mLastTextureIndex = image->getID(); // If we have more than one texture for the other baked layers, we'll want to call this for them too. if ( (i == BAKED_HEAD) || (i == BAKED_UPPER) || (i == BAKED_LOWER) ) { @@ -7782,7 +6376,7 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) mFirstAppearanceMessageReceived = TRUE; - if( mIsSelf ) + if( isSelf() ) { llwarns << "Received AvatarAppearance for self" << llendl; if( mFirstTEMessageReceived ) @@ -7799,31 +6393,24 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) ESex old_sex = getSex(); -// llinfos << "ady LLVOAvatar::processAvatarAppearance()" << llendl; +// llinfos << "LLVOAvatar::processAvatarAppearance()" << llendl; // dumpAvatarTEs( "PRE processAvatarAppearance()" ); unpackTEMessage(mesgsys, _PREHASH_ObjectData); // dumpAvatarTEs( "POST processAvatarAppearance()" ); // prevent the overwriting of valid baked textures with invalid baked textures - for (U8 baked_index = 0; baked_index < mBakedTextureData.size(); baked_index++) + for (U8 baked_index = 0; baked_index < mBakedTextureDatas.size(); baked_index++) { - if (!isTextureDefined(mBakedTextureData[baked_index].mTextureIndex) - && mBakedTextureData[baked_index].mLastTextureIndex != IMG_DEFAULT + if (!isTextureDefined(mBakedTextureDatas[baked_index].mTextureIndex) + && mBakedTextureDatas[baked_index].mLastTextureIndex != IMG_DEFAULT && baked_index != BAKED_SKIRT) { - setTEImage(mBakedTextureData[baked_index].mTextureIndex, gImageList.getImage(mBakedTextureData[baked_index].mLastTextureIndex)); + setTEImage(mBakedTextureDatas[baked_index].mTextureIndex, + LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[baked_index].mLastTextureIndex, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE)); } } - //llinfos << "Received AvatarAppearance: " << (mIsSelf ? "(self): " : "(other): ") << std::endl << - // (isTextureDefined(TEX_HEAD_BAKED) ? "HEAD " : "head " ) << (getTEImage(TEX_HEAD_BAKED)->getID()) << std::endl << - // (isTextureDefined(TEX_UPPER_BAKED) ? "UPPER " : "upper " ) << (getTEImage(TEX_UPPER_BAKED)->getID()) << std::endl << - // (isTextureDefined(TEX_LOWER_BAKED) ? "LOWER " : "lower " ) << (getTEImage(TEX_LOWER_BAKED)->getID()) << std::endl << - // (isTextureDefined(TEX_SKIRT_BAKED) ? "SKIRT " : "skirt " ) << (getTEImage(TEX_SKIRT_BAKED)->getID()) << std::endl << - // (isTextureDefined(TEX_HAIR_BAKED) ? "HAIR" : "hair " ) << (getTEImage(TEX_HAIR_BAKED)->getID()) << std::endl << - // (isTextureDefined(TEX_EYES_BAKED) ? "EYES" : "eyes" ) << (getTEImage(TEX_EYES_BAKED)->getID()) << llendl ; - if( !mFirstTEMessageReceived ) { onFirstTEMessageReceived(); @@ -7831,9 +6418,11 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys ) setCompositeUpdatesEnabled( FALSE ); - if (!mIsSelf) + // ! BACKWARDS COMPATIBILITY ! + // Non-self avatars will no longer have component textures + if (!isSelf()) { - releaseUnnecessaryTextures(); + releaseComponentTextures(); } updateMeshTextures(); // enables updates for laysets without baked textures. @@ -7954,7 +6543,7 @@ void LLVOAvatar::getAnimNames( LLDynamicArray* names ) names->put( "enter_away_from_keyboard_state" ); } -void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { if (!userdata) return; @@ -7993,39 +6582,32 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi, gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); /* if( id == head_baked->getID() ) - if (self->mBakedTextureData[BAKED_HEAD].mTexLayerSet) + if (self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) //llinfos << "onBakedTextureMasksLoaded for head " << id << " discard = " << discard_level << llendl; - self->mBakedTextureData[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); + self->mBakedTextureDatas[BAKED_HEAD].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); maskData->mLastDiscardLevel = discard_level; */ - bool found_texture_id = false; - for (LLVOAvatarDictionary::texture_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + BOOL found_texture_id = false; + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); iter++) { - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = iter->second; - if (text_dict->mIsUsedByBakedTexture) + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsUsedByBakedTexture) { const ETextureIndex texture_index = iter->first; - const LLViewerImage *baked_img = self->getTEImage(texture_index); + const LLViewerTexture *baked_img = self->getImage(texture_index); if (id == baked_img->getID()) { - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - if (self->mBakedTextureData[baked_index].mTexLayerSet) + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + self->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1, baked_index); + maskData->mLastDiscardLevel = discard_level; + if (self->mBakedTextureDatas[baked_index].mMaskTexName) { - //llinfos << "onBakedTextureMasksLoaded for " << text_dict->mName << " " << id << " discard = " << discard_level << llendl; - self->mBakedTextureData[baked_index].mTexLayerSet->applyMorphMask(aux_src->getData(), aux_src->getWidth(), aux_src->getHeight(), 1); - maskData->mLastDiscardLevel = discard_level; - if (self->mBakedTextureData[baked_index].mMaskTexName) - { - LLImageGL::deleteTextures(1, &(self->mBakedTextureData[baked_index].mMaskTexName)); - } - self->mBakedTextureData[baked_index].mMaskTexName = gl_name; - } - else - { - llwarns << "onBakedTextureMasksLoaded: no LayerSet for " << text_dict->mName << "." << llendl; + LLImageGL::deleteTextures(1, &(self->mBakedTextureDatas[baked_index].mMaskTexName)); } + + self->mBakedTextureDatas[baked_index].mMaskTexName = gl_name; found_texture_id = true; break; } @@ -8052,7 +6634,7 @@ void LLVOAvatar::onBakedTextureMasksLoaded( BOOL success, LLViewerImage *src_vi, } // static -void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) +void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ) { LLUUID *avatar_idp = (LLUUID *)userdata; LLVOAvatar *selfp = (LLVOAvatar *)gObjectList.findObject(*avatar_idp); @@ -8067,7 +6649,7 @@ void LLVOAvatar::onInitialBakedTextureLoaded( BOOL success, LLViewerImage *src_v } } -void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +void LLVOAvatar::onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) { //llinfos << "onBakedTextureLoaded: " << src_vi->getID() << llendl; @@ -8100,28 +6682,28 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) mLastHeadBakedID = id; mHeadMesh0.setTexture( head_baked ); mHeadMesh1.setTexture( head_baked ); */ - for (U32 i = 0; i < mBakedTextureData.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) { - LLViewerImage* image_baked = getTEImage( mBakedTextureData[i].mTextureIndex ); + LLViewerTexture* image_baked = getImage( mBakedTextureDatas[i].mTextureIndex ); if (id == image_baked->getID()) { - mBakedTextureData[i].mIsLoaded = true; - mBakedTextureData[i].mIsUsed = true; - mBakedTextureData[i].mLastTextureIndex = id; - for (U32 k = 0; k < mBakedTextureData[i].mMeshes.size(); k++) + mBakedTextureDatas[i].mIsLoaded = true; + mBakedTextureDatas[i].mLastTextureIndex = id; + mBakedTextureDatas[i].mIsUsed = true; + for (U32 k = 0; k < mBakedTextureDatas[i].mMeshes.size(); k++) { - mBakedTextureData[i].mMeshes[k]->setTexture( image_baked ); + mBakedTextureDatas[i].mMeshes[k]->setTexture( image_baked ); } - if (mBakedTextureData[i].mTexLayerSet) + if (mBakedTextureDatas[i].mTexLayerSet) { - mBakedTextureData[i].mTexLayerSet->destroyComposite(); + mBakedTextureDatas[i].mTexLayerSet->destroyComposite(); } - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); local_tex_iter != baked_dict->mLocalTextures.end(); local_tex_iter++) { - setLocalTexture(*local_tex_iter, getTEImage(*local_tex_iter), TRUE); + setLocalTexture(*local_tex_iter, getImage(*local_tex_iter), TRUE); } // ! BACKWARDS COMPATIBILITY ! @@ -8129,9 +6711,9 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id ) // This is paired with similar code in updateMeshTextures that sets hair mesh color. if (i == BAKED_HAIR) { - for (U32 i = 0; i < mBakedTextureData[BAKED_HAIR].mMeshes.size(); i++) + for (U32 i = 0; i < mBakedTextureDatas[BAKED_HAIR].mMeshes.size(); i++) { - mBakedTextureData[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f ); + mBakedTextureDatas[BAKED_HAIR].mMeshes[i]->setColor( 1.f, 1.f, 1.f, 1.f ); } } } @@ -8147,7 +6729,7 @@ void LLVOAvatar::dumpArchetypeXML( void* ) LLAPRFile outfile ; outfile.open(gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,"new archetype.xml"), LL_APR_WB ); apr_file_t* file = outfile.getFileHandle() ; - if( !file ) + if (!file) { return; } @@ -8157,27 +6739,27 @@ void LLVOAvatar::dumpArchetypeXML( void* ) apr_file_printf( file, "\n\t\n" ); // only body parts, not clothing. - for( S32 type = WT_SHAPE; type <= WT_EYES; type++ ) + for (S32 type = WT_SHAPE; type <= WT_EYES; type++) { - const std::string& wearable_name = LLWearable::typeToTypeName( (EWearableType) type ); + const std::string& wearable_name = LLWearableDictionary::getTypeName((EWearableType)type); apr_file_printf( file, "\n\t\t\n", wearable_name.c_str() ); - for( LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam() ) + for (LLVisualParam* param = avatar->getFirstVisualParam(); param; param = avatar->getNextVisualParam()) { LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param; if( (viewer_param->getWearableType() == type) && (viewer_param->getGroup() == VISUAL_PARAM_GROUP_TWEAKABLE) ) { - apr_file_printf( file, "\t\t\n", - viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight() ); + apr_file_printf(file, "\t\t\n", + viewer_param->getID(), viewer_param->getName().c_str(), viewer_param->getWeight()); } } - for(U8 te = 0; te < TEX_NUM_INDICES; te++) + for (U8 te = 0; te < TEX_NUM_INDICES; te++) { - if( LLVOAvatar::getTEWearableType((ETextureIndex)te) == type ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex)te) == type) { - LLViewerImage* te_image = avatar->getTEImage((ETextureIndex)te); + LLViewerTexture* te_image = avatar->getImage((ETextureIndex)te); if( te_image ) { std::string uuid_str; @@ -8192,18 +6774,13 @@ void LLVOAvatar::dumpArchetypeXML( void* ) } -U32 LLVOAvatar::getVisibilityRank() -{ - return mVisibilityRank; -} - void LLVOAvatar::setVisibilityRank(U32 rank) { if (mDrawable.isNull() || mDrawable->isDead()) - { //do nothing + { + // do nothing return; } - mVisibilityRank = rank; } @@ -8212,15 +6789,14 @@ S32 LLVOAvatar::getUnbakedPixelAreaRank() { S32 rank = 1; for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; - if( inst == this ) + if (inst == this) { return rank; } - else - if( !inst->isDead() && !inst->isFullyBaked() ) + else if (!inst->isDead() && !inst->isFullyBaked()) { rank++; } @@ -8232,7 +6808,7 @@ S32 LLVOAvatar::getUnbakedPixelAreaRank() struct CompareScreenAreaGreater { - bool operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs) + BOOL operator()(const LLCharacter* const& lhs, const LLCharacter* const& rhs) { return lhs->getPixelArea() > rhs->getPixelArea(); } @@ -8246,7 +6822,7 @@ void LLVOAvatar::cullAvatarsByPixelArea() // Update the avatars that have changed status U32 rank = 0; for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* inst = (LLVOAvatar*) *iter; BOOL culled; @@ -8277,7 +6853,7 @@ void LLVOAvatar::cullAvatarsByPixelArea() } S32 grey_avatars = 0; - if ( LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars) ) + if (LLVOAvatar::areAllNearbyInstancesBaked(grey_avatars)) { LLVOAvatar::deleteCachedImages(false); } @@ -8299,144 +6875,6 @@ void LLVOAvatar::cullAvatarsByPixelArea() } } -const LLUUID& LLVOAvatar::grabLocalTexture(ETextureIndex index) -{ - if (canGrabLocalTexture(index)) - { - return getTEImage( index )->getID(); - } - return LLUUID::null; -} - -BOOL LLVOAvatar::canGrabLocalTexture(ETextureIndex index) -{ - // Check if the texture hasn't been baked yet. - if (!isTextureDefined(index)) - { - lldebugs << "getTEImage( " << (U32) index << " )->getID() == IMG_DEFAULT_AVATAR" << llendl; - return FALSE; - } - - if (gAgent.isGodlike() && !gAgent.getAdminOverride()) - return TRUE; - - // Check permissions of textures that show up in the - // baked texture. We don't want people copying people's - // work via baked textures. - /* switch(index) - case TEX_EYES_BAKED: - textures.push_back(TEX_EYES_IRIS); */ - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (!text_dict->mIsUsedByBakedTexture) return FALSE; - - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - const LLVOAvatarDictionary::BakedDictionaryEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index); - for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); - iter != baked_dict->mLocalTextures.end(); - iter++) - { - const ETextureIndex t_index = (*iter); - lldebugs << "Checking index " << (U32) t_index << llendl; - const LLUUID& texture_id = getTEImage( t_index )->getID(); - if (texture_id != IMG_DEFAULT_AVATAR) - { - // Search inventory for this texture. - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - LLAssetIDMatches asset_id_matches(texture_id); - gInventory.collectDescendentsIf(LLUUID::null, - cats, - items, - LLInventoryModel::INCLUDE_TRASH, - asset_id_matches); - - BOOL can_grab = FALSE; - lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl; - if (items.count()) - { - // search for full permissions version - for (S32 i = 0; i < items.count(); i++) - { - LLInventoryItem* itemp = items[i]; - LLPermissions item_permissions = itemp->getPermissions(); - if ( item_permissions.allowOperationBy( - PERM_MODIFY, gAgent.getID(), gAgent.getGroupID()) && - item_permissions.allowOperationBy( - PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && - item_permissions.allowOperationBy( - PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID()) ) - { - can_grab = TRUE; - break; - } - } - } - if (!can_grab) return FALSE; - } - } - - return TRUE; -} - -void LLVOAvatar::dumpLocalTextures() -{ - llinfos << "Local Textures:" << llendl; - - /* ETextureIndex baked_equiv[] = { - TEX_UPPER_BAKED, - if (isTextureDefined(baked_equiv[i])) */ - for (LLVOAvatarDictionary::texture_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); - iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); - iter++) - { - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = iter->second; - if (!text_dict->mIsLocalTexture || !text_dict->mIsUsedByBakedTexture) - continue; - - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - const ETextureIndex baked_equiv = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex; - - const std::string &name = text_dict->mName; - const LocalTextureData &local_tex_data = mLocalTextureData[iter->first]; - if (isTextureDefined(baked_equiv)) - { -#if LL_RELEASE_FOR_DOWNLOAD - // End users don't get to trivially see avatar texture IDs, makes textures - // easier to steal. JC - llinfos << "LocTex " << name << ": Baked " << llendl; -#else - llinfos << "LocTex " << name << ": Baked " << getTEImage( baked_equiv )->getID() << llendl; -#endif - } - else if (local_tex_data.mImage.notNull()) - { - if( local_tex_data.mImage->getID() == IMG_DEFAULT_AVATAR ) - { - llinfos << "LocTex " << name << ": None" << llendl; - } - else - { - const LLViewerImage* image = local_tex_data.mImage; - - llinfos << "LocTex " << name << ": " - << "Discard " << image->getDiscardLevel() << ", " - << "(" << image->getWidth() << ", " << image->getHeight() << ") " -#if !LL_RELEASE_FOR_DOWNLOAD - // End users don't get to trivially see avatar texture IDs, - // makes textures easier to steal - << image->getID() << " " -#endif - << "Priority: " << image->getDecodePriority() - << llendl; - } - } - else - { - llinfos << "LocTex " << name << ": No LLViewerImage" << llendl; - } - } -} - void LLVOAvatar::startAppearanceAnimation(BOOL set_by_user, BOOL play_sound) { if(!mAppearanceAnimating) @@ -8448,53 +6886,31 @@ void LLVOAvatar::startAppearanceAnimation(BOOL set_by_user, BOOL play_sound) } } - +// virtual void LLVOAvatar::removeMissingBakedTextures() { - if (!mIsSelf) return; - - BOOL removed = FALSE; - for (U32 i = 0; i < mBakedTextureData.size(); i++) - { - const S32 te = mBakedTextureData[i].mTextureIndex; - if (getTEImage(te)->isMissingAsset()) - { - setTEImage(te, gImageList.getImage(IMG_DEFAULT_AVATAR)); - removed = TRUE; - } - } - - if (removed) - { - for(U32 i = 0; i < mBakedTextureData.size(); i++) - { - invalidateComposite(mBakedTextureData[i].mTexLayerSet, FALSE); - } - updateMeshTextures(); - requestLayerSetUploads(); - } } - //----------------------------------------------------------------------------- // LLVOAvatarXmlInfo //----------------------------------------------------------------------------- -LLVOAvatarXmlInfo::LLVOAvatarXmlInfo() +LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo() : mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0) { } -LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo() +LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo() { std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer()); std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer()); std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer()); - delete mTexSkinColorInfo; - delete mTexHairColorInfo; - delete mTexEyeColorInfo; + deleteAndClear(mTexSkinColorInfo); + deleteAndClear(mTexHairColorInfo); + deleteAndClear(mTexEyeColorInfo); std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer()); - std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer()); + std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer()); } //----------------------------------------------------------------------------- @@ -8606,7 +7022,7 @@ BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node) //----------------------------------------------------------------------------- // parseXmlSkeletonNode(): parses nodes from XML tree //----------------------------------------------------------------------------- -BOOL LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) { LLXmlTreeNode* node = root->getChildByName( "skeleton" ); if( !node ) @@ -8712,7 +7128,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root) //----------------------------------------------------------------------------- // parseXmlMeshNodes(): parses nodes from XML tree //----------------------------------------------------------------------------- -BOOL LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) { for (LLXmlTreeNode* node = root->getChildByName( "mesh" ); node; @@ -8802,7 +7218,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root) //----------------------------------------------------------------------------- // parseXmlColorNodes(): parses nodes from XML tree //----------------------------------------------------------------------------- -BOOL LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) { for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" ); color_node; @@ -8822,7 +7238,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) mTexSkinColorInfo = new LLTexGlobalColorInfo; if( !mTexSkinColorInfo->parseXml( color_node ) ) { - delete mTexSkinColorInfo; mTexSkinColorInfo = 0; + deleteAndClear(mTexSkinColorInfo); llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl; return FALSE; } @@ -8837,7 +7253,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) mTexHairColorInfo = new LLTexGlobalColorInfo; if( !mTexHairColorInfo->parseXml( color_node ) ) { - delete mTexHairColorInfo; mTexHairColorInfo = 0; + deleteAndClear(mTexHairColorInfo); llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl; return FALSE; } @@ -8864,7 +7280,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root) //----------------------------------------------------------------------------- // parseXmlLayerNodes(): parses nodes from XML tree //----------------------------------------------------------------------------- -BOOL LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) { for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" ); layer_node; @@ -8888,7 +7304,7 @@ BOOL LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root) //----------------------------------------------------------------------------- // parseXmlDriverNodes(): parses nodes from XML tree //----------------------------------------------------------------------------- -BOOL LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) { LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" ); if( driver ) @@ -8916,36 +7332,60 @@ BOOL LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root) return TRUE; } -// warning: order(N) not order(1) -S32 LLVOAvatar::getAttachmentCount() +//----------------------------------------------------------------------------- +// parseXmlDriverNodes(): parses nodes from XML tree +//----------------------------------------------------------------------------- +BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root) { - S32 count = mAttachmentPoints.size(); - return count; + LLXmlTreeNode* masks = root->getChildByName( "morph_masks" ); + if( !masks ) + { + return FALSE; + } + + for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" ); + grand_child; + grand_child = masks->getNextNamedChild()) + { + LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo(); + + static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name"); + if (!grand_child->getFastAttributeString(name_string, info->mName)) + { + llwarns << "No name supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region"); + if (!grand_child->getFastAttributeString(region_string, info->mRegion)) + { + llwarns << "No region supplied for morph mask." << llendl; + delete info; + continue; + } + + static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer"); + if (!grand_child->getFastAttributeString(layer_string, info->mLayer)) + { + llwarns << "No layer supplied for morph mask." << llendl; + delete info; + continue; + } + + // optional parameter. don't throw a warning if not present. + static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert"); + grand_child->getFastAttributeBOOL(invert_string, info->mInvert); + + mMorphMaskInfoList.push_back(info); + } + + return TRUE; } //virtual void LLVOAvatar::updateRegion(LLViewerRegion *regionp) { - if (mIsSelf) - { - if (regionp->getHandle() != mLastRegionHandle) - { - if (mLastRegionHandle != 0) - { - ++mRegionCrossingCount; - F64 delta = (F64)mRegionCrossingTimer.getElapsedTimeF32(); - F64 avg = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_AVG); - F64 delta_avg = (delta + avg*(mRegionCrossingCount-1)) / mRegionCrossingCount; - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_AVG, delta_avg); - - F64 max = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_MAX); - max = llmax(delta, max); - LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_MAX, max); - } - mLastRegionHandle = regionp->getHandle(); - } - mRegionCrossingTimer.reset(); - } } std::string LLVOAvatar::getFullname() const @@ -8964,21 +7404,6 @@ std::string LLVOAvatar::getFullname() const return name; } -LLTexLayerSet* LLVOAvatar::getLayerSet(ETextureIndex index) const -{ - /* switch(index) - case TEX_HEAD_BAKED: - case TEX_HEAD_BODYPAINT: - return mHeadLayerSet; */ - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); - if (text_dict->mIsUsedByBakedTexture) - { - const EBakedTextureIndex baked_index = text_dict->mBakedTextureIndex; - return mBakedTextureData[baked_index].mTexLayerSet; - } - return NULL; -} - LLHost LLVOAvatar::getObjectHost() const { LLViewerRegion* region = getRegion(); @@ -9017,7 +7442,7 @@ BOOL LLVOAvatar::updateLOD() if (facep->mVertexBuffer.isNull() || LLVertexBuffer::sEnableVBOs && ((facep->mVertexBuffer->getUsage() == GL_STATIC_DRAW ? TRUE : FALSE) != - (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE))) + (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE))) { mDirtyMesh = TRUE; } @@ -9036,7 +7461,8 @@ BOOL LLVOAvatar::updateLOD() } U32 LLVOAvatar::getPartitionType() const -{ //avatars merely exist as drawables in the bridge partition +{ + // Avatars merely exist as drawables in the bridge partition return LLViewerRegion::PARTITION_BRIDGE; } @@ -9044,10 +7470,9 @@ U32 LLVOAvatar::getPartitionType() const void LLVOAvatar::updateImpostors() { for (std::vector::iterator iter = LLCharacter::sInstances.begin(); - iter != LLCharacter::sInstances.end(); ++iter) + iter != LLCharacter::sInstances.end(); ++iter) { LLVOAvatar* avatar = (LLVOAvatar*) *iter; - if (!avatar->isDead() && avatar->needsImpostorUpdate() && avatar->isVisible() && avatar->isImpostor()) { gPipeline.generateImpostor(avatar); @@ -9111,10 +7536,9 @@ void LLVOAvatar::idleUpdateRenderCost() std::set textures; - attachment_map_t::const_iterator iter; - for (iter = mAttachmentPoints.begin(); - iter != mAttachmentPoints.end(); - ++iter) + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); + ++iter) { LLViewerJointAttachment* attachment = iter->second; LLViewerObject* object = attachment->getObject(); @@ -9159,15 +7583,15 @@ const std::string LLVOAvatar::getBakedStatusForPrintout() const { std::string line; - for (LLVOAvatarDictionary::texture_map_t::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); iter++) { const ETextureIndex index = iter->first; - const LLVOAvatarDictionary::TextureDictionaryEntry *text_dict = iter->second; - if (text_dict->mIsBakedTexture) + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) { - line += text_dict->mName; + line += texture_dict->mName; if (isTextureDefined(index)) { line += "_baked"; @@ -9224,7 +7648,7 @@ U32 calc_shame(LLVOVolume* volume, std::set &textures) { LLFace* face = drawablep->getFace(i); const LLTextureEntry* te = face->getTextureEntry(); - LLViewerImage* img = face->getTexture(); + LLViewerTexture* img = face->getTexture(); textures.insert(img->getID()); @@ -9283,6 +7707,12 @@ U32 calc_shame(LLVOVolume* volume, std::set &textures) return shame; } +//virtual +S32 LLVOAvatar::getTexImageSize() const +{ + return TEX_IMAGE_SIZE_OTHER; +} + //----------------------------------------------------------------------------- // Utility functions //----------------------------------------------------------------------------- @@ -9291,3 +7721,16 @@ F32 calc_bouncy_animation(F32 x) { return -(cosf(x * F_PI * 2.5f - F_PI_BY_TWO))*(0.4f + x * -0.1f) + x * 1.3f; } + +//virtual +BOOL LLVOAvatar::isTextureDefined(LLVOAvatarDefines::ETextureIndex te, U32 index ) const +{ + if (isIndexLocalTexture(te)) + { + return FALSE; + } + + return (getImage(te)->getID() != IMG_DEFAULT_AVATAR && + getImage(te)->getID() != IMG_DEFAULT); +} + diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index f8b2c068ff..4dc70511ce 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -39,6 +39,7 @@ #include #include +#include "imageids.h" // IMG_INVISIBLE #include "llchat.h" #include "lldrawpoolalpha.h" #include "llviewerobject.h" @@ -46,8 +47,10 @@ #include "llviewerjointmesh.h" #include "llviewerjointattachment.h" #include "llrendertarget.h" -#include "llwearable.h" #include "llvoavatardefines.h" +#include "lltexglobalcolor.h" +#include "lldriverparam.h" +#include "material_codes.h" // LL_MCODE_END extern const LLUUID ANIM_AGENT_BODY_NOISE; extern const LLUUID ANIM_AGENT_BREATHE_ROT; @@ -65,10 +68,8 @@ class LLVoiceVisualizer; class LLHUDText; class LLHUDEffectSpiral; class LLTexGlobalColor; - class LLVOAvatarBoneInfo; class LLVOAvatarSkeletonInfo; -class LLVOAvatarXmlInfo; //------------------------------------------------------------------------ // LLVOAvatar @@ -77,433 +78,143 @@ class LLVOAvatar : public LLViewerObject, public LLCharacter { +public: + friend class LLVOAvatarSelf; protected: - virtual ~LLVOAvatar(); + struct LLVOAvatarXmlInfo; + struct LLMaskedMorph; + +/******************************************************************************** + ** ** + ** INITIALIZATION + **/ public: LLVOAvatar(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); - /*virtual*/ void markDead(); - void startDefaultMotions(); - - static void updateImpostors(); - - //-------------------------------------------------------------------- - // LLViewerObject interface - //-------------------------------------------------------------------- -public: - static void initClass(); // Initialize data that's only init'd once per class. - static void cleanupClass(); // Cleanup data that's only init'd once per class. - static BOOL parseSkeletonFile(const std::string& filename); - virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, - void **user_data, - U32 block_num, - const EObjectUpdateType update_type, - LLDataPacker *dp); - /*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); - void idleUpdateVoiceVisualizer(bool voice_enabled); - void idleUpdateMisc(bool detailed_update); - void idleUpdateAppearanceAnimation(); - void idleUpdateLipSync(bool voice_enabled); - void idleUpdateLoadingEffect(); - void idleUpdateWindEffect(); - void idleUpdateNameTag(const LLVector3& root_pos_last); - void idleUpdateRenderCost(); - void idleUpdateTractorBeam(); - void idleUpdateBelowWater(); - -public: - virtual BOOL updateLOD(); - /*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate. - - // Graphical stuff for objects - maybe broken out into render class later? - U32 renderFootShadows(); - U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255)); - U32 renderRigid(); - U32 renderSkinned(EAvatarRenderPass pass); - U32 renderTransparent(BOOL first_pass); - void renderCollisionVolumes(); - - /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, - S32 face = -1, // which face to check, -1 = ALL_SIDES - BOOL pick_transparent = FALSE, - S32* face_hit = NULL, // which face was hit - LLVector3* intersection = NULL, // return the intersection point - LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point - LLVector3* normal = NULL, // return the surface normal at the intersection point - LLVector3* bi_normal = NULL // return the surface bi-normal at the intersection point - ); - - /*virtual*/ void updateTextures(LLAgent &agent); - // If setting a baked texture, need to request it from a non-local sim. - /*virtual*/ S32 setTETexture(const U8 te, const LLUUID& uuid); - /*virtual*/ void onShift(const LLVector3& shift_vector); - virtual U32 getPartitionType() const; - - void updateVisibility(); - void updateAttachmentVisibility(U32 camera_mode); - void clampAttachmentPositions(); - S32 getAttachmentCount(); // Warning: order(N) not order(1) - - // HUD functions - BOOL hasHUDAttachment() const; - LLBBox getHUDBBox() const; - void rebuildHUD(); - - /*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline); - /*virtual*/ BOOL updateGeometry(LLDrawable *drawable); - - /*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); - BOOL updateJointLODs(); - - virtual void updateRegion(LLViewerRegion *regionp); - - virtual const LLVector3 getRenderPosition() const; - virtual void updateDrawable(BOOL force_damped); - void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax); - void getSpatialExtents(LLVector3& newMin, LLVector3& newMax); - BOOL isImpostor() const; - BOOL needsImpostorUpdate() const; - const LLVector3& getImpostorOffset() const; - const LLVector2& getImpostorDim() const; - void getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const; - void cacheImpostorValues(); - void setImpostorDim(const LLVector2& dim); - - //-------------------------------------------------------------------- - // LLCharacter interface - //-------------------------------------------------------------------- -public: - virtual const char *getAnimationPrefix() { return "avatar"; } - virtual LLJoint *getRootJoint() { return &mRoot; } - virtual LLVector3 getCharacterPosition(); - virtual LLQuaternion getCharacterRotation(); - virtual LLVector3 getCharacterVelocity(); - virtual LLVector3 getCharacterAngularVelocity(); - virtual F32 getTimeDilation(); - virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); - virtual BOOL allocateCharacterJoints( U32 num ); - virtual LLJoint *getCharacterJoint( U32 num ); - virtual void requestStopMotion( LLMotion* motion ); - virtual F32 getPixelArea() const; - virtual LLPolyMesh* getHeadMesh(); - virtual LLPolyMesh* getUpperBodyMesh(); - virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position); - virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position); - virtual void updateVisualParams(); - virtual BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); - virtual BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); - virtual void stopMotionFromSource(const LLUUID& source_id); - virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); - virtual LLJoint* findCollisionVolume(U32 volume_id); - virtual S32 getCollisionVolumeID(std::string &name); - virtual void addDebugText(const std::string& text); - virtual const LLUUID& getID(); - virtual LLJoint *getJoint( const std::string &name ); - - //-------------------------------------------------------------------- - // Other public functions - //-------------------------------------------------------------------- -public: - static void onCustomizeStart(); - static void onCustomizeEnd(); - -public: - static void dumpTotalLocalTextureByteCount(); + virtual void markDead(); + static void initClass(); // Initialize data that's only init'd once per class. + static void cleanupClass(); // Cleanup data that's only init'd once per class. + virtual void initInstance(); // Called after construction to initialize the class. protected: - void getLocalTextureByteCount( S32* gl_byte_count ); + virtual ~LLVOAvatar(); + BOOL loadSkeletonNode(); + BOOL loadMeshNodes(); + virtual BOOL loadLayersets(); + +/** Initialization + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** INHERITED + **/ + + //-------------------------------------------------------------------- + // LLViewerObject interface and related + //-------------------------------------------------------------------- +public: + virtual U32 processUpdateMessage(LLMessageSystem *mesgsys, + void **user_data, + U32 block_num, + const EObjectUpdateType update_type, + LLDataPacker *dp); + virtual BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time); + virtual BOOL updateLOD(); + BOOL updateJointLODs(); + virtual BOOL isActive() const; // Whether this object needs to do an idleUpdate. + virtual void updateTextures(LLAgent &agent); + virtual S32 setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim. + virtual void onShift(const LLVector3& shift_vector); + virtual U32 getPartitionType() const; + virtual const LLVector3 getRenderPosition() const; + virtual void updateDrawable(BOOL force_damped); + virtual LLDrawable* createDrawable(LLPipeline *pipeline); + virtual BOOL updateGeometry(LLDrawable *drawable); + virtual void setPixelAreaAndAngle(LLAgent &agent); + virtual void updateRegion(LLViewerRegion *regionp); + virtual void updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax); + virtual void getSpatialExtents(LLVector3& newMin, LLVector3& newMax); + virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, + S32 face = -1, // which face to check, -1 = ALL_SIDES + BOOL pick_transparent = FALSE, + S32* face_hit = NULL, // which face was hit + LLVector3* intersection = NULL, // return the intersection point + LLVector2* tex_coord = NULL, // return the texture coordinates of the intersection point + LLVector3* normal = NULL, // return the surface normal at the intersection point + LLVector3* bi_normal = NULL); // return the surface bi-normal at the intersection point + + //-------------------------------------------------------------------- + // LLCharacter interface and related + //-------------------------------------------------------------------- +public: + virtual LLVector3 getCharacterPosition(); + virtual LLQuaternion getCharacterRotation(); + virtual LLVector3 getCharacterVelocity(); + virtual LLVector3 getCharacterAngularVelocity(); + virtual LLJoint* getCharacterJoint(U32 num); + virtual BOOL allocateCharacterJoints(U32 num); + + virtual BOOL startMotion(const LLUUID& id, F32 time_offset = 0.f); + virtual BOOL stopMotion(const LLUUID& id, BOOL stop_immediate = FALSE); + virtual void stopMotionFromSource(const LLUUID& source_id); + virtual void requestStopMotion(LLMotion* motion); + LLMotion* findMotion(const LLUUID& id) const; + void startDefaultMotions(); + + virtual LLJoint* getJoint(const std::string &name); + virtual LLJoint* getRootJoint() { return &mRoot; } + + virtual const char* getAnimationPrefix() { return "avatar"; } + virtual const LLUUID& getID(); + virtual LLVector3 getVolumePos(S32 joint_index, LLVector3& volume_offset); + virtual LLJoint* findCollisionVolume(U32 volume_id); + virtual S32 getCollisionVolumeID(std::string &name); + virtual void addDebugText(const std::string& text); + virtual F32 getTimeDilation(); + virtual void getGround(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); + virtual F32 getPixelArea() const; + virtual LLPolyMesh* getHeadMesh(); + virtual LLPolyMesh* getUpperBodyMesh(); + virtual LLVector3d getPosGlobalFromAgent(const LLVector3 &position); + virtual LLVector3 getPosAgentFromGlobal(const LLVector3d &position); + virtual void updateVisualParams(); + + +/** Inherited + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** STATE + **/ public: - LLMotion* findMotion(const LLUUID& id); - - BOOL isVisible(); - BOOL isSelf() const { return mIsSelf; } - BOOL isCulled() const { return mCulled; } - -public: - static void cullAvatarsByPixelArea(); - void setVisibilityRank(U32 rank); - U32 getVisibilityRank(); // unused -protected: - S32 getUnbakedPixelAreaRank(); - -public: - void dumpLocalTextures(); - const LLUUID& grabLocalTexture(LLVOAvatarDefines::ETextureIndex index); - BOOL canGrabLocalTexture(LLVOAvatarDefines::ETextureIndex index); - BOOL isTextureDefined(U8 te) const; - BOOL isTextureVisible(U8 te) const; - void startAppearanceAnimation(BOOL set_by_user, BOOL play_sound); - - void setCompositeUpdatesEnabled(BOOL b); - - void addChat(const LLChat& chat); - void clearChat(); - void startTyping() { mTyping = TRUE; mTypingTimer.reset(); } - void stopTyping() { mTyping = FALSE; } - - // Returns "FirstName LastName" - std::string getFullname() const; - - BOOL updateCharacter(LLAgent &agent); - void updateHeadOffset(); - - F32 getPelvisToFoot() const { return mPelvisToFoot; } - -public: - BOOL isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims); - void processAnimationStateChanges(); -protected: - BOOL processSingleAnimationStateChange(const LLUUID &anim_id, BOOL start); - void resetAnimations(); - -public: - void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm); - void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); - void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm); + virtual bool isSelf() const { return false; } // True if this avatar is for this viewer's agent + bool isBuilt() const { return mIsBuilt; } - void slamPosition(); // Slam position to transmitted position (for teleport); - - // morph targets and such - void processAvatarAppearance( LLMessageSystem* mesgsys ); - void onFirstTEMessageReceived(); - void updateSexDependentLayerSets( BOOL set_by_user ); - void dirtyMesh(); // Dirty the avatar mesh - void hideSkirt(); - - virtual void setParent(LLViewerObject* parent); - virtual void addChild(LLViewerObject *childp); - virtual void removeChild(LLViewerObject *childp); - - LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); - BOOL attachObject(LLViewerObject *viewer_object); - BOOL detachObject(LLViewerObject *viewer_object); - void lazyAttach(); - - void sitOnObject(LLViewerObject *sit_object); - void getOffObject(); - - BOOL isWearingAttachment( const LLUUID& inv_item_id ); - LLViewerObject* getWornAttachment( const LLUUID& inv_item_id ); - const std::string getAttachedPointName(const LLUUID& inv_item_id); - - static LLVOAvatar* findAvatarFromAttachment( LLViewerObject* obj ); - - void updateMeshTextures(); - - //-------------------------------------------------------------------- - // texture compositing (used only by the LLTexLayer series of classes) - //-------------------------------------------------------------------- -public: - LLColor4 getGlobalColor( const std::string& color_name ); - BOOL isLocalTextureDataAvailable( LLTexLayerSet* layerset ); - BOOL isLocalTextureDataFinal( LLTexLayerSet* layerset ); - LLVOAvatarDefines::ETextureIndex getBakedTE( LLTexLayerSet* layerset ); - void updateComposites(); - void onGlobalColorChanged( LLTexGlobalColor* global_color, BOOL set_by_user ); - BOOL getLocalTextureRaw( LLVOAvatarDefines::ETextureIndex index, LLImageRaw* image_raw_pp ); - BOOL getLocalTextureGL( LLVOAvatarDefines::ETextureIndex index, LLImageGL** image_gl_pp ); - const LLUUID& getLocalTextureID( LLVOAvatarDefines::ETextureIndex index ); - LLGLuint getScratchTexName( LLGLenum format, U32* texture_bytes ); - BOOL bindScratchTexture( LLGLenum format ); - void invalidateComposite( LLTexLayerSet* layerset, BOOL set_by_user ); - void invalidateAll(); - void forceBakeAllTextures(bool slam_for_debug = false); - static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); - void setNewBakedTexture( LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid ); - void setCachedBakedTexture( LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid ); - void releaseUnnecessaryTextures(); - void requestLayerSetUploads(); - bool hasPendingBakedUploads(); - static void onLocalTextureLoaded( BOOL succcess, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); - static void dumpArchetypeXML( void* ); - static void dumpScratchTextureByteCount(); - static void dumpBakedStatus(); - static void deleteCachedImages(bool clearAll=true); - static void destroyGL(); - static void restoreGL(); - static void resetImpostors(); - static enum EWearableType getTEWearableType(LLVOAvatarDefines::ETextureIndex te ); - static LLUUID getDefaultTEImageID(LLVOAvatarDefines::ETextureIndex te ); - static void onChangeSelfInvisible(BOOL newvalue); - void setInvisible(BOOL newvalue); - static LLColor4 getDummyColor(); - - - - //-------------------------------------------------------------------- - // Clothing colors (conventience functions to access visual parameters - //-------------------------------------------------------------------- -public: - void setClothesColor( LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL set_by_user ); - LLColor4 getClothesColor( LLVOAvatarDefines::ETextureIndex te ); - BOOL teToColorParams( LLVOAvatarDefines::ETextureIndex te, const char* param_name[3] ); - - BOOL isWearingWearableType( EWearableType type ); - void wearableUpdated( EWearableType type ); - - //-------------------------------------------------------------------- - // texture compositing - //-------------------------------------------------------------------- -public: - void setLocTexTE( U8 te, LLViewerImage* image, BOOL set_by_user ); - void setupComposites(); - - //-------------------------------------------------------------------- - // Handling partially loaded avatars (Ruth) - //-------------------------------------------------------------------- -public: - BOOL isFullyLoaded(); - BOOL updateIsFullyLoaded(); private: - BOOL mFullyLoaded; - BOOL mPreviousFullyLoaded; - BOOL mFullyLoadedInitialized; - S32 mFullyLoadedFrameCounter; - LLFrameTimer mFullyLoadedTimer; + BOOL mSupportsAlphaLayers; // For backwards compatibility, TRUE for 1.23+ clients //-------------------------------------------------------------------- - // Collision Volumes + // Updates //-------------------------------------------------------------------- public: - S32 mNumCollisionVolumes; - LLViewerJointCollisionVolume* mCollisionVolumes; + virtual BOOL updateCharacter(LLAgent &agent); + void idleUpdateVoiceVisualizer(bool voice_enabled); + void idleUpdateMisc(bool detailed_update); + void idleUpdateAppearanceAnimation(); + void idleUpdateLipSync(bool voice_enabled); + void idleUpdateLoadingEffect(); + void idleUpdateWindEffect(); + void idleUpdateNameTag(const LLVector3& root_pos_last); + void idleUpdateRenderCost(); + void idleUpdateTractorBeam(); + void idleUpdateBelowWater(); //-------------------------------------------------------------------- - // cached pointers to well known joints - //-------------------------------------------------------------------- -public: - LLViewerJoint* mPelvisp; - LLViewerJoint* mTorsop; - LLViewerJoint* mChestp; - LLViewerJoint* mNeckp; - LLViewerJoint* mHeadp; - LLViewerJoint* mSkullp; - LLViewerJoint* mEyeLeftp; - LLViewerJoint* mEyeRightp; - LLViewerJoint* mHipLeftp; - LLViewerJoint* mHipRightp; - LLViewerJoint* mKneeLeftp; - LLViewerJoint* mKneeRightp; - LLViewerJoint* mAnkleLeftp; - LLViewerJoint* mAnkleRightp; - LLViewerJoint* mFootLeftp; - LLViewerJoint* mFootRightp; - LLViewerJoint* mWristLeftp; - LLViewerJoint* mWristRightp; - - //-------------------------------------------------------------------- - // impostor state - //-------------------------------------------------------------------- -public: - LLRenderTarget mImpostor; - BOOL mNeedsImpostorUpdate; -private: - LLVector3 mImpostorOffset; - LLVector2 mImpostorDim; - BOOL mNeedsAnimUpdate; - LLVector3 mImpostorExtents[2]; - LLVector3 mImpostorAngle; - F32 mImpostorDistance; - F32 mImpostorPixelArea; - LLVector3 mLastAnimExtents[2]; - - //-------------------------------------------------------------------- - // Misc Render State - //-------------------------------------------------------------------- -public: - BOOL mIsDummy; // For special views - S32 mSpecialRenderMode; // Special lighting - - //-------------------------------------------------------------------- - // animation state data - //-------------------------------------------------------------------- -public: - typedef std::map::iterator AnimIterator; - - std::map mSignaledAnimations; // requested state of Animation name/value - std::map mPlayingAnimations; // current state of Animation name/value - - typedef std::multimap AnimationSourceMap; - typedef AnimationSourceMap::iterator AnimSourceIterator; - AnimationSourceMap mAnimationSources; // object ids that triggered anim ids - - //-------------------------------------------------------------------- - // Shadowing - //-------------------------------------------------------------------- -public: - void updateShadowFaces(); - LLDrawable* mShadow; -private: - LLFace* mShadow0Facep; - LLFace* mShadow1Facep; - LLPointer mShadowImagep; - - //-------------------------------------------------------------------- - // Keeps track of foot step state for generating sounds - //-------------------------------------------------------------------- -public: - void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; } - LLVector4 mFootPlane; -private: - BOOL mWasOnGroundLeft; - BOOL mWasOnGroundRight; - - //-------------------------------------------------------------------- - // Pelvis height adjustment members. - //-------------------------------------------------------------------- -public: - LLVector3 mBodySize; - S32 mLastSkeletonSerialNum; -private: - F32 mPelvisToFoot; - - //-------------------------------------------------------------------- - // Display the name, then optionally fade it out - //-------------------------------------------------------------------- -public: - LLFrameTimer mChatTimer; - LLPointer mNameText; -private: - LLFrameTimer mTimeVisible; - std::deque mChats; - BOOL mTyping; - LLFrameTimer mTypingTimer; - - //-------------------------------------------------------------------- - // wind rippling in clothes - //-------------------------------------------------------------------- -public: - LLVector4 mWindVec; - F32 mRipplePhase; - BOOL mBelowWater; -private: - F32 mWindFreq; - LLFrameTimer mRippleTimer; - F32 mRippleTimeLast; - LLVector3 mRippleAccel; - LLVector3 mLastVel; - - //-------------------------------------------------------------------- - // appearance morphing - //-------------------------------------------------------------------- -public: - BOOL mAppearanceAnimating; -private: - LLFrameTimer mAppearanceMorphTimer; - BOOL mAppearanceAnimSetByUser; - F32 mLastAppearanceBlendTime; - - //-------------------------------------------------------------------- - // Attachments - //-------------------------------------------------------------------- -public: - // map of attachment points, by ID - typedef std::map attachment_map_t; - attachment_map_t mAttachmentPoints; - std::vector > mPendingAttachment; - - //-------------------------------------------------------------------- - // static preferences that are controlled by user settings/menus + // Static preferences (controlled by user settings/menus) //-------------------------------------------------------------------- public: static S32 sRenderName; @@ -513,6 +224,7 @@ public: static BOOL sShowAnimationDebug; // show animation debug info static BOOL sUseImpostors; //use impostors for far away avatars static BOOL sShowFootPlane; // show foot collision plane reported by server + static BOOL sShowCollisionVolumes; // show skeletal collision volumes static BOOL sVisibleInFirstPerson; static S32 sNumLODChangesThisFrame; static S32 sNumVisibleChatBubbles; @@ -520,243 +232,791 @@ public: static BOOL sShowAttachmentPoints; static F32 sLODFactor; // user-settable LOD factor static BOOL sJointDebug; // output total number of joints being touched for each avatar - static BOOL sDebugAvatarRotation; + static BOOL sDebugAvatarRotation; - static S32 sNumVisibleAvatars; // Number of instances of this class + //-------------------------------------------------------------------- + // Region state + //-------------------------------------------------------------------- +public: + LLHost getObjectHost() const; + + //-------------------------------------------------------------------- + // Loading state + //-------------------------------------------------------------------- +public: + BOOL isFullyLoaded() const; + virtual BOOL updateIsFullyLoaded(); + BOOL processFullyLoadedChange(bool loading); +private: + BOOL mFullyLoaded; + BOOL mPreviousFullyLoaded; + BOOL mFullyLoadedInitialized; + S32 mFullyLoadedFrameCounter; + LLFrameTimer mFullyLoadedTimer; + +/** State + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** SKELETON + **/ + +public: + void updateHeadOffset(); + F32 getPelvisToFoot() const { return mPelvisToFoot; } + LLVector3 mHeadOffset; // current head position + LLViewerJoint mRoot; +protected: + static BOOL parseSkeletonFile(const std::string& filename); + void buildCharacter(); + BOOL loadAvatar(); + BOOL setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); + BOOL buildSkeleton(const LLVOAvatarSkeletonInfo *info); +private: + BOOL mIsBuilt; // state of deferred character building + S32 mNumJoints; + LLViewerJoint* mSkeleton; //-------------------------------------------------------------------- - // Miscellaneous public variables. + // Pelvis height adjustment members. + //-------------------------------------------------------------------- +public: + LLVector3 mBodySize; + S32 mLastSkeletonSerialNum; +private: + F32 mPelvisToFoot; + + //-------------------------------------------------------------------- + // Cached pointers to well known joints + //-------------------------------------------------------------------- +public: + LLViewerJoint* mPelvisp; + LLViewerJoint* mTorsop; + LLViewerJoint* mChestp; + LLViewerJoint* mNeckp; + LLViewerJoint* mHeadp; + LLViewerJoint* mSkullp; + LLViewerJoint* mEyeLeftp; + LLViewerJoint* mEyeRightp; + LLViewerJoint* mHipLeftp; + LLViewerJoint* mHipRightp; + LLViewerJoint* mKneeLeftp; + LLViewerJoint* mKneeRightp; + LLViewerJoint* mAnkleLeftp; + LLViewerJoint* mAnkleRightp; + LLViewerJoint* mFootLeftp; + LLViewerJoint* mFootRightp; + LLViewerJoint* mWristLeftp; + LLViewerJoint* mWristRightp; + + //-------------------------------------------------------------------- + // XML parse tree + //-------------------------------------------------------------------- +private: + static LLXmlTree sXMLTree; // avatar config file + static LLXmlTree sSkeletonXMLTree; // avatar skeleton file + +/** Skeleton + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** RENDERING + **/ + +public: + U32 renderFootShadows(); + U32 renderImpostor(LLColor4U color = LLColor4U(255,255,255,255)); + U32 renderRigid(); + U32 renderSkinned(EAvatarRenderPass pass); + U32 renderTransparent(BOOL first_pass); + void renderCollisionVolumes(); + static void deleteCachedImages(bool clearAll=true); + static void destroyGL(); + static void restoreGL(); + BOOL mIsDummy; // for special views + S32 mSpecialRenderMode; // special lighting +private: + BOOL mNeedsSkin; // avatar has been animated and verts have not been updated + S32 mUpdatePeriod; + S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. + + //-------------------------------------------------------------------- + // Morph masks + //-------------------------------------------------------------------- +public: + void invalidateMorphMasks(LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + BOOL morphMaskNeedsUpdate(LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + void addMaskedMorph(LLVOAvatarDefines::EBakedTextureIndex index, LLPolyMorphTarget* morph_target, BOOL invert, std::string layer); + void setMorphMasksValid(BOOL new_status, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + void applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_components, LLVOAvatarDefines::EBakedTextureIndex index = LLVOAvatarDefines::BAKED_NUM_INDICES); + + //-------------------------------------------------------------------- + // Visibility + //-------------------------------------------------------------------- +protected: + void updateVisibility(); +private: + U32 mVisibilityRank; + BOOL mVisible; + + //-------------------------------------------------------------------- + // Shadowing + //-------------------------------------------------------------------- +public: + void updateShadowFaces(); + LLDrawable* mShadow; +private: + LLFace* mShadow0Facep; + LLFace* mShadow1Facep; + LLPointer mShadowImagep; + + //-------------------------------------------------------------------- + // Impostors + //-------------------------------------------------------------------- +public: + BOOL isImpostor() const; + BOOL needsImpostorUpdate() const; + const LLVector3& getImpostorOffset() const; + const LLVector2& getImpostorDim() const; + void getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const; + void cacheImpostorValues(); + void setImpostorDim(const LLVector2& dim); + static void resetImpostors(); + static void updateImpostors(); + LLRenderTarget mImpostor; + BOOL mNeedsImpostorUpdate; +private: + LLVector3 mImpostorOffset; + LLVector2 mImpostorDim; + BOOL mNeedsAnimUpdate; + LLVector3 mImpostorExtents[2]; + LLVector3 mImpostorAngle; + F32 mImpostorDistance; + F32 mImpostorPixelArea; + LLVector3 mLastAnimExtents[2]; + + //-------------------------------------------------------------------- + // Wind rippling in clothes + //-------------------------------------------------------------------- +public: + LLVector4 mWindVec; + F32 mRipplePhase; + BOOL mBelowWater; +private: + F32 mWindFreq; + LLFrameTimer mRippleTimer; + F32 mRippleTimeLast; + LLVector3 mRippleAccel; + LLVector3 mLastVel; + + //-------------------------------------------------------------------- + // Culling + //-------------------------------------------------------------------- +public: + static void cullAvatarsByPixelArea(); + BOOL isCulled() const { return mCulled; } +private: + BOOL mCulled; + + //-------------------------------------------------------------------- + // Freeze counter + //-------------------------------------------------------------------- +public: + static void updateFreezeCounter(S32 counter = 0); +private: + static S32 sFreezeCounter; + + //-------------------------------------------------------------------- + // Constants + //-------------------------------------------------------------------- +public: + virtual LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR; } + virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED; } + virtual S32 getTexImageSize() const; + virtual S32 getTexImageArea() const { return getTexImageSize()*getTexImageSize(); } + +/** Rendering + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** TEXTURES + **/ + + //-------------------------------------------------------------------- + // Loading status + //-------------------------------------------------------------------- +public: + virtual BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + BOOL isTextureVisible(LLVOAvatarDefines::ETextureIndex index) const; +protected: + BOOL isFullyBaked(); + static BOOL areAllNearbyInstancesBaked(S32& grey_avatars); + + //-------------------------------------------------------------------- + // Baked textures + //-------------------------------------------------------------------- +public: + void releaseComponentTextures(); // ! BACKWARDS COMPATIBILITY ! +protected: + static void onBakedTextureMasksLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + static void onInitialBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + static void onBakedTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + virtual void removeMissingBakedTextures(); + void useBakedTexture(const LLUUID& id); + + typedef std::deque morph_list_t; + struct BakedTextureData + { + LLUUID mLastTextureIndex; + LLTexLayerSet* mTexLayerSet; // Only exists for self + bool mIsLoaded; + bool mIsUsed; + LLVOAvatarDefines::ETextureIndex mTextureIndex; + U32 mMaskTexName; + // Stores pointers to the joint meshes that this baked texture deals with + std::vector< LLViewerJointMesh * > mMeshes; // std::vector mJoints[i]->mMeshParts + morph_list_t mMaskedMorphs; + BOOL mMorphMasksValid; + }; + typedef std::vector bakedtexturedata_vec_t; + bakedtexturedata_vec_t mBakedTextureDatas; + + //-------------------------------------------------------------------- + // Local Textures + //-------------------------------------------------------------------- +protected: + virtual void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index = 0); + virtual void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex type, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index = 0); + + //-------------------------------------------------------------------- + // Texture accessors + //-------------------------------------------------------------------- +private: + virtual void setImage(const U8 te, LLViewerTexture *imagep); + virtual LLViewerTexture* getImage(const U8 te) const; + + virtual const LLTextureEntry* getTexEntry(const U8 te_num) const; + virtual void setTexEntry(const U8 index, const LLTextureEntry &te); + + + //-------------------------------------------------------------------- + // Layers + //-------------------------------------------------------------------- +protected: + void deleteLayerSetCaches(bool clearAll = true); + void addBakedTextureStats(LLViewerFetchedTexture* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level); + + //-------------------------------------------------------------------- + // Composites + //-------------------------------------------------------------------- +public: + virtual void invalidateComposite(LLTexLayerSet* layerset, BOOL set_by_user); + virtual void invalidateAll(); + virtual void setCompositeUpdatesEnabled(BOOL b); + + //-------------------------------------------------------------------- + // Static texture/mesh/baked dictionary + //-------------------------------------------------------------------- +public: + static BOOL isIndexLocalTexture(LLVOAvatarDefines::ETextureIndex i); + static BOOL isIndexBakedTexture(LLVOAvatarDefines::ETextureIndex i); +private: + static const LLVOAvatarDefines::LLVOAvatarDictionary *getDictionary() { return sAvatarDictionary; } + static LLVOAvatarDefines::LLVOAvatarDictionary* sAvatarDictionary; + static LLVOAvatarSkeletonInfo* sAvatarSkeletonInfo; + static LLVOAvatarXmlInfo* sAvatarXmlInfo; + + //-------------------------------------------------------------------- + // Messaging + //-------------------------------------------------------------------- +public: + void onFirstTEMessageReceived(); +private: + BOOL mFirstTEMessageReceived; + BOOL mFirstAppearanceMessageReceived; + +/** Textures + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** MESHES + **/ + +public: + void updateMeshTextures(); + void updateSexDependentLayerSets(BOOL set_by_user); + void dirtyMesh(); // Dirty the avatar mesh + void updateMeshData(); +protected: + void releaseMeshData(); + /*virtual*/ void restoreMeshData(); +private: + BOOL mDirtyMesh; + + typedef std::multimap polymesh_map_t; + polymesh_map_t mMeshes; + std::vector mMeshLOD; + + //-------------------------------------------------------------------- + // Destroy invisible mesh + //-------------------------------------------------------------------- +protected: + BOOL mMeshValid; + LLFrameTimer mMeshInvisibleTime; + +/** Meshes + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** APPEARANCE + **/ + +public: + void processAvatarAppearance(LLMessageSystem* mesgsys); + void hideSkirt(); + void startAppearanceAnimation(BOOL set_by_user, BOOL play_sound); + + //-------------------------------------------------------------------- + // Appearance morphing + //-------------------------------------------------------------------- +public: + BOOL mAppearanceAnimating; +private: + LLFrameTimer mAppearanceMorphTimer; + BOOL mAppearanceAnimSetByUser; + F32 mLastAppearanceBlendTime; + + //-------------------------------------------------------------------- + // Clothing colors (convenience functions to access visual parameters) + //-------------------------------------------------------------------- +public: + void setClothesColor(LLVOAvatarDefines::ETextureIndex te, const LLColor4& new_color, BOOL set_by_user); + LLColor4 getClothesColor(LLVOAvatarDefines::ETextureIndex te); + BOOL teToColorParams(LLVOAvatarDefines::ETextureIndex te, const char* param_name[3]); + + //-------------------------------------------------------------------- + // Global colors + //-------------------------------------------------------------------- +public: + LLColor4 getGlobalColor(const std::string& color_name ) const; + void onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL set_by_user); +private: + LLTexGlobalColor* mTexSkinColor; + LLTexGlobalColor* mTexHairColor; + LLTexGlobalColor* mTexEyeColor; + + //-------------------------------------------------------------------- + // Visibility + //-------------------------------------------------------------------- +public: + BOOL isVisible() const; + void setVisibilityRank(U32 rank); + U32 getVisibilityRank() const { return mVisibilityRank; } // unused + static S32 sNumVisibleAvatars; // Number of instances of this class + static LLColor4 getDummyColor(); +/** Appearance + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** WEARABLES + **/ + +public: + BOOL isWearingWearableType(EWearableType type ) const; + + //-------------------------------------------------------------------- + // Attachments + //-------------------------------------------------------------------- +public: + void clampAttachmentPositions(); + virtual LLViewerJointAttachment* attachObject(LLViewerObject *viewer_object); + BOOL detachObject(LLViewerObject *viewer_object); + static LLVOAvatar* findAvatarFromAttachment(LLViewerObject* obj); +protected: + LLViewerJointAttachment* getTargetAttachmentPoint(LLViewerObject* viewer_object); + void lazyAttach(); + + //-------------------------------------------------------------------- + // Map of attachment points, by ID + //-------------------------------------------------------------------- +public: + S32 getAttachmentCount(); // Warning: order(N) not order(1) // currently used only by -self + typedef std::map attachment_map_t; + attachment_map_t mAttachmentPoints; + std::vector > mPendingAttachment; + + //-------------------------------------------------------------------- + // HUD functions + //-------------------------------------------------------------------- +public: + BOOL hasHUDAttachment() const; + LLBBox getHUDBBox() const; + void rebuildHUD(); + void resetHUDAttachments(); + +/** Wearables + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** ACTIONS + **/ + + //-------------------------------------------------------------------- + // Animations + //-------------------------------------------------------------------- +public: + BOOL isAnyAnimationSignaled(const LLUUID *anim_array, const S32 num_anims) const; + void processAnimationStateChanges(); +protected: + BOOL processSingleAnimationStateChange(const LLUUID &anim_id, BOOL start); + void resetAnimations(); +private: + LLTimer mAnimTimer; + F32 mTimeLast; + + //-------------------------------------------------------------------- + // Animation state data + //-------------------------------------------------------------------- +public: + typedef std::map::iterator AnimIterator; + std::map mSignaledAnimations; // requested state of Animation name/value + std::map mPlayingAnimations; // current state of Animation name/value + + typedef std::multimap AnimationSourceMap; + typedef AnimationSourceMap::iterator AnimSourceIterator; + AnimationSourceMap mAnimationSources; // object ids that triggered anim ids + + //-------------------------------------------------------------------- + // Chat + //-------------------------------------------------------------------- +public: + void addChat(const LLChat& chat); + void clearChat(); + void startTyping() { mTyping = TRUE; mTypingTimer.reset(); } + void stopTyping() { mTyping = FALSE; } +private: + BOOL mVisibleChat; + + //-------------------------------------------------------------------- + // Lip synch morphs + //-------------------------------------------------------------------- +private: + bool mLipSyncActive; // we're morphing for lip sync + LLVisualParam* mOohMorph; // cached pointers morphs for lip sync + LLVisualParam* mAahMorph; // cached pointers morphs for lip sync + + //-------------------------------------------------------------------- + // Flight //-------------------------------------------------------------------- public: BOOL mInAir; LLFrameTimer mTimeInAir; - LLVector3 mHeadOffset; // current head position - LLViewerJoint mRoot; // avatar skeleton - BOOL mIsSitting; // sitting state + +/** Actions + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** PHYSICS + **/ + +private: + F32 mSpeedAccum; // measures speed (for diagnostics mostly). + BOOL mTurning; // controls hysteresis on avatar rotation + F32 mSpeed; // misc. animation repeated state //-------------------------------------------------------------------- - // Private member variables. + // Collision volumes + //-------------------------------------------------------------------- +public: + S32 mNumCollisionVolumes; + LLViewerJointCollisionVolume* mCollisionVolumes; +protected: + BOOL allocateCollisionVolumes(U32 num); + + //-------------------------------------------------------------------- + // Dimensions + //-------------------------------------------------------------------- +public: + void resolveHeightGlobal(const LLVector3d &inPos, LLVector3d &outPos, LLVector3 &outNorm); + void resolveHeightAgent(const LLVector3 &inPos, LLVector3 &outPos, LLVector3 &outNorm); + void resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm); + void slamPosition(); // Slam position to transmitted position (for teleport); +protected: + void computeBodySize(); + + //-------------------------------------------------------------------- + // Material being stepped on //-------------------------------------------------------------------- private: - BOOL mIsSelf; // True if this avatar is for this viewer's agent + BOOL mStepOnLand; + U8 mStepMaterial; + LLVector3 mStepObjectVelocity; - LLViewerJoint *mScreenp; // special purpose joint for HUD attachments - BOOL mIsBuilt; // state of deferred character building - F32 mSpeedAccum; // measures speed (for diagnostics mostly). +/** Physics + ** ** + *******************************************************************************/ +/******************************************************************************** + ** ** + ** HIERARCHY + **/ + +public: + virtual BOOL setParent(LLViewerObject* parent); + virtual void addChild(LLViewerObject *childp); + virtual void removeChild(LLViewerObject *childp); + + //-------------------------------------------------------------------- + // Sitting + //-------------------------------------------------------------------- +public: + void sitDown(BOOL bSitting); + BOOL isSitting(){return mIsSitting;} + void sitOnObject(LLViewerObject *sit_object); + void getOffObject(); - // LLFrameTimer mUpdateLODTimer; // controls frequency of LOD change calculations - BOOL mDirtyMesh; - BOOL mTurning; // controls hysteresis on avatar rotation - F32 mSpeed; // misc. animation repeated state +private: + // set this property only with LLVOAvatar::sitDown method + BOOL mIsSitting; - // Keep track of the material being stepped on - BOOL mStepOnLand; - U8 mStepMaterial; - LLVector3 mStepObjectVelocity; +/** Hierarchy + ** ** + *******************************************************************************/ - // Destroy mesh data after being invisible for a while - BOOL mMeshValid; - BOOL mVisible; - LLFrameTimer mMeshInvisibleTime; +/******************************************************************************** + ** ** + ** NAME + **/ - // Lip synch morph stuff - bool mLipSyncActive; // we're morphing for lip sync - LLVisualParam* mOohMorph; // cached pointers morphs for lip sync - LLVisualParam* mAahMorph; // cached pointers morphs for lip sync +public: + std::string getFullname() const; // Returns "FirstName LastName" +protected: + static void getAnimLabels(LLDynamicArray* labels); + static void getAnimNames(LLDynamicArray* names); +private: + LLWString mNameString; + std::string mTitle; + BOOL mNameAway; + BOOL mNameBusy; + BOOL mNameMute; + BOOL mNameAppearance; + BOOL mRenderGroupTitles; - // Skeleton for skinned avatar - S32 mNumJoints; - LLViewerJoint* mSkeleton; + //-------------------------------------------------------------------- + // Display the name (then optionally fade it out) + //-------------------------------------------------------------------- +public: + LLFrameTimer mChatTimer; + LLPointer mNameText; +private: + LLFrameTimer mTimeVisible; + std::deque mChats; + BOOL mTyping; + LLFrameTimer mTypingTimer; - // Scratch textures used for compositing - static LLMap< LLGLenum, LLGLuint*> sScratchTexNames; - static LLMap< LLGLenum, F32*> sScratchTexLastBindTime; - static S32 sScratchTexBytes; +/** Name + ** ** + *******************************************************************************/ +/******************************************************************************** + ** ** + ** SOUNDS + **/ + + //-------------------------------------------------------------------- + // Voice visualizer + //-------------------------------------------------------------------- +public: + // Responsible for detecting the user's voice signal (and when the + // user speaks, it puts a voice symbol over the avatar's head) and gesticulations + LLVoiceVisualizer* mVoiceVisualizer; + int mCurrentGesticulationLevel; + + //-------------------------------------------------------------------- + // Step sound + //-------------------------------------------------------------------- +protected: + const LLUUID& getStepSound() const; +private: // Global table of sound ids per material, and the ground const static LLUUID sStepSounds[LL_MCODE_END]; const static LLUUID sStepSoundOnLand; - // Xml parse tree of avatar config file - static LLXmlTree sXMLTree; - // Xml parse tree of avatar skeleton file - static LLXmlTree sSkeletonXMLTree; - - // Voice Visualizer is responsible for detecting the user's voice signal, and when the - // user speaks, it puts a voice symbol over the avatar's head, and triggering gesticulations - LLVoiceVisualizer* mVoiceVisualizer; - int mCurrentGesticulationLevel; - - // Animation timer - LLTimer mAnimTimer; - F32 mTimeLast; - - LLPointer mBeam; - LLFrameTimer mBeamTimer; - - F32 mAdjustedPixelArea; - - LLWString mNameString; - std::string mTitle; - BOOL mNameAway; - BOOL mNameBusy; - BOOL mNameMute; - BOOL mNameAppearance; - BOOL mVisibleChat; - BOOL mRenderGroupTitles; - - std::string mDebugText; - U64 mLastRegionHandle; - LLFrameTimer mRegionCrossingTimer; - S32 mRegionCrossingCount; - //-------------------------------------------------------------------- - // local textures for compositing. + // Foot step state (for generating sounds) //-------------------------------------------------------------------- +public: + void setFootPlane(const LLVector4 &plane) { mFootPlane = plane; } + LLVector4 mFootPlane; private: - LLUUID mSavedTE[ LLVOAvatarDefines::TEX_NUM_INDICES ]; - BOOL mFirstTEMessageReceived; - BOOL mFirstAppearanceMessageReceived; - BOOL mHasBakedHair; + BOOL mWasOnGroundLeft; + BOOL mWasOnGroundRight; - BOOL mCulled; - U32 mVisibilityRank; - F32 mMinPixelArea; // debug - F32 mMaxPixelArea; // debug - BOOL mHasGrey; // debug +/** Sounds + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** DIAGNOSTICS + **/ - //-------------------------------------------------------------------- - // Global Colors - //-------------------------------------------------------------------- -private: - LLTexGlobalColor* mTexSkinColor; - LLTexGlobalColor* mTexHairColor; - LLTexGlobalColor* mTexEyeColor; +public: + static void dumpArchetypeXML(void*); + static void dumpBakedStatus(); + const std::string getBakedStatusForPrintout() const; + void dumpAvatarTEs(const std::string& context); - BOOL mNeedsSkin; //if TRUE, avatar has been animated and verts have not been updated - S32 mUpdatePeriod; - - //-------------------------------------------------------------------- - // Internal functions - //-------------------------------------------------------------------- + static F32 sUnbakedTime; // Total seconds with >=1 unbaked avatars + static F32 sUnbakedUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) + static F32 sGreyTime; // Total seconds with >=1 grey avatars + static F32 sGreyUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) protected: - void buildCharacter(); - void releaseMeshData(); - void restoreMeshData(); - void updateMeshData(); - void computeBodySize(); - const LLUUID& getStepSound() const; - BOOL needsRenderBeam(); - - BOOL allocateCollisionVolumes( U32 num ); - void resetHUDAttachments(); - static void getAnimLabels( LLDynamicArray* labels ); - static void getAnimNames( LLDynamicArray* names ); - - //-------------------------------------------------------------------- - // Textures and Layers - //-------------------------------------------------------------------- -protected: - BOOL loadSkeletonNode(); - BOOL loadMeshNodes(); - BOOL isFullyBaked(); - void deleteLayerSetCaches(bool clearAll = true); - static BOOL areAllNearbyInstancesBaked(S32& grey_avatars); - static void onBakedTextureMasksLoaded(BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - void setLocalTexture(LLVOAvatarDefines::ETextureIndex i, LLViewerImage* tex, BOOL baked_version_exits); - void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); - void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex i, LLViewerImage* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked); - void addBakedTextureStats( LLViewerImage* imagep, F32 pixel_area, F32 texel_area_ratio, S32 boost_level); - static void onInitialBakedTextureLoaded( BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata ); - static void onBakedTextureLoaded(BOOL success, LLViewerImage *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); - void useBakedTexture(const LLUUID& id); - void dumpAvatarTEs(const std::string& context); - void removeMissingBakedTextures(); - LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; - LLHost getObjectHost() const; - S32 getLocalDiscardLevel(LLVOAvatarDefines::ETextureIndex index); -public: - static void updateFreezeCounter(S32 counter = 0 ); + S32 getUnbakedPixelAreaRank(); + BOOL mHasGrey; private: - static S32 sFreezeCounter; + F32 mMinPixelArea; + F32 mMaxPixelArea; + F32 mAdjustedPixelArea; + std::string mDebugText; + +/** Diagnostics + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** SUPPORT CLASSES + **/ + +protected: // Shared with LLVOAvatarSelf + + struct LLVOAvatarXmlInfo + { + LLVOAvatarXmlInfo(); + ~LLVOAvatarXmlInfo(); + + BOOL parseXmlSkeletonNode(LLXmlTreeNode* root); + BOOL parseXmlMeshNodes(LLXmlTreeNode* root); + BOOL parseXmlColorNodes(LLXmlTreeNode* root); + BOOL parseXmlLayerNodes(LLXmlTreeNode* root); + BOOL parseXmlDriverNodes(LLXmlTreeNode* root); + BOOL parseXmlMorphNodes(LLXmlTreeNode* root); + + struct LLVOAvatarMeshInfo + { + typedef std::pair morph_info_pair_t; + typedef std::vector morph_info_list_t; + + LLVOAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {} + ~LLVOAvatarMeshInfo() + { + morph_info_list_t::iterator iter; + for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++) + { + delete iter->first; + } + mPolyMorphTargetInfoList.clear(); + } + + std::string mType; + S32 mLOD; + std::string mMeshFileName; + std::string mReferenceMeshName; + F32 mMinPixelArea; + morph_info_list_t mPolyMorphTargetInfoList; + }; + typedef std::vector mesh_info_list_t; + mesh_info_list_t mMeshInfoList; + + typedef std::vector skeletal_distortion_info_list_t; + skeletal_distortion_info_list_t mSkeletalDistortionInfoList; - //----------------------------------------------------------------------------------------------- - // Avatar skeleton setup. - //----------------------------------------------------------------------------------------------- -private: - BOOL loadAvatar(); - BOOL setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 ¤t_volume_num, S32 ¤t_joint_num); - BOOL buildSkeleton(const LLVOAvatarSkeletonInfo *info); + struct LLVOAvatarAttachmentInfo + { + LLVOAvatarAttachmentInfo() + : mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE), + mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {} + std::string mName; + std::string mJointName; + LLVector3 mPosition; + LLVector3 mRotationEuler; + S32 mGroup; + S32 mAttachmentID; + S32 mPieMenuSlice; + BOOL mVisibleFirstPerson; + BOOL mIsHUDAttachment; + BOOL mHasPosition; + BOOL mHasRotation; + }; + typedef std::vector attachment_info_list_t; + attachment_info_list_t mAttachmentInfoList; + + LLTexGlobalColorInfo *mTexSkinColorInfo; + LLTexGlobalColorInfo *mTexHairColorInfo; + LLTexGlobalColorInfo *mTexEyeColorInfo; - //----------------------------------------------------------------------------------------------- - // Per-avatar information about texture data. - // To-do: Move this to private implementation class - //----------------------------------------------------------------------------------------------- -private: - struct BakedTextureData - { - LLUUID mLastTextureIndex; - LLTexLayerSet* mTexLayerSet; - bool mIsLoaded; - bool mIsUsed; - LLVOAvatarDefines::ETextureIndex mTextureIndex; - U32 mMaskTexName; - // Stores pointers to the joint meshes that this baked texture deals with - std::vector< LLViewerJointMesh * > mMeshes; // std::vector mJoints[i]->mMeshParts + typedef std::vector layer_info_list_t; + layer_info_list_t mLayerInfoList; + + typedef std::vector driver_info_list_t; + driver_info_list_t mDriverInfoList; + + struct LLVOAvatarMorphInfo + { + LLVOAvatarMorphInfo() + : mInvert(FALSE) {} + std::string mName; + std::string mRegion; + std::string mLayer; + BOOL mInvert; + }; + + typedef std::vector morph_info_list_t; + morph_info_list_t mMorphMaskInfoList; }; - typedef std::vector bakedtexturedata_vec_t; - bakedtexturedata_vec_t mBakedTextureData; - struct LocalTextureData + struct LLMaskedMorph { - LocalTextureData() : mIsBakedReady(FALSE), mDiscard(MAX_DISCARD_LEVEL+1), mImage(NULL) - {} - LLPointer mImage; - BOOL mIsBakedReady; - S32 mDiscard; + LLMaskedMorph(LLPolyMorphTarget *morph_target, BOOL invert, std::string layer) : + mMorphTarget(morph_target), + mInvert(invert), + mLayer(layer) + { + morph_target->addPendingMorphMask(); + } + + LLPolyMorphTarget *mMorphTarget; + BOOL mInvert; + std::string mLayer; }; - typedef std::map localtexture_map_t; - localtexture_map_t mLocalTextureData; - typedef std::multimap polymesh_map_t; - polymesh_map_t mMeshes; - std::vector mMeshLOD; - S32 mNumInitFaces ; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. +/** Support classes + ** ** + *******************************************************************************/ - //----------------------------------------------------------------------------------------------- - // Static texture/mesh/baked dictionary for avatars - //----------------------------------------------------------------------------------------------- -public: - static BOOL isIndexLocalTexture(LLVOAvatarDefines::ETextureIndex i); - static BOOL isIndexBakedTexture(LLVOAvatarDefines::ETextureIndex i); -private: - static const LLVOAvatarDefines::LLVOAvatarDictionary *getDictionary() { return sAvatarDictionary; } - static LLVOAvatarDefines::LLVOAvatarDictionary *sAvatarDictionary; - static LLVOAvatarSkeletonInfo* sAvatarSkeletonInfo; - static LLVOAvatarXmlInfo* sAvatarXmlInfo; +}; // LLVOAvatar - //----------------------------------------------------------------------------------------------- - // Diagnostics - //----------------------------------------------------------------------------------------------- -public: - static F32 sUnbakedTime; // Total seconds with >=1 unbaked avatars - static F32 sUnbakedUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) - static F32 sGreyTime; // Total seconds with >=1 grey avatars - static F32 sGreyUpdateTime; // Last time stats were updated (to prevent multiple updates per frame) - - const std::string getBakedStatusForPrintout() const; -}; - -//----------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------ // Inlines -//----------------------------------------------------------------------------------------------- -inline BOOL LLVOAvatar::isTextureDefined(U8 te) const -{ - return (getTEImage(te)->getID() != IMG_DEFAULT_AVATAR && getTEImage(te)->getID() != IMG_DEFAULT); -} - -inline BOOL LLVOAvatar::isTextureVisible(U8 te) const +//------------------------------------------------------------------------ +inline BOOL LLVOAvatar::isTextureVisible(LLVOAvatarDefines::ETextureIndex te) const { return ((isTextureDefined(te) || isSelf()) && (getTEImage(te)->getID() != IMG_INVISIBLE diff --git a/indra/newview/llvoavatardefines.cpp b/indra/newview/llvoavatardefines.cpp index 19ad90a8e2..978a61972f 100644 --- a/indra/newview/llvoavatardefines.cpp +++ b/indra/newview/llvoavatardefines.cpp @@ -4,7 +4,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2007, Linden Research, Inc. + * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -12,12 +12,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -31,6 +32,7 @@ #include "llviewerprecompiledheaders.h" #include "llvoavatardefines.h" +#include "llviewercontrol.h" // gSavedSettings const S32 LLVOAvatarDefines::SCRATCH_TEX_WIDTH = 512; const S32 LLVOAvatarDefines::SCRATCH_TEX_HEIGHT = 512; @@ -41,56 +43,87 @@ using namespace LLVOAvatarDefines; /********************************************************************************* * Edit this function to add/remove/change textures and mesh definitions for avatars. */ -void LLVOAvatarDictionary::initData() + +LLVOAvatarDictionary::Textures::Textures() { - // Textures - mTextureMap[TEX_HEAD_BODYPAINT] = new TextureDictionaryEntry("head bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN); - mTextureMap[TEX_UPPER_SHIRT] = new TextureDictionaryEntry("shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", WT_SHIRT); - mTextureMap[TEX_LOWER_PANTS] = new TextureDictionaryEntry("pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", WT_PANTS); - mTextureMap[TEX_EYES_IRIS] = new TextureDictionaryEntry("iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", WT_EYES); - mTextureMap[TEX_HAIR] = new TextureDictionaryEntry("hair", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", WT_HAIR); - mTextureMap[TEX_UPPER_BODYPAINT] = new TextureDictionaryEntry("upper bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN); - mTextureMap[TEX_LOWER_BODYPAINT] = new TextureDictionaryEntry("lower bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN); - mTextureMap[TEX_LOWER_SHOES] = new TextureDictionaryEntry("shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", WT_SHOES); - mTextureMap[TEX_LOWER_SOCKS] = new TextureDictionaryEntry("socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", WT_SOCKS); - mTextureMap[TEX_UPPER_JACKET] = new TextureDictionaryEntry("upper jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET); - mTextureMap[TEX_LOWER_JACKET] = new TextureDictionaryEntry("lower jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET); - mTextureMap[TEX_UPPER_GLOVES] = new TextureDictionaryEntry("gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", WT_GLOVES); - mTextureMap[TEX_UPPER_UNDERSHIRT] = new TextureDictionaryEntry("undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERSHIRT); - mTextureMap[TEX_LOWER_UNDERPANTS] = new TextureDictionaryEntry("underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERPANTS); - mTextureMap[TEX_SKIRT] = new TextureDictionaryEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", WT_SKIRT); - mTextureMap[TEX_HEAD_BAKED] = new TextureDictionaryEntry("head-baked", FALSE, BAKED_HEAD); - mTextureMap[TEX_UPPER_BAKED] = new TextureDictionaryEntry("upper-baked", FALSE, BAKED_UPPER); - mTextureMap[TEX_LOWER_BAKED] = new TextureDictionaryEntry("lower-baked", FALSE, BAKED_LOWER); - mTextureMap[TEX_EYES_BAKED] = new TextureDictionaryEntry("eyes-baked", FALSE, BAKED_EYES); - mTextureMap[TEX_HAIR_BAKED] = new TextureDictionaryEntry("hair-baked", FALSE, BAKED_HAIR); - mTextureMap[TEX_SKIRT_BAKED] = new TextureDictionaryEntry("skirt-baked", FALSE, BAKED_SKIRT); + addEntry(TEX_HEAD_BODYPAINT, new TextureEntry("head_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN)); + addEntry(TEX_UPPER_SHIRT, new TextureEntry("upper_shirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShirtUUID", WT_SHIRT)); + addEntry(TEX_LOWER_PANTS, new TextureEntry("lower_pants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultPantsUUID", WT_PANTS)); + addEntry(TEX_EYES_IRIS, new TextureEntry("eyes_iris", TRUE, BAKED_NUM_INDICES, "UIImgDefaultEyesUUID", WT_EYES)); + addEntry(TEX_HAIR, new TextureEntry("hair_grain", TRUE, BAKED_NUM_INDICES, "UIImgDefaultHairUUID", WT_HAIR)); + addEntry(TEX_UPPER_BODYPAINT, new TextureEntry("upper_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN)); + addEntry(TEX_LOWER_BODYPAINT, new TextureEntry("lower_bodypaint", TRUE, BAKED_NUM_INDICES, "", WT_SKIN)); + addEntry(TEX_LOWER_SHOES, new TextureEntry("lower_shoes", TRUE, BAKED_NUM_INDICES, "UIImgDefaultShoesUUID", WT_SHOES)); + addEntry(TEX_LOWER_SOCKS, new TextureEntry("lower_socks", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSocksUUID", WT_SOCKS)); + addEntry(TEX_UPPER_JACKET, new TextureEntry("upper_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET)); + addEntry(TEX_LOWER_JACKET, new TextureEntry("lower_jacket", TRUE, BAKED_NUM_INDICES, "UIImgDefaultJacketUUID", WT_JACKET)); + addEntry(TEX_UPPER_GLOVES, new TextureEntry("upper_gloves", TRUE, BAKED_NUM_INDICES, "UIImgDefaultGlovesUUID", WT_GLOVES)); + addEntry(TEX_UPPER_UNDERSHIRT, new TextureEntry("upper_undershirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERSHIRT)); + addEntry(TEX_LOWER_UNDERPANTS, new TextureEntry("lower_underpants", TRUE, BAKED_NUM_INDICES, "UIImgDefaultUnderwearUUID", WT_UNDERPANTS)); + addEntry(TEX_SKIRT, new TextureEntry("skirt", TRUE, BAKED_NUM_INDICES, "UIImgDefaultSkirtUUID", WT_SKIRT)); + addEntry(TEX_LOWER_ALPHA, new TextureEntry("lower_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA)); + addEntry(TEX_UPPER_ALPHA, new TextureEntry("upper_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA)); + addEntry(TEX_HEAD_ALPHA, new TextureEntry("head_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA)); + addEntry(TEX_EYES_ALPHA, new TextureEntry("eyes_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA)); + addEntry(TEX_HAIR_ALPHA, new TextureEntry("hair_alpha", TRUE, BAKED_NUM_INDICES, "UIImgDefaultAlphaUUID", WT_ALPHA)); + addEntry(TEX_HEAD_TATTOO, new TextureEntry("head_tattoo", TRUE, BAKED_NUM_INDICES, "UIImgDefaultTattooUUID", WT_TATTOO)); + addEntry(TEX_UPPER_TATTOO, new TextureEntry("upper_tattoo", TRUE, BAKED_NUM_INDICES, "UIImgDefaultTattooUUID", WT_TATTOO)); + addEntry(TEX_LOWER_TATTOO, new TextureEntry("lower_tattoo", TRUE, BAKED_NUM_INDICES, "UIImgDefaultTattooUUID", WT_TATTOO)); + addEntry(TEX_HEAD_BAKED, new TextureEntry("head-baked", FALSE, BAKED_HEAD)); + addEntry(TEX_UPPER_BAKED, new TextureEntry("upper-baked", FALSE, BAKED_UPPER)); + addEntry(TEX_LOWER_BAKED, new TextureEntry("lower-baked", FALSE, BAKED_LOWER)); + addEntry(TEX_EYES_BAKED, new TextureEntry("eyes-baked", FALSE, BAKED_EYES)); + addEntry(TEX_HAIR_BAKED, new TextureEntry("hair-baked", FALSE, BAKED_HAIR)); + addEntry(TEX_SKIRT_BAKED, new TextureEntry("skirt-baked", FALSE, BAKED_SKIRT)); +} +LLVOAvatarDictionary::BakedTextures::BakedTextures() +{ // Baked textures - mBakedTextureMap[BAKED_HEAD] = new BakedDictionaryEntry(TEX_HEAD_BAKED, "head", 1, TEX_HEAD_BODYPAINT); - mBakedTextureMap[BAKED_UPPER] = new BakedDictionaryEntry(TEX_UPPER_BAKED, "upper_body", 5, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT,TEX_UPPER_JACKET,TEX_UPPER_GLOVES,TEX_UPPER_UNDERSHIRT); - mBakedTextureMap[BAKED_LOWER] = new BakedDictionaryEntry(TEX_LOWER_BAKED, "lower_body", 6, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES,TEX_LOWER_SOCKS,TEX_LOWER_JACKET,TEX_LOWER_UNDERPANTS); - mBakedTextureMap[BAKED_EYES] = new BakedDictionaryEntry(TEX_EYES_BAKED, "eyes", 1, TEX_EYES_IRIS); - mBakedTextureMap[BAKED_SKIRT] = new BakedDictionaryEntry(TEX_SKIRT_BAKED, "skirt", 1, TEX_SKIRT); - mBakedTextureMap[BAKED_HAIR] = new BakedDictionaryEntry(TEX_HAIR_BAKED, "hair", 1, TEX_HAIR); - - // Meshes - mMeshMap[MESH_ID_HAIR] = new MeshDictionaryEntry(BAKED_HAIR, "hairMesh", 6, LLViewerJoint::PN_4); - mMeshMap[MESH_ID_HEAD] = new MeshDictionaryEntry(BAKED_HEAD, "headMesh", 5, LLViewerJoint::PN_5); - mMeshMap[MESH_ID_EYELASH] = new MeshDictionaryEntry(BAKED_HEAD, "eyelashMesh", 1, LLViewerJoint::PN_0); // no baked mesh associated currently - mMeshMap[MESH_ID_UPPER_BODY] = new MeshDictionaryEntry(BAKED_UPPER, "upperBodyMesh", 5, LLViewerJoint::PN_1); - mMeshMap[MESH_ID_LOWER_BODY] = new MeshDictionaryEntry(BAKED_LOWER, "lowerBodyMesh", 5, LLViewerJoint::PN_2); - mMeshMap[MESH_ID_EYEBALL_LEFT] = new MeshDictionaryEntry(BAKED_EYES, "eyeBallLeftMesh", 2, LLViewerJoint::PN_3); - mMeshMap[MESH_ID_EYEBALL_RIGHT] = new MeshDictionaryEntry(BAKED_EYES, "eyeBallRightMesh", 2, LLViewerJoint::PN_3); - mMeshMap[MESH_ID_SKIRT] = new MeshDictionaryEntry(BAKED_SKIRT, "skirtMesh", 5, LLViewerJoint::PN_5); + addEntry(BAKED_HEAD, new BakedEntry(TEX_HEAD_BAKED, + "head", "18ded8d6-bcfc-e415-8539-944c0f5ea7a6", + 3, TEX_HEAD_BODYPAINT, TEX_HEAD_TATTOO, TEX_HEAD_ALPHA, + 5, WT_SHAPE, WT_SKIN, WT_HAIR, WT_TATTOO, WT_ALPHA)); - // Wearables - mWearableMap[BAKED_HEAD] = new WearableDictionaryEntry("18ded8d6-bcfc-e415-8539-944c0f5ea7a6", 3, WT_SHAPE, WT_SKIN, WT_HAIR); - mWearableMap[BAKED_UPPER] = new WearableDictionaryEntry("338c29e3-3024-4dbb-998d-7c04cf4fa88f", 6, WT_SHAPE, WT_SKIN, WT_SHIRT, WT_JACKET, WT_GLOVES, WT_UNDERSHIRT); - mWearableMap[BAKED_LOWER] = new WearableDictionaryEntry("91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f", 7, WT_SHAPE, WT_SKIN, WT_PANTS, WT_SHOES, WT_SOCKS, WT_JACKET, WT_UNDERPANTS); - mWearableMap[BAKED_EYES] = new WearableDictionaryEntry("b2cf28af-b840-1071-3c6a-78085d8128b5", 1, WT_EYES); - mWearableMap[BAKED_SKIRT] = new WearableDictionaryEntry("ea800387-ea1a-14e0-56cb-24f2022f969a", 1, WT_SKIRT); - mWearableMap[BAKED_HAIR] = new WearableDictionaryEntry("0af1ef7c-ad24-11dd-8790-001f5bf833e8", 1, WT_HAIR); + addEntry(BAKED_UPPER, new BakedEntry(TEX_UPPER_BAKED, + "upper_body", "338c29e3-3024-4dbb-998d-7c04cf4fa88f", + 7, TEX_UPPER_SHIRT,TEX_UPPER_BODYPAINT, TEX_UPPER_JACKET, + TEX_UPPER_GLOVES, TEX_UPPER_UNDERSHIRT, TEX_UPPER_TATTOO, TEX_UPPER_ALPHA, + 8, WT_SHAPE, WT_SKIN, WT_SHIRT, WT_JACKET, WT_GLOVES, WT_UNDERSHIRT, WT_TATTOO, WT_ALPHA)); + + addEntry(BAKED_LOWER, new BakedEntry(TEX_LOWER_BAKED, + "lower_body", "91b4a2c7-1b1a-ba16-9a16-1f8f8dcc1c3f", + 8, TEX_LOWER_PANTS,TEX_LOWER_BODYPAINT,TEX_LOWER_SHOES, TEX_LOWER_SOCKS, + TEX_LOWER_JACKET, TEX_LOWER_UNDERPANTS, TEX_LOWER_TATTOO, TEX_LOWER_ALPHA, + 9, WT_SHAPE, WT_SKIN, WT_PANTS, WT_SHOES, WT_SOCKS, WT_JACKET, WT_UNDERPANTS, WT_TATTOO, WT_ALPHA)); + + addEntry(BAKED_EYES, new BakedEntry(TEX_EYES_BAKED, + "eyes", "b2cf28af-b840-1071-3c6a-78085d8128b5", + 2, TEX_EYES_IRIS, TEX_EYES_ALPHA, + 2, WT_EYES, WT_ALPHA)); + + addEntry(BAKED_SKIRT, new BakedEntry(TEX_SKIRT_BAKED, + "skirt", "ea800387-ea1a-14e0-56cb-24f2022f969a", + 1, TEX_SKIRT, + 1, WT_SKIRT)); + + addEntry(BAKED_HAIR, new BakedEntry(TEX_HAIR_BAKED, + "hair", "0af1ef7c-ad24-11dd-8790-001f5bf833e8", + 2, TEX_HAIR, TEX_HAIR_ALPHA, + 2, WT_HAIR, WT_ALPHA)); +} + +LLVOAvatarDictionary::Meshes::Meshes() +{ + // Meshes + addEntry(MESH_ID_HAIR, new MeshEntry(BAKED_HAIR, "hairMesh", 6, LLViewerJoint::PN_4)); + addEntry(MESH_ID_HEAD, new MeshEntry(BAKED_HEAD, "headMesh", 5, LLViewerJoint::PN_5)); + addEntry(MESH_ID_EYELASH, new MeshEntry(BAKED_HEAD, "eyelashMesh", 1, LLViewerJoint::PN_0)); // no baked mesh associated currently + addEntry(MESH_ID_UPPER_BODY, new MeshEntry(BAKED_UPPER, "upperBodyMesh", 5, LLViewerJoint::PN_1)); + addEntry(MESH_ID_LOWER_BODY, new MeshEntry(BAKED_LOWER, "lowerBodyMesh", 5, LLViewerJoint::PN_2)); + addEntry(MESH_ID_EYEBALL_LEFT, new MeshEntry(BAKED_EYES, "eyeBallLeftMesh", 2, LLViewerJoint::PN_3)); + addEntry(MESH_ID_EYEBALL_RIGHT, new MeshEntry(BAKED_EYES, "eyeBallRightMesh", 2, LLViewerJoint::PN_3)); + addEntry(MESH_ID_SKIRT, new MeshEntry(BAKED_SKIRT, "skirtMesh", 5, LLViewerJoint::PN_5)); } /* @@ -99,18 +132,22 @@ void LLVOAvatarDictionary::initData() LLVOAvatarDictionary::LLVOAvatarDictionary() { - initData(); createAssociations(); } +//virtual +LLVOAvatarDictionary::~LLVOAvatarDictionary() +{ +} + // Baked textures are composites of textures; for each such composited texture, // map it to the baked texture. void LLVOAvatarDictionary::createAssociations() { - for (baked_map_t::const_iterator iter = mBakedTextureMap.begin(); iter != mBakedTextureMap.end(); iter++) + for (BakedTextures::const_iterator iter = mBakedTextures.begin(); iter != mBakedTextures.end(); iter++) { const EBakedTextureIndex baked_index = (iter->first); - const BakedDictionaryEntry *dict = (iter->second); + const BakedEntry *dict = (iter->second); // For each texture that this baked texture index affects, associate those textures // with this baked texture index. @@ -119,19 +156,19 @@ void LLVOAvatarDictionary::createAssociations() local_texture_iter++) { const ETextureIndex local_texture_index = (ETextureIndex) *local_texture_iter; - mTextureMap[local_texture_index]->mIsUsedByBakedTexture = true; - mTextureMap[local_texture_index]->mBakedTextureIndex = baked_index; + mTextures[local_texture_index]->mIsUsedByBakedTexture = true; + mTextures[local_texture_index]->mBakedTextureIndex = baked_index; } } } -LLVOAvatarDictionary::TextureDictionaryEntry::TextureDictionaryEntry(const std::string &name, - bool is_local_texture, - EBakedTextureIndex baked_texture_index, - const std::string &default_image_name, - EWearableType wearable_type) : - mName(name), +LLVOAvatarDictionary::TextureEntry::TextureEntry(const std::string &name, + bool is_local_texture, + EBakedTextureIndex baked_texture_index, + const std::string &default_image_name, + EWearableType wearable_type) : + LLDictionaryEntry(name), mIsLocalTexture(is_local_texture), mIsBakedTexture(!is_local_texture), mIsUsedByBakedTexture(baked_texture_index != BAKED_NUM_INDICES), @@ -141,87 +178,93 @@ LLVOAvatarDictionary::TextureDictionaryEntry::TextureDictionaryEntry(const std:: { } -LLVOAvatarDictionary::MeshDictionaryEntry::MeshDictionaryEntry(EBakedTextureIndex baked_index, - const std::string &name, - U8 level, - LLViewerJoint::PickName pick) : +LLVOAvatarDictionary::MeshEntry::MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, + U8 level, + LLViewerJoint::PickName pick) : + LLDictionaryEntry(name), mBakedID(baked_index), - mName(name), mLOD(level), mPickName(pick) { } -LLVOAvatarDictionary::BakedDictionaryEntry::BakedDictionaryEntry(ETextureIndex tex_index, - const std::string &name, - U32 num_local_textures, ... ) : - mName(name), +LLVOAvatarDictionary::BakedEntry::BakedEntry(ETextureIndex tex_index, + const std::string &name, + const std::string &hash_name, + U32 num_local_textures, + ... ) : + LLDictionaryEntry(name), + mWearablesHashID(LLUUID(hash_name)), mTextureIndex(tex_index) - { va_list argp; + va_start(argp, num_local_textures); + + // Read in local textures for (U8 i=0; i < num_local_textures; i++) { ETextureIndex t = (ETextureIndex)va_arg(argp,int); mLocalTextures.push_back(t); } -} -LLVOAvatarDictionary::WearableDictionaryEntry::WearableDictionaryEntry(const std::string &hash_name, - U32 num_wearables, ... ) : - mHashID(LLUUID(hash_name)) -{ - va_list argp; - va_start(argp, num_wearables); + // Read in number of wearables + const U32 num_wearables = (U32)va_arg(argp,int); + // Read in wearables for (U8 i=0; i < num_wearables; i++) { EWearableType t = (EWearableType)va_arg(argp,int); - mWearablesVec.push_back(t); + mWearables.push_back(t); } } -//virtual -LLVOAvatarDictionary::~LLVOAvatarDictionary() -{ - for (mesh_map_t::iterator iter = mMeshMap.begin(); iter != mMeshMap.end(); iter++) - delete (iter->second); - for (baked_map_t::iterator iter = mBakedTextureMap.begin(); iter != mBakedTextureMap.end(); iter++) - delete (iter->second); - for (texture_map_t::iterator iter = mTextureMap.begin(); iter != mTextureMap.end(); iter++) - delete (iter->second); -} - -const LLVOAvatarDictionary::MeshDictionaryEntry *LLVOAvatarDictionary::getMesh(EMeshIndex index) const -{ - mesh_map_t::const_iterator mesh_iter = mMeshMap.find(index); - if (mesh_iter == mMeshMap.end()) return NULL; - return mesh_iter->second; -} - -const LLVOAvatarDictionary::BakedDictionaryEntry *LLVOAvatarDictionary::getBakedTexture(EBakedTextureIndex index) const -{ - baked_map_t::const_iterator baked_iter = mBakedTextureMap.find(index); - if (baked_iter == mBakedTextureMap.end()) return NULL; - return baked_iter->second; -} - -const LLVOAvatarDictionary::TextureDictionaryEntry *LLVOAvatarDictionary::getTexture(ETextureIndex index) const -{ - texture_map_t::const_iterator texture_iter = mTextureMap.find(index); - if (texture_iter == mTextureMap.end()) return NULL; - return texture_iter->second; -} - -const LLVOAvatarDictionary::WearableDictionaryEntry *LLVOAvatarDictionary::getWearable(EBakedTextureIndex index) const -{ - wearable_map_t::const_iterator wearable_iter = mWearableMap.find(index); - if (wearable_iter == mWearableMap.end()) return NULL; - return wearable_iter->second; -} - - - -ETextureIndex LLVOAvatarDefines::getTextureIndex(EBakedTextureIndex index) +// static +ETextureIndex LLVOAvatarDictionary::bakedToLocalTextureIndex(EBakedTextureIndex index) { return LLVOAvatarDictionary::getInstance()->getBakedTexture(index)->mTextureIndex; } + +//static +EBakedTextureIndex LLVOAvatarDictionary::findBakedByRegionName(std::string name) +{ + U8 index = 0; + while (index < BAKED_NUM_INDICES) + { + const BakedEntry *be = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex) index); + if (be && be->mName.compare(name) == 0) + { + // baked texture found + return (EBakedTextureIndex) index; + } + index++; + } + // baked texture could not be found + return BAKED_NUM_INDICES; +} + +//static +const LLUUID LLVOAvatarDictionary::getDefaultTextureImageID(ETextureIndex index) +{ + /* switch( index ) + case TEX_UPPER_SHIRT: return LLUUID( gSavedSettings.getString("UIImgDefaultShirtUUID") ); */ + const TextureEntry *texture_dict = getInstance()->getTexture(index); + const std::string &default_image_name = texture_dict->mDefaultImageName; + if (default_image_name == "") + { + return IMG_DEFAULT_AVATAR; + } + else + { + return LLUUID(gSavedSettings.getString(default_image_name)); + } +} + +// static +EWearableType LLVOAvatarDictionary::getTEWearableType(ETextureIndex index ) +{ + /* switch(index) + case TEX_UPPER_SHIRT: + return WT_SHIRT; */ + return getInstance()->getTexture(index)->mWearableType; +} + diff --git a/indra/newview/llvoavatardefines.h b/indra/newview/llvoavatardefines.h index bc1a1f1c1f..cf3d318159 100644 --- a/indra/newview/llvoavatardefines.h +++ b/indra/newview/llvoavatardefines.h @@ -5,7 +5,7 @@ * * $LicenseInfo:firstyear=2001&license=viewergpl$ * - * Copyright (c) 2001-2007, Linden Research, Inc. + * Copyright (c) 2001-2009, Linden Research, Inc. * * Second Life Viewer Source Code * The source code in this file ("Source Code") is provided by Linden Lab @@ -13,12 +13,13 @@ * ("GPL"), unless you have obtained a separate licensing agreement * ("Other License"), formally executed by you and Linden Lab. Terms of * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 * * There are special exceptions to the terms and conditions of the GPL as * it is applied to this Source Code. View the full text of the exception * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, @@ -36,6 +37,7 @@ #include #include "llwearable.h" #include "llviewerjoint.h" +#include "lldictionary.h" namespace LLVOAvatarDefines { @@ -45,7 +47,7 @@ extern const S32 SCRATCH_TEX_HEIGHT; extern const S32 IMPOSTOR_PERIOD; //-------------------------------------------------------------------- -// texture entry assignment +// Enums //-------------------------------------------------------------------- enum ETextureIndex { @@ -57,9 +59,9 @@ enum ETextureIndex TEX_UPPER_BODYPAINT, TEX_LOWER_BODYPAINT, TEX_LOWER_SHOES, - TEX_HEAD_BAKED, // Pre-composited - TEX_UPPER_BAKED, // Pre-composited - TEX_LOWER_BAKED, // Pre-composited + TEX_HEAD_BAKED, // Pre-composited + TEX_UPPER_BAKED, // Pre-composited + TEX_LOWER_BAKED, // Pre-composited TEX_EYES_BAKED, // Pre-composited TEX_LOWER_SOCKS, TEX_UPPER_JACKET, @@ -68,14 +70,19 @@ enum ETextureIndex TEX_UPPER_UNDERSHIRT, TEX_LOWER_UNDERPANTS, TEX_SKIRT, - TEX_SKIRT_BAKED, // Pre-composited + TEX_SKIRT_BAKED, // Pre-composited TEX_HAIR_BAKED, // Pre-composited + TEX_LOWER_ALPHA, + TEX_UPPER_ALPHA, + TEX_HEAD_ALPHA, + TEX_EYES_ALPHA, + TEX_HAIR_ALPHA, + TEX_HEAD_TATTOO, + TEX_UPPER_TATTOO, + TEX_LOWER_TATTOO, TEX_NUM_INDICES -}; // "Note: if TEX_NUM_ENTRIES changes, update AGENT_TEXTURES in llagentinfo.h, mTextureIndexBaked, and BAKED_TEXTURE_COUNT" -// Seraph - Above comment about order is probably obsolete. +}; -typedef std::vector texture_vec_t; - enum EBakedTextureIndex { BAKED_HEAD = 0, @@ -86,7 +93,6 @@ enum EBakedTextureIndex BAKED_HAIR, BAKED_NUM_INDICES }; -typedef std::vector bakedtexture_vec_t; // Reference IDs for each mesh. Used as indices for vector of joints enum EMeshIndex @@ -101,19 +107,15 @@ enum EMeshIndex MESH_ID_SKIRT, MESH_ID_NUM_INDICES }; + +//-------------------------------------------------------------------- +// Vector Types +//-------------------------------------------------------------------- +typedef std::vector texture_vec_t; +typedef std::vector bakedtexture_vec_t; typedef std::vector mesh_vec_t; - typedef std::vector wearables_vec_t; -//-------------------------------------------------------------------------------- -// Convenience Functions -//-------------------------------------------------------------------------------- - -// Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED -ETextureIndex getTextureIndex(EBakedTextureIndex t); - - - //------------------------------------------------------------------------ // LLVOAvatarDictionary // @@ -124,86 +126,109 @@ ETextureIndex getTextureIndex(EBakedTextureIndex t); //------------------------------------------------------------------------ class LLVOAvatarDictionary : public LLSingleton { + //-------------------------------------------------------------------- + // Constructors and Destructors + //-------------------------------------------------------------------- public: LLVOAvatarDictionary(); virtual ~LLVOAvatarDictionary(); +private: + void createAssociations(); - struct TextureDictionaryEntry + //-------------------------------------------------------------------- + // Local and baked textures + //-------------------------------------------------------------------- +public: + struct TextureEntry : public LLDictionaryEntry { - TextureDictionaryEntry(const std::string &name, - bool is_local_texture, - EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES, - const std::string &default_image_name = "", - EWearableType wearable_type = WT_INVALID); - const std::string mName; - const std::string mDefaultImageName; + TextureEntry(const std::string &name, // this must match the xml name used by LLTexLayerInfo::parseXml + bool is_local_texture, + EBakedTextureIndex baked_texture_index = BAKED_NUM_INDICES, + const std::string& default_image_name = "", + EWearableType wearable_type = WT_INVALID); + const std::string mDefaultImageName; const EWearableType mWearableType; // It's either a local texture xor baked - BOOL mIsLocalTexture; - BOOL mIsBakedTexture; + BOOL mIsLocalTexture; + BOOL mIsBakedTexture; // If it's a local texture, it may be used by a baked texture - BOOL mIsUsedByBakedTexture; - EBakedTextureIndex mBakedTextureIndex; + BOOL mIsUsedByBakedTexture; + EBakedTextureIndex mBakedTextureIndex; }; - - struct MeshDictionaryEntry + + struct Textures : public LLDictionary { - MeshDictionaryEntry(EBakedTextureIndex baked_index, - const std::string &name, - U8 level, - LLViewerJoint::PickName pick); - const std::string mName; // names of mesh types as they are used in avatar_lad.xml + Textures(); + } mTextures; + const TextureEntry* getTexture(ETextureIndex index) const { return mTextures.lookup(index); } + const Textures& getTextures() const { return mTextures; } + + //-------------------------------------------------------------------- + // Meshes + //-------------------------------------------------------------------- +public: + struct MeshEntry : public LLDictionaryEntry + { + MeshEntry(EBakedTextureIndex baked_index, + const std::string &name, // names of mesh types as they are used in avatar_lad.xml + U8 level, + LLViewerJoint::PickName pick); // Levels of Detail for each mesh. Must match levels of detail present in avatar_lad.xml // Otherwise meshes will be unable to be found, or levels of detail will be ignored - const U8 mLOD; - const EBakedTextureIndex mBakedID; - const LLViewerJoint::PickName mPickName; + const U8 mLOD; + const EBakedTextureIndex mBakedID; + const LLViewerJoint::PickName mPickName; }; - struct BakedDictionaryEntry + struct Meshes : public LLDictionary { - BakedDictionaryEntry(ETextureIndex tex_index, - const std::string &name, - U32 num_local_textures, ... ); + Meshes(); + } mMeshes; + const MeshEntry* getMesh(EMeshIndex index) const { return mMeshes.lookup(index); } + const Meshes& getMeshes() const { return mMeshes; } + + //-------------------------------------------------------------------- + // Baked Textures + //-------------------------------------------------------------------- +public: + struct BakedEntry : public LLDictionaryEntry + { + BakedEntry(ETextureIndex tex_index, + const std::string &name, // unused, but necessary for templating. + const std::string &hash_name, + U32 num_local_textures, ... ); // # local textures, local texture list, # wearables, wearable list + // Local Textures const ETextureIndex mTextureIndex; - const std::string mName; - texture_vec_t mLocalTextures; + texture_vec_t mLocalTextures; + // Wearables + const LLUUID mWearablesHashID; + wearables_vec_t mWearables; }; - - struct WearableDictionaryEntry + + struct BakedTextures: public LLDictionary { - WearableDictionaryEntry(const std::string &hash_name, - U32 num_wearables, ... ); - const LLUUID mHashID; - wearables_vec_t mWearablesVec; - }; - - typedef std::map baked_map_t; - typedef std::map texture_map_t; - typedef std::map mesh_map_t; - typedef std::map wearable_map_t; - - const MeshDictionaryEntry *getMesh(EMeshIndex index) const; - const BakedDictionaryEntry *getBakedTexture(EBakedTextureIndex index) const; - const TextureDictionaryEntry *getTexture(ETextureIndex index) const; - const WearableDictionaryEntry *getWearable(EBakedTextureIndex index) const; - - const texture_map_t &getTextures() const { return mTextureMap; } - const baked_map_t &getBakedTextures() const { return mBakedTextureMap; } - const mesh_map_t &getMeshes() const { return mMeshMap; } - const wearable_map_t &getWearables() const { return mWearableMap; } + BakedTextures(); + } mBakedTextures; + const BakedEntry* getBakedTexture(EBakedTextureIndex index) const { return mBakedTextures.lookup(index); } + const BakedTextures& getBakedTextures() const { return mBakedTextures; } -private: - void initData(); - void createAssociations(); + //-------------------------------------------------------------------- + // Convenience Functions + //-------------------------------------------------------------------- +public: + // Convert from baked texture to associated texture; e.g. BAKED_HEAD -> TEX_HEAD_BAKED + static ETextureIndex bakedToLocalTextureIndex(EBakedTextureIndex t); - texture_map_t mTextureMap; - baked_map_t mBakedTextureMap; - mesh_map_t mMeshMap; - wearable_map_t mWearableMap; + // find a baked texture index based on its name + static EBakedTextureIndex findBakedByRegionName(std::string name); + + static const LLUUID getDefaultTextureImageID(ETextureIndex index); + + // Given a texture entry, determine which wearable type owns it. + static EWearableType getTEWearableType(ETextureIndex index); }; // End LLVOAvatarDictionary } // End namespace LLVOAvatarDefines -#endif +#endif //LL_VO_AVATARDEFINES_H diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp new file mode 100644 index 0000000000..a7b5b60842 --- /dev/null +++ b/indra/newview/llvoavatarself.cpp @@ -0,0 +1,2044 @@ +/** + * @file llvoavatar.cpp + * @brief Implementation of LLVOAvatar class which is a derivation fo LLViewerObject + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llvoavatarself.h" +#include "llvoavatar.h" + +#include +#include + +#include "llaudioengine.h" +#include "noise.h" + +// TODO: Seraph - Remove unnecessary headers. These are copied from llvoavatar.h. +#include "llagent.h" // Get state values from here +#include "llagentwearables.h" +#include "llviewercontrol.h" +#include "lldrawpoolavatar.h" +#include "lldriverparam.h" +#include "lleditingmotion.h" +#include "llemote.h" +#include "llface.h" +#include "llfirstuse.h" +#include "llheadrotmotion.h" +#include "llhudeffecttrail.h" +#include "llhudmanager.h" +#include "llkeyframefallmotion.h" +#include "llkeyframestandmotion.h" +#include "llkeyframewalkmotion.h" +#include "llmutelist.h" +#include "llselectmgr.h" +#include "llsprite.h" +#include "lltargetingmotion.h" +#include "lltexlayer.h" +#include "lltexglobalcolor.h" +#include "lltoolgrab.h" // for needsRenderBeam +#include "lltoolmgr.h" // for needsRenderBeam +#include "lltoolmorph.h" +#include "lltrans.h" +#include "llviewercamera.h" +#include "llviewertexturelist.h" +#include "llviewermenu.h" +#include "llviewerobjectlist.h" +#include "llviewerparcelmgr.h" +#include "llviewerstats.h" +#include "llvovolume.h" +#include "llworld.h" +#include "pipeline.h" +#include "llviewershadermgr.h" +#include "llsky.h" +#include "llanimstatelabels.h" +#include "llgesturemgr.h" //needed to trigger the voice gesticulations +#include "llvoiceclient.h" +#include "llvoicevisualizer.h" // Ventrella + +#include "boost/lexical_cast.hpp" + +using namespace LLVOAvatarDefines; + +/********************************************************************************* + ** ** + ** Begin private LLVOAvatarSelf Support classes + ** + **/ + +struct LocalTextureData +{ + LocalTextureData() : + mIsBakedReady(FALSE), + mDiscard(MAX_DISCARD_LEVEL+1), + mImage(NULL), + mWearableID(IMG_DEFAULT_AVATAR), + mTexEntry(NULL) + {} + LLPointer mImage; + BOOL mIsBakedReady; + S32 mDiscard; + LLUUID mWearableID; // UUID of the wearable that this texture belongs to, not of the image itself + LLTextureEntry *mTexEntry; +}; + +//----------------------------------------------------------------------------- +// Callback data +//----------------------------------------------------------------------------- +struct LLAvatarTexData +{ + LLAvatarTexData(const LLUUID& id, ETextureIndex index) : + mAvatarID(id), + mIndex(index) + {} + LLUUID mAvatarID; + ETextureIndex mIndex; +}; + +/** + ** + ** End LLVOAvatarSelf Support classes + ** ** + *********************************************************************************/ + + +//----------------------------------------------------------------------------- +// Static Data +//----------------------------------------------------------------------------- +S32 LLVOAvatarSelf::sScratchTexBytes = 0; +LLMap< LLGLenum, LLGLuint*> LLVOAvatarSelf::sScratchTexNames; +LLMap< LLGLenum, F32*> LLVOAvatarSelf::sScratchTexLastBindTime; + + +/********************************************************************************* + ** ** + ** Begin LLVOAvatarSelf Constructor routines + ** + **/ + +LLVOAvatarSelf::LLVOAvatarSelf(const LLUUID& id, + const LLPCode pcode, + LLViewerRegion* regionp) : + LLVOAvatar(id, pcode, regionp), + mScreenp(NULL), + mLastRegionHandle(0), + mRegionCrossingCount(0) +{ + gAgent.setAvatarObject(this); + gAgentWearables.setAvatarObject(this); + + lldebugs << "Marking avatar as self " << id << llendl; +} + +void LLVOAvatarSelf::initInstance() +{ + BOOL status = TRUE; + // creates hud joint(mScreen) among other things + status &= loadAvatarSelf(); + + // adds attachment points to mScreen among other things + LLVOAvatar::initInstance(); + + status &= buildMenus(); + if (!status) + { + llerrs << "Unable to load user's avatar" << llendl; + return; + } +} + +// virtual +void LLVOAvatarSelf::markDead() +{ + mBeam = NULL; + LLVOAvatar::markDead(); +} + +BOOL LLVOAvatarSelf::loadAvatarSelf() +{ + BOOL success = TRUE; + // avatar_skeleton.xml + if (!buildSkeletonSelf(sAvatarSkeletonInfo)) + { + llwarns << "avatar file: buildSkeleton() failed" << llendl; + return FALSE; + } + // TODO: make loadLayersets() called only by self. + //success &= loadLayersets(); + + return success; +} + +BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + // add special-purpose "screen" joint + mScreenp = new LLViewerJoint("mScreen", NULL); + // for now, put screen at origin, as it is only used during special + // HUD rendering mode + F32 aspect = LLViewerCamera::getInstance()->getAspect(); + LLVector3 scale(1.f, aspect, 1.f); + mScreenp->setScale(scale); + mScreenp->setWorldPosition(LLVector3::zero); + return TRUE; +} + +BOOL LLVOAvatarSelf::buildMenus() +{ + //------------------------------------------------------------------------- + // build the attach and detach menus + //------------------------------------------------------------------------- + gAttachBodyPartPieMenus[0] = NULL; + + LLContextMenu::Params params; + params.label(LLTrans::getString("BodyPartsRightArm") + " >"); + params.name(params.label); + params.visible(false); + gAttachBodyPartPieMenus[1] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsHead") + " >"); + params.name(params.label); + gAttachBodyPartPieMenus[2] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsLeftArm") + " >"); + params.name(params.label); + gAttachBodyPartPieMenus[3] = LLUICtrlFactory::create (params); + + gAttachBodyPartPieMenus[4] = NULL; + + params.label(LLTrans::getString("BodyPartsLeftLeg") + " >"); + params.name(params.label); + gAttachBodyPartPieMenus[5] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsTorso") + " >"); + params.name(params.label); + gAttachBodyPartPieMenus[6] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsRightLeg") + " >"); + params.name(params.label); + gAttachBodyPartPieMenus[7] = LLUICtrlFactory::create (params); + + gDetachBodyPartPieMenus[0] = NULL; + + params.label(LLTrans::getString("BodyPartsRightArm") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[1] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsHead") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[2] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsLeftArm") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[3] = LLUICtrlFactory::create (params); + + gDetachBodyPartPieMenus[4] = NULL; + + params.label(LLTrans::getString("BodyPartsLeftLeg") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[5] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsTorso") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[6] = LLUICtrlFactory::create (params); + + params.label(LLTrans::getString("BodyPartsRightLeg") + " >"); + params.name(params.label); + gDetachBodyPartPieMenus[7] = LLUICtrlFactory::create (params); + + for (S32 i = 0; i < 8; i++) + { + if (gAttachBodyPartPieMenus[i]) + { + gAttachPieMenu->appendContextSubMenu( gAttachBodyPartPieMenus[i] ); + } + else + { + BOOL attachment_found = FALSE; + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getGroup() == i) + { + LLMenuItemCallGL::Params item_params; + + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = curiter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create(item_params); + + gAttachPieMenu->addChild(item); + + attachment_found = TRUE; + break; + + } + } + + if (!attachment_found) + { + gAttachPieMenu->addSeparator(); + } + } + + if (gDetachBodyPartPieMenus[i]) + { + gDetachPieMenu->appendContextSubMenu( gDetachBodyPartPieMenus[i] ); + } + else + { + BOOL attachment_found = FALSE; + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getGroup() == i) + { + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Attachment.Detach"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Attachment.EnableDetach"; + item_params.on_enable.parameter = curiter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create(item_params); + + gDetachPieMenu->addChild(item); + + attachment_found = TRUE; + break; + } + } + + if (!attachment_found) + { + gDetachPieMenu->addSeparator(); + } + } + } + + // add screen attachments + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getGroup() == 8) + { + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = curiter->first; + LLMenuItemCallGL* item = LLUICtrlFactory::create(item_params); + gAttachScreenPieMenu->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = curiter->first; + item = LLUICtrlFactory::create(item_params); + gDetachScreenPieMenu->addChild(item); + } + } + + for (S32 pass = 0; pass < 2; pass++) + { + // *TODO: Skinning - gAttachSubMenu is an awful, awful hack + if (!gAttachSubMenu) + { + break; + } + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getIsHUDAttachment() != (pass == 1)) + { + continue; + } + LLMenuItemCallGL::Params item_params; + std::string sub_piemenu_name = attachment->getName(); + if (LLTrans::getString(sub_piemenu_name) != "") + { + item_params.label = LLTrans::getString(sub_piemenu_name); + } + else + { + item_params.label = sub_piemenu_name; + } + item_params.name =(item_params.label ); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = curiter->first; + //* TODO: Skinning: + //LLSD params; + //params["index"] = curiter->first; + //params["label"] = attachment->getName(); + //item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params)); + + LLMenuItemCallGL* item = LLUICtrlFactory::create(item_params); + gAttachSubMenu->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = curiter->first; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = curiter->first; + //* TODO: Skinning: item->addEventHandler("on_enable", LLMenuItemCallGL::MenuCallback().function_name("Attachment.Label").parameter(params)); + + item = LLUICtrlFactory::create(item_params); + gDetachSubMenu->addChild(item); + } + if (pass == 0) + { + // put separator between non-hud and hud attachments + gAttachSubMenu->addSeparator(); + gDetachSubMenu->addSeparator(); + } + } + + for (S32 group = 0; group < 8; group++) + { + // skip over groups that don't have sub menus + if (!gAttachBodyPartPieMenus[group] || !gDetachBodyPartPieMenus[group]) + { + continue; + } + + std::multimap attachment_pie_menu_map; + + // gather up all attachment points assigned to this group, and throw into map sorted by pie slice number + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if(attachment->getGroup() == group) + { + // use multimap to provide a partial order off of the pie slice key + S32 pie_index = attachment->getPieSlice(); + attachment_pie_menu_map.insert(std::make_pair(pie_index, curiter->first)); + } + } + + // add in requested order to pie menu, inserting separators as necessary + S32 cur_pie_slice = 0; + for (std::multimap::iterator attach_it = attachment_pie_menu_map.begin(); + attach_it != attachment_pie_menu_map.end(); ++attach_it) + { + S32 requested_pie_slice = attach_it->first; + S32 attach_index = attach_it->second; + while (cur_pie_slice < requested_pie_slice) + { + gAttachBodyPartPieMenus[group]->addSeparator(); + gDetachBodyPartPieMenus[group]->addSeparator(); + cur_pie_slice++; + } + + LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attach_index, (LLViewerJointAttachment*)NULL); + if (attachment) + { + LLMenuItemCallGL::Params item_params; + item_params.name = attachment->getName(); + item_params.label = attachment->getName(); + item_params.on_click.function_name = "Object.AttachToAvatar"; + item_params.on_click.parameter = attach_index; + item_params.on_enable.function_name = "Object.EnableWear"; + item_params.on_enable.parameter = attach_index; + + LLMenuItemCallGL* item = LLUICtrlFactory::create(item_params); + gAttachBodyPartPieMenus[group]->addChild(item); + + item_params.on_click.function_name = "Attachment.DetachFromPoint"; + item_params.on_click.parameter = attach_index; + item_params.on_enable.function_name = "Attachment.PointFilled"; + item_params.on_enable.parameter = attach_index; + item = LLUICtrlFactory::create(item_params); + gDetachBodyPartPieMenus[group]->addChild(item); + cur_pie_slice++; + } + } + } + return TRUE; +} + +LLVOAvatarSelf::~LLVOAvatarSelf() +{ + gAgent.setAvatarObject(NULL); + gAgentWearables.setAvatarObject(NULL); + delete mScreenp; + mScreenp = NULL; +} + +/** + ** + ** End LLVOAvatarSelf Constructor routines + ** ** + *********************************************************************************/ + +//virtual +BOOL LLVOAvatarSelf::loadLayersets() +{ + BOOL success = TRUE; + for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator iter = sAvatarXmlInfo->mLayerInfoList.begin(); + iter != sAvatarXmlInfo->mLayerInfoList.end(); + iter++) + { + // Construct a layerset for each one specified in avatar_lad.xml and initialize it as such. + const LLTexLayerSetInfo *info = *iter; + LLTexLayerSet* layer_set = new LLTexLayerSet( this ); + + if (!layer_set->setInfo(info)) + { + stop_glerror(); + delete layer_set; + llwarns << "avatar file: layer_set->parseData() failed" << llendl; + return FALSE; + } + + // scan baked textures and associate the layerset with the appropriate one + EBakedTextureIndex baked_index = BAKED_NUM_INDICES; + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + baked_iter++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + if (layer_set->isBodyRegion(baked_dict->mName)) + { + baked_index = baked_iter->first; + // ensure both structures are aware of each other + mBakedTextureDatas[baked_index].mTexLayerSet = layer_set; + layer_set->setBakedTexIndex(baked_index); + break; + } + } + // if no baked texture was found, warn and cleanup + if (baked_index == BAKED_NUM_INDICES) + { + llwarns << " has invalid body_region attribute" << llendl; + delete layer_set; + return FALSE; + } + + // scan morph masks and let any affected layers know they have an associated morph + for (LLVOAvatar::morph_list_t::const_iterator morph_iter = mBakedTextureDatas[baked_index].mMaskedMorphs.begin(); + morph_iter != mBakedTextureDatas[baked_index].mMaskedMorphs.end(); + morph_iter++) + { + LLMaskedMorph *morph = *morph_iter; + LLTexLayer * layer = layer_set->findLayerByName(morph->mLayer); + if (layer) + { + layer->setHasMorph(TRUE); + } + else + { + llwarns << "Could not find layer named " << morph->mLayer << " to set morph flag" << llendl; + success = FALSE; + } + } + } + return success; +} +// virtual +BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent) +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + // update screen joint size + if (mScreenp) + { + F32 aspect = LLViewerCamera::getInstance()->getAspect(); + LLVector3 scale(1.f, aspect, 1.f); + mScreenp->setScale(scale); + mScreenp->updateWorldMatrixChildren(); + resetHUDAttachments(); + } + return LLVOAvatar::updateCharacter(agent); +} + +// virtual +LLJoint *LLVOAvatarSelf::getJoint(const std::string &name) +{ + if (mScreenp) + { + LLJoint* jointp = mScreenp->findJoint(name); + if (jointp) return jointp; + } + return LLVOAvatar::getJoint(name); +} + +// virtual +void LLVOAvatarSelf::requestStopMotion(LLMotion* motion) +{ + // Only agent avatars should handle the stop motion notifications. + + // Notify agent that motion has stopped + gAgent.requestStopMotion(motion); +} + +// virtual +void LLVOAvatarSelf::stopMotionFromSource(const LLUUID& source_id) +{ + for (AnimSourceIterator motion_it = mAnimationSources.find(source_id); motion_it != mAnimationSources.end(); ) + { + gAgent.sendAnimationRequest(motion_it->second, ANIM_REQUEST_STOP); + mAnimationSources.erase(motion_it++); + } + + LLViewerObject* object = gObjectList.findObject(source_id); + if (object) + { + object->mFlags &= ~FLAGS_ANIM_SOURCE; + } +} + +// virtual +void LLVOAvatarSelf::setLocalTextureTE(U8 te, LLViewerTexture* image, BOOL set_by_user, U32 index) +{ + if (te >= TEX_NUM_INDICES) + { + llassert(0); + return; + } + + if (getTEImage(te)->getID() == image->getID()) + { + return; + } + + if (isIndexBakedTexture((ETextureIndex)te)) + { + llassert(0); + return; + } + + LLTexLayerSet* layer_set = getLayerSet((ETextureIndex)te); + if (layer_set) + { + invalidateComposite(layer_set, set_by_user); + } + + setTEImage(te, image); + updateMeshTextures(); + + if (gAgent.cameraCustomizeAvatar()) + { + LLVisualParamHint::requestHintUpdates(); + } +} + +//virtual +void LLVOAvatarSelf::removeMissingBakedTextures() +{ + BOOL removed = FALSE; + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + const S32 te = mBakedTextureDatas[i].mTextureIndex; + LLViewerTexture* tex = getTEImage(te) ; + if (!tex || tex->isMissingAsset()) + { + setTEImage(te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR)); + removed = TRUE; + } + } + + if (removed) + { + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, FALSE); + } + updateMeshTextures(); + requestLayerSetUploads(); + } +} + +//virtual +void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp) +{ + if (regionp->getHandle() != mLastRegionHandle) + { + if (mLastRegionHandle != 0) + { + ++mRegionCrossingCount; + F64 delta = (F64)mRegionCrossingTimer.getElapsedTimeF32(); + F64 avg = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_AVG); + F64 delta_avg = (delta + avg*(mRegionCrossingCount-1)) / mRegionCrossingCount; + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_AVG, delta_avg); + + F64 max = (mRegionCrossingCount == 1) ? 0 : LLViewerStats::getInstance()->getStat(LLViewerStats::ST_CROSSING_MAX); + max = llmax(delta, max); + LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CROSSING_MAX, max); + } + mLastRegionHandle = regionp->getHandle(); + } + mRegionCrossingTimer.reset(); +} + +//-------------------------------------------------------------------- +// draw tractor beam when editing objects +//-------------------------------------------------------------------- +//virtual +void LLVOAvatarSelf::idleUpdateTractorBeam() +{ + // This is only done for yourself (maybe it should be in the agent?) + if (!needsRenderBeam() || !mIsBuilt) + { + mBeam = NULL; + } + else if (!mBeam || mBeam->isDead()) + { + // VEFFECT: Tractor Beam + mBeam = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BEAM); + mBeam->setColor(LLColor4U(gAgent.getEffectColor())); + mBeam->setSourceObject(this); + mBeamTimer.reset(); + } + + if (!mBeam.isNull()) + { + LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); + + if (gAgent.mPointAt.notNull()) + { + // get point from pointat effect + mBeam->setPositionGlobal(gAgent.mPointAt->getPointAtPosGlobal()); + mBeam->triggerLocal(); + } + else if (selection->getFirstRootObject() && + selection->getSelectType() != SELECT_TYPE_HUD) + { + LLViewerObject* objectp = selection->getFirstRootObject(); + mBeam->setTargetObject(objectp); + } + else + { + mBeam->setTargetObject(NULL); + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + if (tool->isEditing()) + { + if (tool->getEditingObject()) + { + mBeam->setTargetObject(tool->getEditingObject()); + } + else + { + mBeam->setPositionGlobal(tool->getEditingPointGlobal()); + } + } + else + { + const LLPickInfo& pick = gViewerWindow->getLastPick(); + mBeam->setPositionGlobal(pick.mPosGlobal); + } + + } + if (mBeamTimer.getElapsedTimeF32() > 0.25f) + { + mBeam->setColor(LLColor4U(gAgent.getEffectColor())); + mBeam->setNeedsSendToSim(TRUE); + mBeamTimer.reset(); + } + } +} + +//----------------------------------------------------------------------------- +// restoreMeshData() +//----------------------------------------------------------------------------- +// virtual +void LLVOAvatarSelf::restoreMeshData() +{ + LLMemType mt(LLMemType::MTYPE_AVATAR); + + //llinfos << "Restoring" << llendl; + mMeshValid = TRUE; + updateJointLODs(); + updateAttachmentVisibility(gAgent.getCameraMode()); + + // force mesh update as LOD might not have changed to trigger this + gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE); +} + + + +//----------------------------------------------------------------------------- +// updateAttachmentVisibility() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::updateAttachmentVisibility(U32 camera_mode) +{ + for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::iterator curiter = iter++; + LLViewerJointAttachment* attachment = curiter->second; + if (attachment->getIsHUDAttachment()) + { + attachment->setAttachmentVisibility(TRUE); + } + else + { + switch (camera_mode) + { + case CAMERA_MODE_MOUSELOOK: + if (LLVOAvatar::sVisibleInFirstPerson && attachment->getVisibleInFirstPerson()) + { + attachment->setAttachmentVisibility(TRUE); + } + else + { + attachment->setAttachmentVisibility(FALSE); + } + break; + default: + attachment->setAttachmentVisibility(TRUE); + break; + } + } + } +} + +//----------------------------------------------------------------------------- +// updatedWearable( EWearableType type ) +// forces an update to any baked textures relevant to type. +// Should be called only on saving the wearable +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::wearableUpdated( EWearableType type ) +{ + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + baked_iter++) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + const LLVOAvatarDefines::EBakedTextureIndex index = baked_iter->first; + if (baked_dict) + { + for (LLVOAvatarDefines::wearables_vec_t::const_iterator type_iter = baked_dict->mWearables.begin(); + type_iter != baked_dict->mWearables.end(); + type_iter++) + { + const EWearableType comp_type = *type_iter; + if (comp_type == type) + { + if (mBakedTextureDatas[index].mTexLayerSet) + { + mBakedTextureDatas[index].mTexLayerSet->requestUpdate(); + mBakedTextureDatas[index].mTexLayerSet->requestUpload(); + } + break; + } + } + } + } +} + +//----------------------------------------------------------------------------- +// isWearingAttachment() +//----------------------------------------------------------------------------- +// Warning: include_linked_items = TRUE makes this operation expensive. +BOOL LLVOAvatarSelf::isWearingAttachment( const LLUUID& inv_item_id , BOOL include_linked_items ) const +{ + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::const_iterator curiter = iter++; + const LLViewerJointAttachment* attachment = curiter->second; + if( attachment->getItemID() == inv_item_id ) + { + return TRUE; + } + } + + if (include_linked_items) + { + LLInventoryModel::item_array_t item_array; + gInventory.collectLinkedItems(inv_item_id, item_array); + for (LLInventoryModel::item_array_t::const_iterator iter = item_array.begin(); + iter != item_array.end(); + iter++) + { + const LLViewerInventoryItem *linked_item = (*iter); + const LLUUID &item_id = linked_item->getUUID(); + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::const_iterator curiter = iter++; + const LLViewerJointAttachment* attachment = curiter->second; + if( attachment->getItemID() == item_id ) + { + return TRUE; + } + } + } + } + + return FALSE; +} + +//----------------------------------------------------------------------------- +// getWornAttachment() +//----------------------------------------------------------------------------- +LLViewerObject* LLVOAvatarSelf::getWornAttachment( const LLUUID& inv_item_id ) const +{ + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::const_iterator curiter = iter++; + const LLViewerJointAttachment* attachment = curiter->second; + if( attachment->getItemID() == inv_item_id ) + { + return attachment->getObject(); + } + } + return NULL; +} + +const std::string LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id) const +{ + for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ) + { + attachment_map_t::const_iterator curiter = iter++; + const LLViewerJointAttachment* attachment = curiter->second; + if( attachment->getItemID() == inv_item_id ) + { + return attachment->getName(); + } + } + + return LLStringUtil::null; +} + +//virtual +LLViewerJointAttachment *LLVOAvatarSelf::attachObject(LLViewerObject *viewer_object) +{ + LLViewerJointAttachment *attachment = LLVOAvatar::attachObject(viewer_object); + if (!attachment) + { + return 0; + } + + updateAttachmentVisibility(gAgent.getCameraMode()); + + // Then make sure the inventory is in sync with the avatar. + gInventory.addChangedMask(LLInventoryObserver::LABEL, attachment->getItemID()); + gInventory.notifyObservers(); + + return attachment; +} + +void LLVOAvatarSelf::getAllAttachmentsArray(LLDynamicArray& attachments) +{ + for (LLVOAvatar::attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); + iter != mAttachmentPoints.end(); ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + if ( attachment && (attachment->getNumObjects() > 0)) + { + attachments.push_back(iter->first); + } + } +} + +U32 LLVOAvatarSelf::getNumWearables(LLVOAvatarDefines::ETextureIndex i) const +{ + EWearableType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i); + return gAgentWearables.getWearableCount(type); +} + +// virtual +void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + //llinfos << "onLocalTextureLoaded: " << src_vi->getID() << llendl; + + const LLUUID& src_id = src_vi->getID(); + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + ETextureIndex index = data->mIndex; + if (!isIndexLocalTexture(index)) return; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(index, 0); + + // fix for EXT-268. Preventing using of NULL pointer + if(NULL == local_tex_obj) + { + LL_WARNS("TAG") << "There is no Local Texture Object with index: " << index + << ", final: " << final + << LL_ENDL; + return; + } + if (success) + { + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + (local_tex_obj->getID() == src_id) && + discard_level < local_tex_obj->getDiscard()) + { + local_tex_obj->setDiscard(discard_level); + if (!gAgent.cameraCustomizeAvatar()) + { + requestLayerSetUpdate(index); + } + else if (gAgent.cameraCustomizeAvatar()) + { + LLVisualParamHint::requestHintUpdates(); + } + updateMeshTextures(); + } + } + else if (final) + { + // Failed: asset is missing + if (!local_tex_obj->getBakedReady() && + local_tex_obj->getImage() != NULL && + local_tex_obj->getImage()->getID() == src_id) + { + local_tex_obj->setDiscard(0); + requestLayerSetUpdate(index); + updateMeshTextures(); + } + } +} + +// virtual +/* //unused +BOOL LLVOAvatarSelf::getLocalTextureRaw(ETextureIndex index, LLImageRaw* image_raw) const +{ + if (!isIndexLocalTexture(index)) return FALSE; + if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR) return TRUE; + + const LocalTextureData *local_tex_data = getLocalTextureData(index)[0]; + if (local_tex_data->mImage->readBackRaw(-1, image_raw, false)) + { + + return TRUE; + } + + // No data loaded yet + setLocalTexture((ETextureIndex)index, getTEImage(index), FALSE); // <-- non-const, move this elsewhere + return FALSE; +} +*/ + +// virtual +BOOL LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const +{ + *tex_pp = NULL; + + if (!isIndexLocalTexture(type)) return FALSE; + if (getLocalTextureID(type, index) == IMG_DEFAULT_AVATAR) return TRUE; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (!local_tex_obj) + { + return FALSE; + } + *tex_pp = local_tex_obj->getImage(); + return TRUE; +} + +const LLUUID& LLVOAvatarSelf::getLocalTextureID(ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) return IMG_DEFAULT_AVATAR; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (local_tex_obj && local_tex_obj->getImage() != NULL) + { + return local_tex_obj->getImage()->getID(); + } + return IMG_DEFAULT_AVATAR; +} + +//----------------------------------------------------------------------------- +// isLocalTextureDataAvailable() +// Returns true if at least the lowest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::isLocalTextureDataAvailable(const LLTexLayerSet* layerset) const +{ + /* if (layerset == mBakedTextureDatas[BAKED_HEAD].mTexLayerSet) + return getLocalDiscardLevel(TEX_HEAD_BODYPAINT) >= 0; */ + for (LLVOAvatarDictionary::BakedTextures::const_iterator baked_iter = LLVOAvatarDictionary::getInstance()->getBakedTextures().begin(); + baked_iter != LLVOAvatarDictionary::getInstance()->getBakedTextures().end(); + baked_iter++) + { + const EBakedTextureIndex baked_index = baked_iter->first; + if (layerset == mBakedTextureDatas[baked_index].mTexLayerSet) + { + BOOL ret = true; + const LLVOAvatarDictionary::BakedEntry *baked_dict = baked_iter->second; + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + local_tex_iter++) + { + const ETextureIndex tex_index = *local_tex_iter; + ret &= (getLocalDiscardLevel(tex_index) >= 0); + } + return ret; + } + } + llassert(0); + return FALSE; +} + +//----------------------------------------------------------------------------- +// virtual +// isLocalTextureDataFinal() +// Returns true if the highest quality discard level exists for every texture +// in the layerset. +//----------------------------------------------------------------------------- +BOOL LLVOAvatarSelf::isLocalTextureDataFinal(const LLTexLayerSet* layerset) const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet) + { + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture((EBakedTextureIndex)i); + for (texture_vec_t::const_iterator local_tex_iter = baked_dict->mLocalTextures.begin(); + local_tex_iter != baked_dict->mLocalTextures.end(); + local_tex_iter++) + { + if (getLocalDiscardLevel(*local_tex_iter) != 0) + { + return FALSE; + } + } + return TRUE; + } + } + llassert(0); + return FALSE; +} + +BOOL LLVOAvatarSelf::isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index) const +{ + LLUUID id; + if (isIndexLocalTexture(type)) + { + id = getLocalTextureID(type, index); + } + else + { + id = getTEImage(type)->getID(); + } + + return (id != IMG_DEFAULT_AVATAR && + id != IMG_DEFAULT); +} + +//----------------------------------------------------------------------------- +// virtual +// requestLayerSetUploads() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUploads() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); + if (!layer_baked && mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->requestUpload(); + } + } +} + +bool LLVOAvatarSelf::areTexturesCurrent() const +{ + return !hasPendingBakedUploads() && gAgentWearables.areWearablesLoaded(); +} + +// virtual +bool LLVOAvatarSelf::hasPendingBakedUploads() const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + BOOL upload_pending = (mBakedTextureDatas[i].mTexLayerSet && mBakedTextureDatas[i].mTexLayerSet->getComposite()->uploadPending()); + if (upload_pending) + { + return true; + } + } + return false; +} + +void LLVOAvatarSelf::invalidateComposite( LLTexLayerSet* layerset, BOOL set_by_user ) +{ + if( !layerset || !layerset->getUpdatesEnabled() ) + { + return; + } + // llinfos << "LLVOAvatar::invalidComposite() " << layerset->getBodyRegion() << llendl; + + invalidateMorphMasks(layerset->getBakedTexIndex()); + layerset->requestUpdate(); + + if( set_by_user ) + { + llassert(isSelf()); + + ETextureIndex baked_te = getBakedTE( layerset ); + setTEImage( baked_te, LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT_AVATAR) ); + layerset->requestUpload(); + } +} + +void LLVOAvatarSelf::invalidateAll() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + invalidateComposite(mBakedTextureDatas[i].mTexLayerSet, TRUE); + } + updateMeshTextures(); +} + +//----------------------------------------------------------------------------- +// setCompositeUpdatesEnabled() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setCompositeUpdatesEnabled( BOOL b ) +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (mBakedTextureDatas[i].mTexLayerSet ) + { + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled( b ); + } + } +} + +void LLVOAvatarSelf::setupComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + BOOL layer_baked = isTextureDefined(mBakedTextureDatas[i].mTextureIndex); + if (mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(!layer_baked); + } + } +} + +void LLVOAvatarSelf::updateComposites() +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (mBakedTextureDatas[i].mTexLayerSet + && ((i != BAKED_SKIRT) || isWearingWearableType(WT_SKIRT))) + { + mBakedTextureDatas[i].mTexLayerSet->updateComposite(); + } + } +} + +// virtual +S32 LLVOAvatarSelf::getLocalDiscardLevel(ETextureIndex type, U32 index) const +{ + if (!isIndexLocalTexture(type)) return FALSE; + + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type, index); + if (local_tex_obj) + { + if (type >= 0 + && getLocalTextureID(type,index) != IMG_DEFAULT_AVATAR + && !local_tex_obj->getImage()->isMissingAsset()) + { + return local_tex_obj->getImage()->getDiscardLevel(); + } + else + { + // We don't care about this (no image associated with the layer) treat as fully loaded. + return 0; + } + } + return 0; +} + +// virtual +// Counts the memory footprint of local textures. +void LLVOAvatarSelf::getLocalTextureByteCount(S32* gl_bytes) const +{ + *gl_bytes = 0; + for (S32 type = 0; type < TEX_NUM_INDICES; type++) + { + if (!isIndexLocalTexture((ETextureIndex)type)) continue; + U32 max_tex = getNumWearables((ETextureIndex) type); + for (U32 num = 0; num < max_tex; num++) + { + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject((ETextureIndex) type, num); + if (local_tex_obj) + { + const LLViewerFetchedTexture* image_gl = local_tex_obj->getImage(); + if (image_gl) + { + S32 bytes = (S32)image_gl->getWidth() * image_gl->getHeight() * image_gl->getComponents(); + + if (image_gl->hasValidGLTexture()) + { + *gl_bytes += bytes; + } + } + } + } + } +} + +// virtual +void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_tex, BOOL baked_version_ready, U32 index) +{ + if (!isIndexLocalTexture(type)) return; + + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(src_tex, TRUE) ; + if(!tex) + { + return ; + } + + S32 desired_discard = isSelf() ? 0 : 2; + LLLocalTextureObject *local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + if (type >= TEX_NUM_INDICES) + { + llerrs << "Tried to set local texture with invalid type: (" << (U32) type << ", " << index << ")" << llendl; + return; + } + EWearableType wearable_type = LLVOAvatarDictionary::getInstance()->getTEWearableType(type); + if (!gAgentWearables.getWearable(wearable_type,0)) + { + // no wearable is loaded, cannot set the texture. + return; + } + gAgentWearables.addLocalTextureObject(wearable_type,type,index); + local_tex_obj = getLocalTextureObject(type,index); + if (!local_tex_obj) + { + llerrs << "Unable to create LocalTextureObject for wearable type & index: (" << (U32) wearable_type << ", " << index << ")" << llendl; + return; + } + } + if (!baked_version_ready) + { + if (tex != local_tex_obj->getImage() || local_tex_obj->getBakedReady()) + { + local_tex_obj->setDiscard(MAX_DISCARD_LEVEL+1); + } + if (tex->getID() != IMG_DEFAULT_AVATAR) + { + if (local_tex_obj->getDiscard() > desired_discard) + { + S32 tex_discard = tex->getDiscardLevel(); + if (tex_discard >= 0 && tex_discard <= desired_discard) + { + local_tex_obj->setDiscard(tex_discard); + if (isSelf() && !gAgent.cameraCustomizeAvatar()) + { + requestLayerSetUpdate(type); + } + else if (isSelf() && gAgent.cameraCustomizeAvatar()) + { + LLVisualParamHint::requestHintUpdates(); + } + } + else + { + tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type)); + } + } + tex->setMinDiscardLevel(desired_discard); + } + } + local_tex_obj->setBakedReady( baked_version_ready ); + local_tex_obj->setImage(tex); +} + +// virtual +void LLVOAvatarSelf::dumpLocalTextures() const +{ + llinfos << "Local Textures:" << llendl; + + /* ETextureIndex baked_equiv[] = { + TEX_UPPER_BAKED, + if (isTextureDefined(baked_equiv[i])) */ + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + iter++) + { + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + continue; + + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + const ETextureIndex baked_equiv = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex; + + const std::string &name = texture_dict->mName; + const LLLocalTextureObject *local_tex_obj = getLocalTextureObject(iter->first, 0); + if (isTextureDefined(baked_equiv)) + { +#if LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, makes textures + // easier to steal. JC + llinfos << "LocTex " << name << ": Baked " << llendl; +#else + llinfos << "LocTex " << name << ": Baked " << getTEImage(baked_equiv)->getID() << llendl; +#endif + } + else if (local_tex_obj->getImage() != NULL) + { + if (local_tex_obj->getImage()->getID() == IMG_DEFAULT_AVATAR) + { + llinfos << "LocTex " << name << ": None" << llendl; + } + else + { + const LLViewerFetchedTexture* image = local_tex_obj->getImage(); + + llinfos << "LocTex " << name << ": " + << "Discard " << image->getDiscardLevel() << ", " + << "(" << image->getWidth() << ", " << image->getHeight() << ") " +#if !LL_RELEASE_FOR_DOWNLOAD + // End users don't get to trivially see avatar texture IDs, + // makes textures easier to steal + << image->getID() << " " +#endif + << "Priority: " << image->getDecodePriority() + << llendl; + } + } + else + { + llinfos << "LocTex " << name << ": No LLViewerTexture" << llendl; + } + } +} + +//----------------------------------------------------------------------------- +// static +// onLocalTextureLoaded() +//----------------------------------------------------------------------------- + +void LLVOAvatarSelf::onLocalTextureLoaded(BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src_raw, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata) +{ + LLAvatarTexData *data = (LLAvatarTexData *)userdata; + LLVOAvatarSelf *self = (LLVOAvatarSelf *)gObjectList.findObject(data->mAvatarID); + if (self) + { + // We should only be handling local textures for ourself + self->localTextureLoaded(success, src_vi, src_raw, aux_src, discard_level, final, userdata); + } + // ensure data is cleaned up + if (final || !success) + { + delete data; + } +} + +// static +void LLVOAvatarSelf::dumpTotalLocalTextureByteCount() +{ + S32 gl_bytes = 0; + gAgent.getAvatarObject()->getLocalTextureByteCount(&gl_bytes); + llinfos << "Total Avatar LocTex GL:" << (gl_bytes/1024) << "KB" << llendl; +} + +BOOL LLVOAvatarSelf::updateIsFullyLoaded() +{ + BOOL loading = FALSE; + + // do we have a shape? + if (visualParamWeightsAreDefault()) + { + loading = TRUE; + } + + if (!isTextureDefined(TEX_HAIR)) + { + loading = TRUE; + } + + if (!mPreviousFullyLoaded) + { + if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_LOWER].mTexLayerSet) && + (!isTextureDefined(TEX_LOWER_BAKED))) + { + loading = TRUE; + } + + if (!isLocalTextureDataAvailable(mBakedTextureDatas[BAKED_UPPER].mTexLayerSet) && + (!isTextureDefined(TEX_UPPER_BAKED))) + { + loading = TRUE; + } + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (i == BAKED_SKIRT && !isWearingWearableType(WT_SKIRT)) + continue; + + BakedTextureData& texture_data = mBakedTextureDatas[i]; + if (!isTextureDefined(texture_data.mTextureIndex)) + continue; + + // Check for the case that texture is defined but not sufficiently loaded to display anything. + LLViewerTexture* baked_img = getImage( texture_data.mTextureIndex ); + if (!baked_img || !baked_img->hasValidGLTexture()) + { + loading = TRUE; + } + + } + + } + return processFullyLoadedChange(loading); +} + +const LLUUID& LLVOAvatarSelf::grabLocalTexture(ETextureIndex type, U32 index) const +{ + if (canGrabLocalTexture(type, index)) + { + return getTEImage( type )->getID(); + } + return LLUUID::null; +} + +BOOL LLVOAvatarSelf::canGrabLocalTexture(ETextureIndex type, U32 index) const +{ + // Check if the texture hasn't been baked yet. + if (!isTextureDefined(type)) + { + lldebugs << "getTEImage( " << (U32) type << " )->getID() == IMG_DEFAULT_AVATAR" << llendl; + return FALSE; + } + + if (gAgent.isGodlike()) + return TRUE; + + // Check permissions of textures that show up in the + // baked texture. We don't want people copying people's + // work via baked textures. + /* switch(type) + case TEX_EYES_BAKED: + textures.push_back(TEX_EYES_IRIS); */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(type); + if (!texture_dict->mIsUsedByBakedTexture) return FALSE; + + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + const LLVOAvatarDictionary::BakedEntry *baked_dict = LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_index); + for (texture_vec_t::const_iterator iter = baked_dict->mLocalTextures.begin(); + iter != baked_dict->mLocalTextures.end(); + iter++) + { + const ETextureIndex t_index = (*iter); + lldebugs << "Checking index " << (U32) t_index << llendl; + const LLUUID& texture_id = getTEImage( t_index )->getID(); + if (texture_id != IMG_DEFAULT_AVATAR) + { + // Search inventory for this texture. + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + LLAssetIDMatches asset_id_matches(texture_id); + gInventory.collectDescendentsIf(LLUUID::null, + cats, + items, + LLInventoryModel::INCLUDE_TRASH, + asset_id_matches); + + BOOL can_grab = FALSE; + lldebugs << "item count for asset " << texture_id << ": " << items.count() << llendl; + if (items.count()) + { + // search for full permissions version + for (S32 i = 0; i < items.count(); i++) + { + LLInventoryItem* itemp = items[i]; + LLPermissions item_permissions = itemp->getPermissions(); + if ( item_permissions.allowOperationBy( + PERM_MODIFY, gAgent.getID(), gAgent.getGroupID()) && + item_permissions.allowOperationBy( + PERM_COPY, gAgent.getID(), gAgent.getGroupID()) && + item_permissions.allowOperationBy( + PERM_TRANSFER, gAgent.getID(), gAgent.getGroupID()) ) + { + can_grab = TRUE; + break; + } + } + } + if (!can_grab) return FALSE; + } + } + + return TRUE; +} + +void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTexture* imagep, + F32 texel_area_ratio, BOOL render_avatar, BOOL covered_by_baked, U32 index ) +{ + if (!isIndexLocalTexture(type)) return; + + if (!covered_by_baked) + { + if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR) + { + F32 desired_pixels; + desired_pixels = llmin(mPixelArea, (F32)getTexImageArea()); + imagep->setBoostLevel(getAvatarBoostLevel()); + imagep->addTextureStats( desired_pixels / texel_area_ratio ); + if (imagep->getDiscardLevel() < 0) + { + mHasGrey = TRUE; // for statistics gathering + } + } + else + { + // texture asset is missing + mHasGrey = TRUE; // for statistics gathering + } + } +} + +LLLocalTextureObject* LLVOAvatarSelf::getLocalTextureObject(LLVOAvatarDefines::ETextureIndex i, U32 wearable_index) const +{ + EWearableType type = LLVOAvatarDictionary::getInstance()->getTEWearableType(i); + LLWearable* wearable = gAgentWearables.getWearable(type, wearable_index); + if (wearable) + { + return wearable->getLocalTextureObject(i); + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// getBakedTE() +// Used by the LayerSet. (Layer sets don't in general know what textures depend on them.) +//----------------------------------------------------------------------------- +ETextureIndex LLVOAvatarSelf::getBakedTE( const LLTexLayerSet* layerset ) const +{ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if (layerset == mBakedTextureDatas[i].mTexLayerSet ) + { + return mBakedTextureDatas[i].mTextureIndex; + } + } + llassert(0); + return TEX_HEAD_BAKED; +} + + +//----------------------------------------------------------------------------- +// setNewBakedTexture() +// A new baked texture has been successfully uploaded and we can start using it now. +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::setNewBakedTexture( ETextureIndex te, const LLUUID& uuid ) +{ + // Baked textures live on other sims. + LLHost target_host = getObjectHost(); + setTEImage( te, LLViewerTextureManager::getFetchedTextureFromHost( uuid, target_host ) ); + updateMeshTextures(); + dirtyMesh(); + + LLVOAvatar::cullAvatarsByPixelArea(); + + /* switch(te) + case TEX_HEAD_BAKED: + llinfos << "New baked texture: HEAD" << llendl; */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(te); + if (texture_dict->mIsBakedTexture) + { + llinfos << "New baked texture: " << texture_dict->mName << " UUID: " << uuid <cancelUpload(); */ + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + if ( mBakedTextureDatas[i].mTextureIndex == te && mBakedTextureDatas[i].mTexLayerSet) + { + mBakedTextureDatas[i].mTexLayerSet->cancelUpload(); + } + } +} + +// static +void LLVOAvatarSelf::processRebakeAvatarTextures(LLMessageSystem* msg, void**) +{ + LLUUID texture_id; + msg->getUUID("TextureData", "TextureID", texture_id); + + LLVOAvatarSelf* self = gAgent.getAvatarObject(); + if (!self) return; + + // If this is a texture corresponding to one of our baked entries, + // just rebake that layer set. + BOOL found = FALSE; + + /* ETextureIndex baked_texture_indices[BAKED_NUM_INDICES] = + TEX_HEAD_BAKED, + TEX_UPPER_BAKED, */ + for (LLVOAvatarDictionary::Textures::const_iterator iter = LLVOAvatarDictionary::getInstance()->getTextures().begin(); + iter != LLVOAvatarDictionary::getInstance()->getTextures().end(); + iter++) + { + const ETextureIndex index = iter->first; + const LLVOAvatarDictionary::TextureEntry *texture_dict = iter->second; + if (texture_dict->mIsBakedTexture) + { + if (texture_id == self->getTEImage(index)->getID()) + { + LLTexLayerSet* layer_set = self->getLayerSet(index); + if (layer_set) + { + llinfos << "TAT: rebake - matched entry " << (S32)index << llendl; + // Apparently set_by_user == force upload + BOOL set_by_user = TRUE; + self->invalidateComposite(layer_set, set_by_user); + found = TRUE; + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); + } + } + } + } + + // If texture not found, rebake all entries. + if (!found) + { + self->forceBakeAllTextures(); + } + else + { + // Not sure if this is necessary, but forceBakeAllTextures() does it. + self->updateMeshTextures(); + } +} + +void LLVOAvatarSelf::forceBakeAllTextures(bool slam_for_debug) +{ + llinfos << "TAT: forced full rebake. " << llendl; + + for (U32 i = 0; i < mBakedTextureDatas.size(); i++) + { + ETextureIndex baked_index = mBakedTextureDatas[i].mTextureIndex; + LLTexLayerSet* layer_set = getLayerSet(baked_index); + if (layer_set) + { + if (slam_for_debug) + { + layer_set->setUpdatesEnabled(TRUE); + layer_set->cancelUpload(); + } + + BOOL set_by_user = TRUE; + invalidateComposite(layer_set, set_by_user); + LLViewerStats::getInstance()->incStat(LLViewerStats::ST_TEX_REBAKES); + } + else + { + llwarns << "TAT: NO LAYER SET FOR " << (S32)baked_index << llendl; + } + } + + // Don't know if this is needed + updateMeshTextures(); +} + +//----------------------------------------------------------------------------- +// requestLayerSetUpdate() +//----------------------------------------------------------------------------- +void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index ) +{ + /* switch(index) + case LOCTEX_UPPER_BODYPAINT: + case LOCTEX_UPPER_SHIRT: + if( mUpperBodyLayerSet ) + mUpperBodyLayerSet->requestUpdate(); */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); + if (!texture_dict->mIsLocalTexture || !texture_dict->mIsUsedByBakedTexture) + return; + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + if (mBakedTextureDatas[baked_index].mTexLayerSet) + { + mBakedTextureDatas[baked_index].mTexLayerSet->requestUpdate(); + } +} + +LLTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const +{ + /* switch(index) + case TEX_HEAD_BAKED: + case TEX_HEAD_BODYPAINT: + return mHeadLayerSet; */ + const LLVOAvatarDictionary::TextureEntry *texture_dict = LLVOAvatarDictionary::getInstance()->getTexture(index); + if (texture_dict->mIsUsedByBakedTexture) + { + const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex; + return mBakedTextureDatas[baked_index].mTexLayerSet; + } + return NULL; +} + +// static +void LLVOAvatarSelf::onCustomizeStart() +{ + // We're no longer doing any baking or invalidating on entering + // appearance editing mode. Leaving function in place in case + // further changes require us to do something at this point - Nyx +} + +// static +void LLVOAvatarSelf::onCustomizeEnd() +{ + LLVOAvatarSelf *avatarp = gAgent.getAvatarObject(); + if (avatarp) + { + avatarp->invalidateAll(); + avatarp->requestLayerSetUploads(); + } +} + +// static +void LLVOAvatarSelf::onChangeSelfInvisible(BOOL newvalue) +{ + LLVOAvatarSelf *avatarp = gAgent.getAvatarObject(); + if (avatarp) + { + if (newvalue) + { + // we have just requested to set the avatar's baked textures to invisible + avatarp->setInvisible(TRUE); + } + else + { + avatarp->setInvisible(FALSE); + } + } +} + +void LLVOAvatarSelf::setInvisible(BOOL newvalue) +{ + if (newvalue) + { + setCompositeUpdatesEnabled(FALSE); + for (U32 i = 0; i < mBakedTextureDatas.size(); i++ ) + { + setNewBakedTexture(mBakedTextureDatas[i].mTextureIndex, IMG_INVISIBLE); + } + gAgent.sendAgentSetAppearance(); + } + else + { + setCompositeUpdatesEnabled(TRUE); + invalidateAll(); + requestLayerSetUploads(); + gAgent.sendAgentSetAppearance(); + } +} + +//------------------------------------------------------------------------ +// needsRenderBeam() +//------------------------------------------------------------------------ +BOOL LLVOAvatarSelf::needsRenderBeam() +{ + if (gNoRender) + { + return FALSE; + } + LLTool *tool = LLToolMgr::getInstance()->getCurrentTool(); + + BOOL is_touching_or_grabbing = (tool == LLToolGrab::getInstance() && LLToolGrab::getInstance()->isEditing()); + if (LLToolGrab::getInstance()->getEditingObject() && + LLToolGrab::getInstance()->getEditingObject()->isAttachment()) + { + // don't render selection beam on hud objects + is_touching_or_grabbing = FALSE; + } + return is_touching_or_grabbing || (mState & AGENT_STATE_EDITING && LLSelectMgr::getInstance()->shouldShowSelection()); +} + +// static +void LLVOAvatarSelf::deleteScratchTextures() +{ + for( LLGLuint* namep = sScratchTexNames.getFirstData(); + namep; + namep = sScratchTexNames.getNextData() ) + { + LLImageGL::deleteTextures(1, (U32 *)namep ); + stop_glerror(); + } + + if( sScratchTexBytes ) + { + lldebugs << "Clearing Scratch Textures " << (sScratchTexBytes/1024) << "KB" << llendl; + + sScratchTexNames.deleteAllData(); + sScratchTexLastBindTime.deleteAllData(); + LLImageGL::sGlobalTextureMemoryInBytes -= sScratchTexBytes; + sScratchTexBytes = 0; + } +} + +BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format ) +{ + U32 texture_bytes = 0; + GLuint gl_name = getScratchTexName( format, &texture_bytes ); + if( gl_name ) + { + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name); + stop_glerror(); + + F32* last_bind_time = sScratchTexLastBindTime.getIfThere( format ); + if( last_bind_time ) + { + if( *last_bind_time != LLImageGL::sLastFrameTime ) + { + *last_bind_time = LLImageGL::sLastFrameTime; + LLImageGL::updateBoundTexMem(texture_bytes); + } + } + else + { + LLImageGL::updateBoundTexMem(texture_bytes); + sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) ); + } + return TRUE; + } + return FALSE; +} + +LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, U32* texture_bytes ) +{ + S32 components; + GLenum internal_format; + switch( format ) + { + case GL_LUMINANCE: components = 1; internal_format = GL_LUMINANCE8; break; + case GL_ALPHA: components = 1; internal_format = GL_ALPHA8; break; + case GL_COLOR_INDEX: components = 1; internal_format = GL_COLOR_INDEX8_EXT; break; + case GL_LUMINANCE_ALPHA: components = 2; internal_format = GL_LUMINANCE8_ALPHA8; break; + case GL_RGB: components = 3; internal_format = GL_RGB8; break; + case GL_RGBA: components = 4; internal_format = GL_RGBA8; break; + default: llassert(0); components = 4; internal_format = GL_RGBA8; break; + } + + *texture_bytes = components * SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT; + + if( sScratchTexNames.checkData( format ) ) + { + return *( sScratchTexNames.getData( format ) ); + } + + LLGLSUIDefault gls_ui; + + U32 name = 0; + LLImageGL::generateTextures(1, &name ); + stop_glerror(); + + gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, name); + stop_glerror(); + + LLImageGL::setManualImage( + GL_TEXTURE_2D, 0, internal_format, + SCRATCH_TEX_WIDTH, SCRATCH_TEX_HEIGHT, + format, GL_UNSIGNED_BYTE, NULL ); + stop_glerror(); + + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR); + gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP); + stop_glerror(); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + stop_glerror(); + + sScratchTexNames.addData( format, new LLGLuint( name ) ); + + sScratchTexBytes += *texture_bytes; + LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes; + return name; +} + +// static +void LLVOAvatarSelf::dumpScratchTextureByteCount() +{ + llinfos << "Scratch Texture GL: " << (sScratchTexBytes/1024) << "KB" << llendl; +} diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h new file mode 100644 index 0000000000..17744cce1b --- /dev/null +++ b/indra/newview/llvoavatarself.h @@ -0,0 +1,314 @@ +/** + * @file llvoavatarself.h + * @brief Declaration of LLVOAvatar class which is a derivation fo + * LLViewerObject + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + * + * Copyright (c) 2001-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLVOAVATARSELF_H +#define LL_LLVOAVATARSELF_H + +#include "llviewertexture.h" +#include "llvoavatar.h" + +struct LocalTextureData; + +//------------------------------------------------------------------------ +// LLVOAvatarSelf +//------------------------------------------------------------------------ +class LLVOAvatarSelf : + public LLVOAvatar +{ + +/******************************************************************************** + ** ** + ** INITIALIZATION + **/ + +public: + LLVOAvatarSelf(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp); + virtual ~LLVOAvatarSelf(); + virtual void markDead(); + virtual void initInstance(); // Called after construction to initialize the class. +protected: + BOOL loadAvatarSelf(); + BOOL buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info); + BOOL buildMenus(); + /*virtual*/ BOOL loadLayersets(); + +/** Initialization + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** INHERITED + **/ + + //-------------------------------------------------------------------- + // LLViewerObject interface and related + //-------------------------------------------------------------------- +public: + /*virtual*/ void updateRegion(LLViewerRegion *regionp); + + //-------------------------------------------------------------------- + // LLCharacter interface and related + //-------------------------------------------------------------------- +public: + /*virtual*/ void stopMotionFromSource(const LLUUID& source_id); + /*virtual*/ void requestStopMotion(LLMotion* motion); + /*virtual*/ LLJoint* getJoint(const std::string &name); + +/** Initialization + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** STATE + **/ + +public: + /*virtual*/ bool isSelf() const { return true; } + + //-------------------------------------------------------------------- + // Updates + //-------------------------------------------------------------------- +public: + /*virtual*/ BOOL updateCharacter(LLAgent &agent); + /*virtual*/ void idleUpdateTractorBeam(); + + //-------------------------------------------------------------------- + // Loading state + //-------------------------------------------------------------------- +public: + /*virtual*/ BOOL updateIsFullyLoaded(); +private: + BOOL mIsBaked; // are the stored baked textures up to date? + + //-------------------------------------------------------------------- + // Region state + //-------------------------------------------------------------------- +private: + U64 mLastRegionHandle; + LLFrameTimer mRegionCrossingTimer; + S32 mRegionCrossingCount; + +/** State + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** RENDERING + **/ + + //-------------------------------------------------------------------- + // Render beam + //-------------------------------------------------------------------- +protected: + BOOL needsRenderBeam(); +private: + LLPointer mBeam; + LLFrameTimer mBeamTimer; + + //-------------------------------------------------------------------- + // LLVOAvatar Constants + //-------------------------------------------------------------------- +public: + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_SELF; } + /*virtual*/ LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLViewerTexture::BOOST_AVATAR_BAKED_SELF; } + /*virtual*/ S32 getTexImageSize() const { return LLVOAvatar::getTexImageSize()*4; } + +/** Rendering + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** TEXTURES + **/ + + //-------------------------------------------------------------------- + // Loading status + //-------------------------------------------------------------------- +public: + /*virtual*/ bool hasPendingBakedUploads() const; + S32 getLocalDiscardLevel(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + bool areTexturesCurrent() const; + BOOL isLocalTextureDataAvailable(const LLTexLayerSet* layerset) const; + BOOL isLocalTextureDataFinal(const LLTexLayerSet* layerset) const; + /*virtual*/ BOOL isTextureDefined(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + + //-------------------------------------------------------------------- + // Local Textures + //-------------------------------------------------------------------- +public: + BOOL getLocalTextureGL(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture** image_gl_pp, U32 index = 0) const; + const LLUUID& getLocalTextureID(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + void setLocalTextureTE(U8 te, LLViewerTexture* image, BOOL set_by_user, U32 index = 0); + const LLUUID& grabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; + BOOL canGrabLocalTexture(LLVOAvatarDefines::ETextureIndex type, U32 index = 0) const; +protected: + /*virtual*/ void setLocalTexture(LLVOAvatarDefines::ETextureIndex type, LLViewerTexture* tex, BOOL baked_version_exits, U32 index = 0); + void localTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + void getLocalTextureByteCount(S32* gl_byte_count) const; + /*virtual*/ void addLocalTextureStats(LLVOAvatarDefines::ETextureIndex i, LLViewerFetchedTexture* imagep, F32 texel_area_ratio, BOOL rendered, BOOL covered_by_baked, U32 index = 0); + LLLocalTextureObject* getLocalTextureObject(LLVOAvatarDefines::ETextureIndex i, U32 index = 0) const; + +private: + static void onLocalTextureLoaded(BOOL succcess, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* aux_src, S32 discard_level, BOOL final, void* userdata); + + //-------------------------------------------------------------------- + // Baked textures + //-------------------------------------------------------------------- +public: + LLVOAvatarDefines::ETextureIndex getBakedTE(const LLTexLayerSet* layerset ) const; + void setNewBakedTexture(LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid); + void setCachedBakedTexture(LLVOAvatarDefines::ETextureIndex i, const LLUUID& uuid); + void forceBakeAllTextures(bool slam_for_debug = false); + static void processRebakeAvatarTextures(LLMessageSystem* msg, void**); +protected: + /*virtual*/ void removeMissingBakedTextures(); + + //-------------------------------------------------------------------- + // Layers + //-------------------------------------------------------------------- +public: + void requestLayerSetUploads(); + void requestLayerSetUpdate(LLVOAvatarDefines::ETextureIndex i); +protected: + LLTexLayerSet* getLayerSet(LLVOAvatarDefines::ETextureIndex index) const; + + //-------------------------------------------------------------------- + // Composites + //-------------------------------------------------------------------- +public: + /* virtual */ void invalidateComposite(LLTexLayerSet* layerset, BOOL set_by_user); + /* virtual */ void invalidateAll(); + /* virtual */ void setCompositeUpdatesEnabled(BOOL b); // only works for self + void setupComposites(); + void updateComposites(); + + //-------------------------------------------------------------------- + // Scratch textures (used for compositing) + //-------------------------------------------------------------------- +public: + BOOL bindScratchTexture(LLGLenum format); + static void deleteScratchTextures(); +protected: + LLGLuint getScratchTexName(LLGLenum format, U32* texture_bytes); +private: + static S32 sScratchTexBytes; + static LLMap< LLGLenum, LLGLuint*> sScratchTexNames; + static LLMap< LLGLenum, F32*> sScratchTexLastBindTime; + +/** Textures + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** MESHES + **/ +protected: + /*virtual*/ void restoreMeshData(); + +/** Meshes + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** WEARABLES + **/ + +public: + void wearableUpdated(EWearableType type); + + //-------------------------------------------------------------------- + // Attachments + //-------------------------------------------------------------------- +public: + void updateAttachmentVisibility(U32 camera_mode); + BOOL isWearingAttachment(const LLUUID& inv_item_id, BOOL include_linked_items = FALSE) const; + LLViewerObject* getWornAttachment(const LLUUID& inv_item_id ) const; + const std::string getAttachedPointName(const LLUUID& inv_item_id) const; + /*virtual*/ LLViewerJointAttachment *attachObject(LLViewerObject *viewer_object); + void getAllAttachmentsArray(LLDynamicArray& attachments); + + //-------------------------------------------------------------------- + // HUDs + //-------------------------------------------------------------------- +private: + U32 getNumWearables(LLVOAvatarDefines::ETextureIndex i) const; + + LLViewerJoint* mScreenp; // special purpose joint for HUD attachments + +/** Attachments + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** APPEARANCE + **/ + +public: + static void onCustomizeStart(); + static void onCustomizeEnd(); + + //-------------------------------------------------------------------- + // Visibility + //-------------------------------------------------------------------- +public: + static void onChangeSelfInvisible(BOOL newvalue); + void setInvisible(BOOL newvalue); + +/** Appearance + ** ** + *******************************************************************************/ + +/******************************************************************************** + ** ** + ** DIAGNOSTICS + **/ + +public: + static void dumpTotalLocalTextureByteCount(); + void dumpLocalTextures() const; + static void dumpScratchTextureByteCount(); + +/** Diagnostics + ** ** + *******************************************************************************/ + +}; + +#endif // LL_VO_AVATARSELF_H diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp index 9095ee43c8..130e1fd749 100644 --- a/indra/newview/llvoclouds.cpp +++ b/indra/newview/llvoclouds.cpp @@ -44,7 +44,7 @@ #include "llprimitive.h" #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llvosky.h" @@ -61,8 +61,8 @@ LLVOClouds::LLVOClouds(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re mCloudGroupp = NULL; mbCanSelect = FALSE; setNumTEs(1); - LLViewerImage* image = gImageList.getImage(gCloudTextureID); - image->setBoostLevel(LLViewerImage::BOOST_CLOUDS); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(gCloudTextureID); + image->setBoostLevel(LLViewerTexture::BOOST_CLOUDS); setTEImage(0, image); } @@ -115,9 +115,11 @@ LLDrawable* LLVOClouds::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_CLOUDS("Update Clouds"); + BOOL LLVOClouds::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_CLOUDS); + LLFastTimer ftm(FTM_UPDATE_CLOUDS); if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_CLOUDS))) { return TRUE; diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h index f70ea5b9e7..95e6b96e4e 100644 --- a/indra/newview/llvoclouds.h +++ b/indra/newview/llvoclouds.h @@ -37,7 +37,7 @@ #include "lltable.h" #include "v4coloru.h" -class LLViewerImage; +class LLViewerTexture; class LLViewerCloudGroup; class LLCloudGroup; diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp index fe4a2fdc76..a2793accea 100644 --- a/indra/newview/llvograss.cpp +++ b/indra/newview/llvograss.cpp @@ -46,7 +46,7 @@ #include "llsurfacepatch.h" #include "llvosky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "pipeline.h" #include "llspatialpartition.h" @@ -106,7 +106,7 @@ void LLVOGrass::updateSpecies() SpeciesMap::const_iterator it = sSpeciesTable.begin(); mSpecies = (*it).first; } - setTEImage(0, gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID)); + setTEImage(0, LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE)); } @@ -165,16 +165,6 @@ void LLVOGrass::initClass() grass_def->getFastAttributeUUID(texture_id_string, id); newGrass->mTextureID = id; - if (newGrass->mTextureID.isNull()) - { - std::string textureName; - - static LLStdStringHandle texture_name_string = LLXmlTree::addAttributeString("texture_name"); - success &= grass_def->getFastAttributeString(texture_name_string, textureName); - LLViewerImage* grass_image = gImageList.getImageFromFile(textureName); - newGrass->mTextureID = grass_image->getID(); - } - static LLStdStringHandle blade_sizex_string = LLXmlTree::addAttributeString("blade_size_x"); success &= grass_def->getFastAttributeF32(blade_sizex_string, F32_val); newGrass->mBladeSizeX = F32_val; @@ -392,9 +382,11 @@ LLDrawable* LLVOGrass::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_GRASS("Update Grass"); + BOOL LLVOGrass::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_GRASS); + LLFastTimer ftm(FTM_UPDATE_GRASS); dirtySpatialGroup(); plantBlades(); return TRUE; diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h index 11b79d519c..124400d356 100644 --- a/indra/newview/llvograss.h +++ b/indra/newview/llvograss.h @@ -38,7 +38,7 @@ #include class LLSurfacePatch; -class LLViewerImage; +class LLViewerTexture; class LLVOGrass : public LLAlphaObject diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp index fe19e18151..ac2484ddfd 100644 --- a/indra/newview/llvoground.cpp +++ b/indra/newview/llvoground.cpp @@ -37,7 +37,6 @@ #include "llviewercontrol.h" -#include "llagent.h" #include "lldrawable.h" #include "llface.h" #include "llsky.h" diff --git a/indra/newview/llvoground.h b/indra/newview/llvoground.h index f485bd0aa4..af3fcd65d4 100644 --- a/indra/newview/llvoground.h +++ b/indra/newview/llvoground.h @@ -36,7 +36,7 @@ #include "stdtypes.h" #include "v3color.h" #include "v4coloru.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llviewerobject.h" class LLVOGround : public LLStaticViewerObject diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 232885b3f6..182850f326 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -62,10 +62,14 @@ #include "llfirstuse.h" #include "llviewerwindow.h" #include "llviewercamera.h" +#include "llvoavatarself.h" #include "llfloaterfriends.h" //VIVOX, inorder to refresh communicate panel #include "llfloaterchat.h" // for LLFloaterChat::addChat() +// for Talk Button's state updating +#include "llnearbychatbar.h" + // for base64 decoding #include "apr_base64.h" @@ -1103,58 +1107,61 @@ static void killGateway() /////////////////////////////////////////////////////////////////////////////////////////////// -LLVoiceClient::LLVoiceClient() +LLVoiceClient::LLVoiceClient() : + mState(stateDisabled), + mSessionTerminateRequested(false), + mRelogRequested(false), + mConnected(false), + mPump(NULL), + + mTuningMode(false), + mTuningEnergy(0.0f), + mTuningMicVolume(0), + mTuningMicVolumeDirty(true), + mTuningSpeakerVolume(0), + mTuningSpeakerVolumeDirty(true), + mTuningExitState(stateDisabled), + + mAreaVoiceDisabled(false), + mAudioSession(NULL), + mAudioSessionChanged(false), + mNextAudioSession(NULL), + + mCurrentParcelLocalID(0), + mNumberOfAliases(0), + mCommandCookie(0), + mLoginRetryCount(0), + + mBuddyListMapPopulated(false), + mBlockRulesListReceived(false), + mAutoAcceptRulesListReceived(false), + mCaptureDeviceDirty(false), + mRenderDeviceDirty(false), + mSpatialCoordsDirty(false), + + mPTTDirty(true), + mPTT(true), + mUsePTT(true), + mPTTIsMiddleMouse(false), + mPTTKey(0), + mPTTIsToggle(false), + mUserPTTState(false), + mMuteMic(false), + mFriendsListDirty(true), + + mEarLocation(0), + mSpeakerVolumeDirty(true), + mSpeakerMuteDirty(true), + mSpeakerVolume(0), + mMicVolume(0), + mMicVolumeDirty(true), + + mVoiceEnabled(false), + mWriteInProgress(false), + + mLipSyncEnabled(false) { gVoiceClient = this; - mWriteInProgress = false; - mAreaVoiceDisabled = false; - mPTT = true; - mUserPTTState = false; - mMuteMic = false; - mSessionTerminateRequested = false; - mRelogRequested = false; - mCommandCookie = 0; - mCurrentParcelLocalID = 0; - mLoginRetryCount = 0; - - mSpeakerVolume = 0; - mMicVolume = 0; - - mAudioSession = NULL; - mAudioSessionChanged = false; - - // Initial dirty state - mSpatialCoordsDirty = false; - mPTTDirty = true; - mFriendsListDirty = true; - mSpeakerVolumeDirty = true; - mMicVolumeDirty = true; - mBuddyListMapPopulated = false; - mBlockRulesListReceived = false; - mAutoAcceptRulesListReceived = false; - mCaptureDeviceDirty = false; - mRenderDeviceDirty = false; - - // Use default values for everything then call updateSettings() after preferences are loaded - mVoiceEnabled = false; - mUsePTT = true; - mPTTIsToggle = false; - mEarLocation = 0; - mLipSyncEnabled = false; - - mTuningMode = false; - mTuningEnergy = 0.0f; - mTuningMicVolume = 0; - mTuningMicVolumeDirty = true; - mTuningSpeakerVolume = 0; - mTuningSpeakerVolumeDirty = true; - - // gMuteListp isn't set up at this point, so we defer this until later. -// gMuteListp->addObserver(&mutelist_listener); - - // stash the pump for later use - // This now happens when init() is called instead. - mPump = NULL; #if LL_DARWIN || LL_LINUX || LL_SOLARIS // HACK: THIS DOES NOT BELONG HERE @@ -1503,6 +1510,7 @@ std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserv CASE(STATUS_JOINED); CASE(STATUS_LEFT_CHANNEL); CASE(STATUS_VOICE_DISABLED); + CASE(STATUS_VOICE_ENABLED); CASE(BEGIN_ERROR_STATUS); CASE(ERROR_CHANNEL_FULL); CASE(ERROR_CHANNEL_LOCKED); @@ -4547,7 +4555,7 @@ void LLVoiceClient::messageEvent( if(messageHeader.find("text/html") != std::string::npos) { - std::string rawMessage; + std::string message; { const std::string startMarker = "', start + 1)) != std::string::npos) + if((end = message.find('>', start + 1)) != std::string::npos) { // Strip out the tag - rawMessage.erase(start, (end + 1) - start); + message.erase(start, (end + 1) - start); } else { @@ -4622,31 +4630,31 @@ void LLVoiceClient::messageEvent( // The text may contain text encoded with <, >, and & mark = 0; - while((mark = rawMessage.find("<", mark)) != std::string::npos) + while((mark = message.find("<", mark)) != std::string::npos) { - rawMessage.replace(mark, 4, "<"); + message.replace(mark, 4, "<"); mark += 1; } mark = 0; - while((mark = rawMessage.find(">", mark)) != std::string::npos) + while((mark = message.find(">", mark)) != std::string::npos) { - rawMessage.replace(mark, 4, ">"); + message.replace(mark, 4, ">"); mark += 1; } mark = 0; - while((mark = rawMessage.find("&", mark)) != std::string::npos) + while((mark = message.find("&", mark)) != std::string::npos) { - rawMessage.replace(mark, 5, "&"); + message.replace(mark, 5, "&"); mark += 1; } } // strip leading/trailing whitespace (since we always seem to get a couple newlines) - LLStringUtil::trim(rawMessage); + LLStringUtil::trim(message); -// LL_DEBUGS("Voice") << " stripped message = \n" << rawMessage << LL_ENDL; +// LL_DEBUGS("Voice") << " stripped message = \n" << message << LL_ENDL; sessionState *session = findSession(sessionHandle); if(session) @@ -4670,14 +4678,12 @@ void LLVoiceClient::messageEvent( quiet_chat = true; // TODO: Question: Return busy mode response here? Or maybe when session is started instead? } - - std::string fullMessage = std::string(": ") + rawMessage; - + LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL; gIMMgr->addMessage(session->mIMSessionID, session->mCallerID, session->mName.c_str(), - fullMessage.c_str(), + message.c_str(), LLStringUtil::null, // default arg IM_NOTHING_SPECIAL, // default arg 0, // default arg @@ -4685,7 +4691,7 @@ void LLVoiceClient::messageEvent( LLVector3::zero, // default arg true); // prepend name and make it a link to the user's profile - chat.mText = std::string("IM: ") + session->mName + std::string(": ") + rawMessage; + chat.mText = std::string("IM: ") + session->mName + std::string(": ") + message; // If the chat should come in quietly (i.e. we're in busy mode), pretend it's from a local agent. LLFloaterChat::addChat( chat, TRUE, quiet_chat ); } @@ -5773,9 +5779,15 @@ void LLVoiceClient::setMuteMic(bool muted) mMuteMic = muted; } +bool LLVoiceClient::getMuteMic() const +{ + return mMuteMic; +} + void LLVoiceClient::setUserPTTState(bool ptt) { mUserPTTState = ptt; + if (LLNearbyChatBar::instanceExists()) LLNearbyChatBar::getInstance()->setPTTState(ptt); } bool LLVoiceClient::getUserPTTState() @@ -5786,6 +5798,7 @@ bool LLVoiceClient::getUserPTTState() void LLVoiceClient::toggleUserPTTState(void) { mUserPTTState = !mUserPTTState; + if (LLNearbyChatBar::instanceExists()) LLNearbyChatBar::getInstance()->setPTTState(mUserPTTState); } void LLVoiceClient::setVoiceEnabled(bool enabled) @@ -5793,15 +5806,21 @@ void LLVoiceClient::setVoiceEnabled(bool enabled) if (enabled != mVoiceEnabled) { mVoiceEnabled = enabled; + LLVoiceClientStatusObserver::EStatusType status; + if (enabled) { LLVoiceChannel::getCurrentVoiceChannel()->activate(); + status = LLVoiceClientStatusObserver::STATUS_VOICE_ENABLED; } else { // Turning voice off looses your current channel -- this makes sure the UI isn't out of sync when you re-enable it. LLVoiceChannel::getCurrentVoiceChannel()->deactivate(); + status = LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED; } + + notifyStatusObservers(status); } } @@ -6901,12 +6920,12 @@ void LLVoiceClient::notifyFriendObservers() void LLVoiceClient::lookupName(const LLUUID &id) { - BOOL is_group = FALSE; + gCacheName->get(id, FALSE, &LLVoiceClient::onAvatarNameLookup); gCacheName->getNameFromUUID(id, is_group, onAvatarNameLookup); } //static -void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data) +void LLVoiceClient::onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group) { if(gVoiceClient) { diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h index cfc336b27d..fe99e787da 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -43,6 +43,7 @@ class LLVivoxProtocolParser; #include "llframetimer.h" #include "llviewerregion.h" #include "llcallingcard.h" // for LLFriendObserver +#include "m3math.h" // LLMatrix3 class LLVoiceClientParticipantObserver { @@ -64,6 +65,11 @@ public: STATUS_JOINED, STATUS_LEFT_CHANNEL, STATUS_VOICE_DISABLED, + + // Adding STATUS_VOICE_ENABLED as pair status for STATUS_VOICE_DISABLED + // See LLVoiceClient::setVoiceEnabled() + STATUS_VOICE_ENABLED, + BEGIN_ERROR_STATUS, ERROR_CHANNEL_FULL, ERROR_CHANNEL_LOCKED, @@ -178,6 +184,7 @@ static void updatePosition(void); void setMuteMic(bool muted); // Use this to mute the local mic (for when the client is minimized, etc), ignoring user PTT state. + bool getMuteMic() const; void setUserPTTState(bool ptt); bool getUserPTTState(); void toggleUserPTTState(void); @@ -461,7 +468,7 @@ static void updatePosition(void); void removeObserver(LLFriendObserver* observer); void lookupName(const LLUUID &id); - static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group, void* user_data); + static void onAvatarNameLookup(const LLUUID& id, const std::string& first, const std::string& last, BOOL is_group); void avatarNameResolved(const LLUUID &id, const std::string &name); typedef std::vector deviceList; @@ -727,7 +734,6 @@ static std::string nameFromsipURI(const std::string &uri); bool mVoiceEnabled; bool mWriteInProgress; std::string mWriteString; - size_t mWriteOffset; LLTimer mUpdateTimer; diff --git a/indra/newview/llvoicevisualizer.cpp b/indra/newview/llvoicevisualizer.cpp index 5606398aaf..9bafc03a6d 100644 --- a/indra/newview/llvoicevisualizer.cpp +++ b/indra/newview/llvoicevisualizer.cpp @@ -42,9 +42,8 @@ #include "llvoicevisualizer.h" #include "llviewercamera.h" #include "llviewerobject.h" -#include "llimagegl.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llvoiceclient.h" #include "llrender.h" @@ -131,19 +130,19 @@ LLVoiceVisualizer::LLVoiceVisualizer( const U8 type ) const char* sound_level_img[] = { - "041ee5a0-cb6a-9ac5-6e49-41e9320507d5.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c", - "29de489d-0491-fb00-7dab-f9e686d31e83.j2c" + "voice_meter_dot.j2c", + "voice_meter_rings.j2c", + "voice_meter_rings.j2c", + "voice_meter_rings.j2c", + "voice_meter_rings.j2c", + "voice_meter_rings.j2c", + "voice_meter_rings.j2c" }; for (int i=0; igetSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncOohAahRate")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncOoh")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncAah")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncOohPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); - gSavedSettings.getControl("LipSyncAahPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _1)); + gSavedSettings.getControl("LipSyncEnabled")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncOohAahRate")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncOoh")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncAah")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncOohPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); + gSavedSettings.getControl("LipSyncAahPowerTransfer")->getSignal()->connect(boost::bind(&handleVoiceVisualizerPrefsChanged, _2)); sPrefsInitialized = true; } diff --git a/indra/newview/llvoicevisualizer.h b/indra/newview/llvoicevisualizer.h index 0cbf24b786..1887849300 100644 --- a/indra/newview/llvoicevisualizer.h +++ b/indra/newview/llvoicevisualizer.h @@ -121,7 +121,7 @@ class LLVoiceVisualizer : public LLHUDEffect bool mWaveActive [ NUM_VOICE_SYMBOL_WAVES ]; F64 mWaveFadeOutStartTime [ NUM_VOICE_SYMBOL_WAVES ]; F32 mWaveOpacity [ NUM_VOICE_SYMBOL_WAVES ]; - LLPointer mTexture [ NUM_VOICE_SYMBOL_WAVES ]; + LLPointer mTexture [ NUM_VOICE_SYMBOL_WAVES ]; bool mActive; LLVector3 mPosition; }; diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp index 29036f4947..38c9ce28c4 100644 --- a/indra/newview/llvopartgroup.cpp +++ b/indra/newview/llvopartgroup.cpp @@ -139,9 +139,10 @@ LLVector3 LLVOPartGroup::getCameraPosition() const return gAgent.getCameraPositionAgent(); } +static LLFastTimer::DeclareTimer FTM_UPDATE_PARTICLES("Update Particles"); BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_PARTICLES); + LLFastTimer ftm(FTM_UPDATE_PARTICLES); dirtySpatialGroup(); @@ -416,12 +417,15 @@ void LLParticlePartition::addGeometryCount(LLSpatialGroup* group, U32& vertex_co } } +static LLFastTimer::DeclareTimer FTM_REBUILD_GRASS_VB("Grass VB"); +static LLFastTimer::DeclareTimer FTM_REBUILD_PARTICLE_VB("Particle VB"); + void LLParticlePartition::getGeometry(LLSpatialGroup* group) { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); LLFastTimer ftm(mDrawableType == LLPipeline::RENDER_TYPE_GRASS ? - LLFastTimer::FTM_REBUILD_GRASS_VB : - LLFastTimer::FTM_REBUILD_PARTICLE_VB); + FTM_REBUILD_GRASS_VB : + FTM_REBUILD_PARTICLE_VB); std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater()); diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp index d4df141477..ae5992099d 100644 --- a/indra/newview/llvosky.cpp +++ b/indra/newview/llvosky.cpp @@ -49,7 +49,7 @@ #include "llglheaders.h" #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llworld.h" @@ -212,8 +212,8 @@ void LLSkyTex::init() for (S32 i = 0; i < 2; ++i) { - mImageGL[i] = new LLImageGL(FALSE); - mImageGL[i]->setAddressMode(LLTexUnit::TAM_CLAMP); + mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE); + mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP); mImageRaw[i] = new LLImageRaw(sResolution, sResolution, sComponents); initEmpty(i); @@ -222,16 +222,16 @@ void LLSkyTex::init() void LLSkyTex::cleanupGL() { - mImageGL[0] = NULL; - mImageGL[1] = NULL; + mTexture[0] = NULL; + mTexture[1] = NULL; } void LLSkyTex::restoreGL() { for (S32 i = 0; i < 2; i++) { - mImageGL[i] = new LLImageGL(FALSE); - mImageGL[i]->setAddressMode(LLTexUnit::TAM_CLAMP); + mTexture[i] = LLViewerTextureManager::getLocalTexture(FALSE); + mTexture[i]->setAddressMode(LLTexUnit::TAM_CLAMP); } } @@ -289,13 +289,13 @@ void LLSkyTex::create(const F32 brightness) void LLSkyTex::createGLImage(S32 which) { - mImageGL[which]->createGLTexture(0, mImageRaw[which]); - mImageGL[which]->setAddressMode(LLTexUnit::TAM_CLAMP); + mTexture[which]->createGLTexture(0, mImageRaw[which]); + mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP); } void LLSkyTex::bindTexture(BOOL curr) { - gGL.getTexUnit(0)->bind(mImageGL[getWhich(curr)]); + gGL.getTexUnit(0)->bind(mTexture[getWhich(curr)]); } /*************************************** @@ -376,11 +376,11 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) mSun.setIntensity(SUN_INTENSITY); mMoon.setIntensity(0.1f * SUN_INTENSITY); - mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE); + mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, TRUE); mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE); + mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, TRUE); mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mBloomTexturep = gImageList.getImage(IMG_BLOOM1); + mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); mBloomTexturep->setNoDelete() ; mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -390,7 +390,7 @@ LLVOSky::LLVOSky(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) LLVOSky::~LLVOSky() { - // Don't delete images - it'll get deleted by gImageList on shutdown + // Don't delete images - it'll get deleted by gTextureList on shutdown // This needs to be done for each texture mCubeMap = NULL; @@ -472,11 +472,11 @@ void LLVOSky::restoreGL() { mSkyTex[i].restoreGL(); } - mSunTexturep = gImageList.getImage(gSunTextureID, TRUE, TRUE); + mSunTexturep = LLViewerTextureManager::getFetchedTexture(gSunTextureID, TRUE, TRUE); mSunTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mMoonTexturep = gImageList.getImage(gMoonTextureID, TRUE, TRUE); + mMoonTexturep = LLViewerTextureManager::getFetchedTexture(gMoonTextureID, TRUE, TRUE); mMoonTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); - mBloomTexturep = gImageList.getImage(IMG_BLOOM1); + mBloomTexturep = LLViewerTextureManager::getFetchedTexture(IMG_BLOOM1); mBloomTexturep->setNoDelete() ; mBloomTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); @@ -1231,6 +1231,8 @@ void LLVOSky::createDummyVertexBuffer() } } +static LLFastTimer::DeclareTimer FTM_RENDER_FAKE_VBO_UPDATE("Fake VBO Update"); + void LLVOSky::updateDummyVertexBuffer() { if(!LLVertexBuffer::sEnableVBOs) @@ -1242,7 +1244,7 @@ void LLVOSky::updateDummyVertexBuffer() return ; } - LLFastTimer t(LLFastTimer::FTM_RENDER_FAKE_VBO_UPDATE) ; + LLFastTimer t(FTM_RENDER_FAKE_VBO_UPDATE) ; if(!mFace[FACE_DUMMY] || mFace[FACE_DUMMY]->mVertexBuffer.isNull()) createDummyVertexBuffer() ; @@ -1255,10 +1257,11 @@ void LLVOSky::updateDummyVertexBuffer() //---------------------------------- //end of fake vertex buffer updating //---------------------------------- +static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); BOOL LLVOSky::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY); + LLFastTimer ftm(FTM_GEO_SKY); if (mFace[FACE_REFLECTION] == NULL) { LLDrawPoolWater *poolp = (LLDrawPoolWater*) gPipeline.getPool(LLDrawPool::POOL_WATER); diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h index 5e23065153..466cdfdcd0 100644 --- a/indra/newview/llvosky.h +++ b/indra/newview/llvosky.h @@ -36,7 +36,7 @@ #include "stdtypes.h" #include "v3color.h" #include "v4coloru.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llviewerobject.h" #include "llframetimer.h" @@ -122,7 +122,7 @@ class LLSkyTex private: static S32 sResolution; static S32 sComponents; - LLPointer mImageGL[2]; + LLPointer mTexture[2]; LLPointer mImageRaw[2]; LLColor4 *mSkyData; LLVector3 *mSkyDirs; // Cache of sky direction vectors @@ -567,9 +567,9 @@ public: BOOL isReflFace(const LLFace* face) const { return face == mFace[FACE_REFLECTION]; } LLFace* getReflFace() const { return mFace[FACE_REFLECTION]; } - LLViewerImage* getSunTex() const { return mSunTexturep; } - LLViewerImage* getMoonTex() const { return mMoonTexturep; } - LLViewerImage* getBloomTex() const { return mBloomTexturep; } + LLViewerTexture* getSunTex() const { return mSunTexturep; } + LLViewerTexture* getMoonTex() const { return mMoonTexturep; } + LLViewerTexture* getBloomTex() const { return mBloomTexturep; } void forceSkyUpdate(void) { mForceUpdate = TRUE; } public: @@ -579,9 +579,9 @@ public: protected: ~LLVOSky(); - LLPointer mSunTexturep; - LLPointer mMoonTexturep; - LLPointer mBloomTexturep; + LLPointer mSunTexturep; + LLPointer mMoonTexturep; + LLPointer mBloomTexturep; static S32 sResolution; static S32 sTileResX; diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 4980b50de4..157d719fcc 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -176,10 +176,11 @@ LLDrawable *LLVOSurfacePatch::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_TERRAIN("Update Terrain"); BOOL LLVOSurfacePatch::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TERRAIN); + LLFastTimer ftm(FTM_UPDATE_TERRAIN); dirtySpatialGroup(); @@ -1028,9 +1029,10 @@ LLVertexBuffer* LLTerrainPartition::createVertexBuffer(U32 type_mask, U32 usage) return new LLVertexBufferTerrain(); } +static LLFastTimer::DeclareTimer FTM_REBUILD_TERRAIN_VB("Terrain VB"); void LLTerrainPartition::getGeometry(LLSpatialGroup* group) { - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_TERRAIN_VB); + LLFastTimer ftm(FTM_REBUILD_TERRAIN_VB); LLVertexBuffer* buffer = group->mVertexBuffer; diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp index de69aac037..f5094c025e 100644 --- a/indra/newview/llvotextbubble.cpp +++ b/indra/newview/llvotextbubble.cpp @@ -39,11 +39,10 @@ #include "llprimitive.h" #include "llrendersphere.h" -#include "llagent.h" #include "llbox.h" #include "lldrawable.h" #include "llface.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llvolume.h" #include "pipeline.h" #include "llviewerregion.h" @@ -125,7 +124,7 @@ void LLVOTextBubble::updateTextures(LLAgent &agent) const LLTextureEntry *te = getTE(i); F32 texel_area_ratio = fabs(te->mScaleS * te->mScaleT); texel_area_ratio = llclamp(texel_area_ratio, .125f, 16.f); - LLViewerImage *imagep = getTEImage(i); + LLViewerTexture *imagep = getTEImage(i); if (imagep) { imagep->addTextureStats(mPixelArea / texel_area_ratio); @@ -142,9 +141,9 @@ LLDrawable *LLVOTextBubble::createDrawable(LLPipeline *pipeline) for (U32 i = 0; i < getNumTEs(); i++) { - LLViewerImage *imagep; + LLViewerTexture *imagep; const LLTextureEntry *texture_entry = getTE(i); - imagep = gImageList.getImage(texture_entry->getID()); + imagep = LLViewerTextureManager::getFetchedTexture(texture_entry->getID()); mDrawable->addFace((LLFacePool*) NULL, imagep); } @@ -194,7 +193,7 @@ BOOL LLVOTextBubble::updateGeometry(LLDrawable *drawable) { LLFace *face = drawable->getFace(i); face->setTEOffset(i); - face->setTexture(LLViewerImage::sSmokeImagep); + face->setTexture(LLViewerFetchedTexture::sSmokeImagep); face->setState(LLFace::FULLBRIGHT); } diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp index 3fd5054fd1..86d9f31d07 100644 --- a/indra/newview/llvotree.cpp +++ b/indra/newview/llvotree.cpp @@ -48,14 +48,14 @@ #include "lldrawable.h" #include "llface.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobjectlist.h" #include "llviewerregion.h" #include "llworld.h" #include "noise.h" #include "pipeline.h" #include "llspatialpartition.h" -#include "llviewerwindow.h" +#include "llnotifications.h" extern LLPipeline gPipeline; @@ -311,10 +311,10 @@ U32 LLVOTree::processUpdateMessage(LLMessageSystem *mesgsys, // // Load Species-Specific data // - mTreeImagep = gImageList.getImage(sSpeciesTable[mSpecies]->mTextureID); + mTreeImagep = LLViewerTextureManager::getFetchedTexture(sSpeciesTable[mSpecies]->mTextureID, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); if (mTreeImagep) { - gGL.getTexUnit(0)->bind(mTreeImagep.get()); + gGL.getTexUnit(0)->bind(mTreeImagep); } mBranchLength = sSpeciesTable[mSpecies]->mBranchLength; mTrunkLength = sSpeciesTable[mSpecies]->mTrunkLength; @@ -504,9 +504,11 @@ LLDrawable* LLVOTree::createDrawable(LLPipeline *pipeline) const S32 LEAF_INDICES = 24; const S32 LEAF_VERTICES = 16; +static LLFastTimer::DeclareTimer FTM_UPDATE_TREE("Update Tree"); + BOOL LLVOTree::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_TREE); + LLFastTimer ftm(FTM_UPDATE_TREE); if (mReferenceBuffer.isNull() || mDrawable->getFace(0)->mVertexBuffer.isNull()) { diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h index 42a6d54f62..13817fa111 100644 --- a/indra/newview/llvotree.h +++ b/indra/newview/llvotree.h @@ -39,7 +39,7 @@ class LLFace; class LLDrawPool; - +class LLViewerFetchedTexture; class LLVOTree : public LLViewerObject { @@ -160,7 +160,7 @@ protected: LLVector3 mWind; LLPointer mReferenceBuffer; //reference geometry for generating tree mesh - LLPointer mTreeImagep; // Pointer to proper tree image + LLPointer mTreeImagep; // Pointer to proper tree image U8 mSpecies; // Species of tree F32 mBranchLength; // Scale (length) of tree branches @@ -184,7 +184,7 @@ protected: // complete rebuild when not animating LLVector3 mLastPosition; LLQuaternion mLastRotation; - + U32 mFrameCount; typedef std::map SpeciesMap; diff --git a/indra/newview/llvotreenew.h b/indra/newview/llvotreenew.h index 02f6d3a056..3fec5855ef 100644 --- a/indra/newview/llvotreenew.h +++ b/indra/newview/llvotreenew.h @@ -41,7 +41,7 @@ #include "llstrider.h" #include "v2math.h" #include "v3math.h" -#include "llviewerimage.h" +#include "llviewertexture.h" class LLFace; class LLDrawPool; @@ -187,7 +187,7 @@ public: //LLTreeParams mParams; U8 mSpecies; - LLPointer mTreeImagep; + LLPointer mTreeImagep; LLMatrix4 mTrunkFlareFrames[MAX_FLARE]; F32 mSegSplitsError[3]; U32 mRandOffset[MAX_LEVELS]; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index dd68733d98..940accdd06 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -47,7 +47,7 @@ #include "material_codes.h" #include "message.h" #include "object_flags.h" -#include "llagent.h" +#include "llagentconstants.h" #include "lldrawable.h" #include "lldrawpoolbump.h" #include "llface.h" @@ -59,7 +59,7 @@ #include "llsky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "llviewertextureanim.h" #include "llworld.h" @@ -72,13 +72,16 @@ const F32 FORCE_CULL_AREA = 8.f; const S32 MAX_SCULPT_REZ = 128; BOOL gAnimateTextures = TRUE; -extern BOOL gHideSelectedObjects; +//extern BOOL gHideSelectedObjects; F32 LLVOVolume::sLODFactor = 1.f; F32 LLVOVolume::sLODSlopDistanceFactor = 0.5f; //Changing this to zero, effectively disables the LOD transition slop F32 LLVOVolume::sDistanceFactor = 1.0f; S32 LLVOVolume::sNumLODChanges = 0; +static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles"); +static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes"); + LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp) : LLViewerObject(id, pcode, regionp), mVolumeImpl(NULL) @@ -427,7 +430,7 @@ void LLVOVolume::updateTextures() return; } - if (LLViewerImage::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible()) + if (LLViewerTexture::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible()) { return; } @@ -443,7 +446,7 @@ void LLVOVolume::updateTextures() { LLFace* face = mDrawable->getFace(i); const LLTextureEntry *te = face->getTextureEntry(); - LLViewerImage *imagep = face->getTexture(); + LLViewerTexture *imagep = face->getTexture(); if (!imagep || !te || face->mExtents[0] == face->mExtents[1]) { @@ -456,7 +459,7 @@ void LLVOVolume::updateTextures() { F32 area = (F32) LLViewerCamera::getInstance()->getScreenPixelArea(); vsize = area; - imagep->setBoostLevel(LLViewerImage::BOOST_HUD); + imagep->setBoostLevel(LLViewerTexture::BOOST_HUD); face->setPixelArea(area); // treat as full screen } else @@ -486,10 +489,14 @@ void LLVOVolume::updateTextures() } else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY)) { - F32 pri = imagep->getDecodePriority(); - pri = llmax(pri, 0.0f); - if (pri < min_vsize) min_vsize = pri; - if (pri > max_vsize) max_vsize = pri; + LLViewerFetchedTexture* img = LLViewerTextureManager::staticCastToFetchedTexture(imagep) ; + if(img) + { + F32 pri = img->getDecodePriority(); + pri = llmax(pri, 0.0f); + if (pri < min_vsize) min_vsize = pri; + if (pri > max_vsize) max_vsize = pri; + } } else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA)) { @@ -503,7 +510,7 @@ void LLVOVolume::updateTextures() { LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT); LLUUID id = sculpt_params->getSculptTexture(); - mSculptTexture = gImageList.getImage(id); + mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); if (mSculptTexture.notNull()) { S32 lod = llmin(mLOD, 3); @@ -511,7 +518,8 @@ void LLVOVolume::updateTextures() F32 tex_size = lodf * MAX_SCULPT_REZ; mSculptTexture->addTextureStats(2.f * tex_size * tex_size); mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(), - (S32)LLViewerImage::BOOST_SCULPTED)); + (S32)LLViewerTexture::BOOST_SCULPTED)); + mSculptTexture->setForSculpt() ; } S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture @@ -624,7 +632,7 @@ void LLVOVolume::setScale(const LLVector3 &scale, BOOL damped) LLFace* LLVOVolume::addFace(S32 f) { const LLTextureEntry* te = getTE(f); - LLViewerImage* imagep = getTEImage(f); + LLViewerTexture* imagep = getTEImage(f); return mDrawable->addFace(te, imagep); } @@ -700,7 +708,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail if (isSculpted()) { - mSculptTexture = gImageList.getImage(volume_params.getSculptID()); + mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); if (mSculptTexture.notNull()) { sculpt(); @@ -781,6 +789,11 @@ void LLVOVolume::sculpt() sculpt_width = 0; sculpt_height = 0; sculpt_data = NULL ; + + if(LLViewerTextureManager::sTesterp) + { + LLViewerTextureManager::sTesterp->updateGrayTextureBinding(); + } } else { @@ -789,6 +802,11 @@ void LLVOVolume::sculpt() << " < " << sculpt_height << " x " << sculpt_width << " x " <getData(); + + if(LLViewerTextureManager::sTesterp) + { + mSculptTexture->updateBindStatsForTester() ; + } } getVolume()->sculpt(sculpt_width, sculpt_height, sculpt_components, sculpt_data, discard_level); } @@ -923,17 +941,20 @@ void LLVOVolume::updateFaceFlags() } } -void LLVOVolume::setParent(LLViewerObject* parent) +BOOL LLVOVolume::setParent(LLViewerObject* parent) { + BOOL ret = FALSE ; if (parent != getParent()) { - LLViewerObject::setParent(parent); - if (mDrawable) + ret = LLViewerObject::setParent(parent); + if (ret && mDrawable) { gPipeline.markMoved(mDrawable); gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, TRUE); } } + + return ret ; } // NOTE: regenFaces() MUST be followed by genTriangles()! @@ -1112,15 +1133,18 @@ void LLVOVolume::updateRelativeXform() } } +static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies"); +static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives"); + BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { - LLFastTimer t(LLFastTimer::FTM_UPDATE_PRIMITIVES); + LLFastTimer t(FTM_UPDATE_PRIMITIVES); if (mVolumeImpl != NULL) { BOOL res; { - LLFastTimer t(LLFastTimer::FTM_GEN_FLEX); + LLFastTimer t(FTM_GEN_FLEX); res = mVolumeImpl->doUpdateGeometry(drawable); } updateFaceFlags(); @@ -1144,14 +1168,14 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) if (mVolumeChanged) { - LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME); + LLFastTimer ftm(FTM_GEN_VOLUME); LLVolumeParams volume_params = getVolume()->getParams(); setVolume(volume_params, 0); drawable->setState(LLDrawable::REBUILD_VOLUME); } { - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); regenFaces(); genBBoxes(FALSE); } @@ -1168,7 +1192,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) old_volumep = NULL ; { - LLFastTimer ftm(LLFastTimer::FTM_GEN_VOLUME); + LLFastTimer ftm(FTM_GEN_VOLUME); LLVolumeParams volume_params = getVolume()->getParams(); setVolume(volume_params, 0); } @@ -1186,7 +1210,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) drawable->setState(LLDrawable::REBUILD_VOLUME); // for face->genVolumeTriangles() { - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); if (new_num_faces != old_num_faces) { regenFaces(); @@ -1200,7 +1224,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable) { compiled = TRUE; // All it did was move or we changed the texture coordinate offset - LLFastTimer t(LLFastTimer::FTM_GEN_TRIANGLES); + LLFastTimer t(FTM_GEN_TRIANGLES); genBBoxes(FALSE); } @@ -1243,7 +1267,7 @@ BOOL LLVOVolume::isRootEdit() const return TRUE; } -void LLVOVolume::setTEImage(const U8 te, LLViewerImage *imagep) +void LLVOVolume::setTEImage(const U8 te, LLViewerTexture *imagep) { BOOL changed = (mTEImages[te] != imagep); LLViewerObject::setTEImage(te, imagep); @@ -1735,7 +1759,7 @@ void LLVOVolume::generateSilhouette(LLSelectNode* nodep, const LLVector3& view_p trans_mat.translate(getRegion()->getOriginAgent()); } - volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans); + volume->generateSilhouetteVertices(nodep->mSilhouetteVertices, nodep->mSilhouetteNormals, nodep->mSilhouetteSegments, view_vector, trans_mat, mRelativeXformInvTrans, nodep->getTESelectMask()); nodep->mSilhouetteExists = TRUE; } @@ -1977,10 +2001,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal) { - if (!mbCanSelect || - (gHideSelectedObjects && isSelected()) || - mDrawable->isDead() || - !gPipeline.hasRenderType(mDrawable->getRenderType())) + if (!mbCanSelect + || mDrawable->isDead() + || !gPipeline.hasRenderType(mDrawable->getRenderType())) { return FALSE; } @@ -2043,7 +2066,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e { LLFace* face = mDrawable->getFace(face_hit); - if (pick_transparent || !face->getTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) + if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))) { v_end = p; if (face_hitp != NULL) @@ -2120,7 +2143,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, { LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION); - if (facep->getViewerObject()->isSelected() && gHideSelectedObjects) + if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects) { return; } @@ -2154,7 +2177,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0); - LLViewerImage* tex = facep->getTexture(); + LLViewerTexture* tex = facep->getTexture(); U8 glow = 0; @@ -2218,6 +2241,9 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group) } +static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume"); +static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt"); + void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (LLPipeline::sSkipUpdate) @@ -2236,8 +2262,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { if (group->isState(LLSpatialGroup::MESH_DIRTY) && !LLPipeline::sDelayVBUpdate) { - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); - LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB); + LLFastTimer ftm(FTM_REBUILD_VBO); + LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); rebuildMesh(group); } @@ -2245,9 +2271,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) } group->mBuilt = 1.f; - LLFastTimer ftm(LLFastTimer::FTM_REBUILD_VBO); + LLFastTimer ftm(FTM_REBUILD_VBO); - LLFastTimer ftm2(LLFastTimer::FTM_REBUILD_VOLUME_VB); + LLFastTimer ftm2(FTM_REBUILD_VOLUME_VB); group->clearDrawMap(); @@ -2305,7 +2331,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (facep->hasGeometry() && facep->mPixelArea > FORCE_CULL_AREA) { const LLTextureEntry* te = facep->getTextureEntry(); - LLViewerImage* tex = facep->getTexture(); + LLViewerTexture* tex = facep->getTexture(); if (facep->isState(LLFace::TEXTURE_ANIM)) { @@ -2553,7 +2579,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: LLSpatialGroup::buffer_map_t buffer_map; - LLViewerImage* last_tex = NULL; + LLViewerTexture* last_tex = NULL; S32 buffer_index = 0; if (distance_sort) @@ -2565,7 +2591,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std:: { //pull off next face LLFace* facep = *face_iter; - LLViewerImage* tex = facep->getTexture(); + LLViewerTexture* tex = facep->getTexture(); if (distance_sort) { diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 9b4e715194..d343d4db74 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -34,9 +34,11 @@ #define LL_LLVOVOLUME_H #include "llviewerobject.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llframetimer.h" #include "llapr.h" +#include "m3math.h" // LLMatrix3 +#include "m4math.h" // LLMatrix4 #include class LLViewerTextureAnim; @@ -105,7 +107,7 @@ public: /*virtual*/ BOOL isHUDAttachment() const; void generateSilhouette(LLSelectNode* nodep, const LLVector3& view_point); - /*virtual*/ void setParent(LLViewerObject* parent); + /*virtual*/ BOOL setParent(LLViewerObject* parent); S32 getLOD() const { return mLOD; } const LLVector3 getPivotPositionAgent() const; const LLMatrix4& getRelativeXform() const { return mRelativeXform; } @@ -151,7 +153,7 @@ public: /*virtual*/ void setScale(const LLVector3 &scale, BOOL damped); - /*virtual*/ void setTEImage(const U8 te, LLViewerImage *imagep); + /*virtual*/ void setTEImage(const U8 te, LLViewerTexture *imagep); /*virtual*/ S32 setTETexture(const U8 te, const LLUUID &uuid); /*virtual*/ S32 setTEColor(const U8 te, const LLColor3 &color); /*virtual*/ S32 setTEColor(const U8 te, const LLColor4 &color); @@ -235,7 +237,7 @@ private: BOOL mVolumeChanged; F32 mVObjRadius; LLVolumeInterface *mVolumeImpl; - LLPointer mSculptTexture; + LLPointer mSculptTexture; // statics public: diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp index d23c746b75..e2357957ab 100644 --- a/indra/newview/llvowater.cpp +++ b/indra/newview/llvowater.cpp @@ -37,7 +37,6 @@ #include "imageids.h" #include "llviewercontrol.h" -#include "llagent.h" #include "lldrawable.h" #include "lldrawpoolwater.h" #include "llface.h" @@ -45,7 +44,7 @@ #include "llsurface.h" #include "llvosky.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "llworld.h" #include "pipeline.h" @@ -139,9 +138,11 @@ LLDrawable *LLVOWater::createDrawable(LLPipeline *pipeline) return mDrawable; } +static LLFastTimer::DeclareTimer FTM_UPDATE_WATER("Update Water"); + BOOL LLVOWater::updateGeometry(LLDrawable *drawable) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WATER); + LLFastTimer ftm(FTM_UPDATE_WATER); LLFace *face; if (drawable->getNumFaces() < 1) diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h index cdda48f6f2..28a5633c58 100644 --- a/indra/newview/llvowater.h +++ b/indra/newview/llvowater.h @@ -34,7 +34,7 @@ #define LL_VOWATER_H #include "llviewerobject.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "v2math.h" const U32 N_RES = 16; //32 // number of subdivisions of wave tile diff --git a/indra/newview/llvowlsky.cpp b/indra/newview/llvowlsky.cpp index abd25e6598..8621e5e1d9 100644 --- a/indra/newview/llvowlsky.cpp +++ b/indra/newview/llvowlsky.cpp @@ -307,9 +307,11 @@ void LLVOWLSky::restoreGL() gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_ALL, TRUE); } +static LLFastTimer::DeclareTimer FTM_GEO_SKY("Sky Geometry"); + BOOL LLVOWLSky::updateGeometry(LLDrawable * drawable) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_SKY); + LLFastTimer ftm(FTM_GEO_SKY); LLStrider vertices; LLStrider texCoords; LLStrider indices; diff --git a/indra/newview/llwatchdog.h b/indra/newview/llwatchdog.h index ed7d5bdcfb..79398c434a 100644 --- a/indra/newview/llwatchdog.h +++ b/indra/newview/llwatchdog.h @@ -64,9 +64,10 @@ public: /* virtual */ bool isAlive() const; /* virtual */ void reset(); - /* virtual */ void start(const std::string& state); + /* virtual */ void start() { start(""); } /* virtual */ void stop(); + void start(const std::string& state); void setTimeout(F32 d); void ping(const std::string& state); const std::string& getState() {return mPingState; } diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 50e407739b..3661be500b 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -39,6 +39,7 @@ #include "pipeline.h" #include "llsky.h" +#include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" @@ -262,17 +263,20 @@ void LLWaterParamManager::updateShaderUniforms(LLGLSLShader * shader) } } +static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); + void LLWaterParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); // update the shaders and the menu propagateParameters(); // sync menus if they exist - if(LLFloaterWater::isOpen()) + LLFloaterWater* waterfloater = LLFloaterReg::findTypedInstance("env_water"); + if(waterfloater) { - LLFloaterWater::instance()->syncMenu(); + waterfloater->syncMenu(); } stop_glerror(); diff --git a/indra/newview/llwaterparamset.cpp b/indra/newview/llwaterparamset.cpp index a26ccedfb2..3e97f9dbef 100644 --- a/indra/newview/llwaterparamset.cpp +++ b/indra/newview/llwaterparamset.cpp @@ -39,7 +39,7 @@ #include "llwaterparammanager.h" #include "lluictrlfactory.h" #include "llsliderctrl.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewercontrol.h" #include "lluuid.h" diff --git a/indra/newview/llwearable.cpp b/indra/newview/llwearable.cpp index f705531723..0d3dd10a01 100644 --- a/indra/newview/llwearable.cpp +++ b/indra/newview/llwearable.cpp @@ -32,92 +32,27 @@ #include "llviewerprecompiledheaders.h" -#include "imageids.h" -#include "llassetstorage.h" -#include "lldbstrings.h" -#include "lldir.h" -#include "llquantize.h" - #include "llagent.h" -#include "llassetuploadresponders.h" -#include "llviewerwindow.h" +#include "llagentwearables.h" #include "llfloatercustomize.h" +#include "llviewertexturelist.h" #include "llinventorymodel.h" -#include "llviewerimagelist.h" -#include "llviewerinventory.h" #include "llviewerregion.h" #include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llvoavatardefines.h" #include "llwearable.h" +#include "lldictionary.h" +#include "lltrans.h" using namespace LLVOAvatarDefines; // static S32 LLWearable::sCurrentDefinitionVersion = 1; -// static -const std::string LLWearable::sTypeName[ WT_COUNT+1 ] = -{ - "shape", - "skin", - "hair", - "eyes", - "shirt", - "pants", - "shoes", - "socks", - "jacket", - "gloves", - "undershirt", - "underpants", - "skirt", - "invalid" -}; - -// static -const std::string LLWearable::sTypeLabel[ WT_COUNT+1 ] = -{ - "Shape", - "Skin", - "Hair", - "Eyes", - "Shirt", - "Pants", - "Shoes", - "Socks", - "Jacket", - "Gloves", - "Undershirt", - "Underpants", - "Skirt", - "invalid" -}; - - -// static -LLAssetType::EType LLWearable::typeToAssetType(EWearableType wearable_type) -{ - switch( wearable_type ) - { - case WT_SHAPE: - case WT_SKIN: - case WT_HAIR: - case WT_EYES: - return LLAssetType::AT_BODYPART; - case WT_SHIRT: - case WT_PANTS: - case WT_SHOES: - case WT_SOCKS: - case WT_JACKET: - case WT_GLOVES: - case WT_UNDERSHIRT: - case WT_UNDERPANTS: - case WT_SKIRT: - return LLAssetType::AT_CLOTHING; - default: - return LLAssetType::AT_NONE; - } -} - +// Private local functions +static std::string terse_F32_to_string(F32 f); +static std::string asset_id_to_filename(const LLUUID &asset_id); LLWearable::LLWearable(const LLTransactionID& transaction_id) : mDefinitionVersion(LLWearable::sCurrentDefinitionVersion), @@ -139,56 +74,22 @@ LLWearable::~LLWearable() { } - -// static -EWearableType LLWearable::typeNameToType( const std::string& type_name ) +const std::string& LLWearable::getTypeLabel() const { - for( S32 i = 0; i < WT_COUNT; i++ ) - { - if( type_name == LLWearable::sTypeName[ i ] ) - { - return (EWearableType)i; - } - } - return WT_INVALID; + return LLWearableDictionary::getTypeLabel(mType); } - -std::string terse_F32_to_string( F32 f ) +const std::string& LLWearable::getTypeName() const { - std::string r = llformat( "%.2f", f ); - - // "1.20" -> "1.2" - // "24.00" -> "24." - S32 len = r.length(); - while( len > 0 && '0' == r[len - 1] ) - { - r.erase(len-1, 1); - len--; - } - - if( '.' == r[len - 1] ) - { - // "24." -> "24" - r.erase(len-1, 1); - } - else - if( ('-' == r[0]) && ('0' == r[1]) ) - { - // "-0.59" -> "-.59" - r.erase(1, 1); - } - else - if( '0' == r[0] ) - { - // "0.59" -> ".59" - r.erase(0, 1); - } - - return r; + return LLWearableDictionary::getTypeName(mType); } -BOOL LLWearable::exportFile( LLFILE* file ) +LLAssetType::EType LLWearable::getAssetType() const +{ + return LLWearableDictionary::getAssetType(mType); +} + +BOOL LLWearable::exportFile(LLFILE* file) const { // header and version if( fprintf( file, "LLWearable version %d\n", mDefinitionVersion ) < 0 ) @@ -234,7 +135,7 @@ BOOL LLWearable::exportFile( LLFILE* file ) return FALSE; } - for (param_map_t::iterator iter = mVisualParamMap.begin(); + for (param_map_t::const_iterator iter = mVisualParamMap.begin(); iter != mVisualParamMap.end(); ++iter) { S32 param_id = iter->first; @@ -252,22 +153,18 @@ BOOL LLWearable::exportFile( LLFILE* file ) return FALSE; } - for (te_map_t::iterator iter = mTEMap.begin(); - iter != mTEMap.end(); ++iter) + for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter) { S32 te = iter->first; - LLUUID& image_id = iter->second; + const LLUUID& image_id = iter->second.getID(); if( fprintf( file, "%d %s\n", te, image_id.asString().c_str()) < 0 ) { return FALSE; } } - return TRUE; } - - BOOL LLWearable::importFile( LLFILE* file ) { // *NOTE: changing the type or size of this buffer will require @@ -453,7 +350,8 @@ BOOL LLWearable::importFile( LLFILE* file ) return FALSE; } - mTEMap[te] = LLUUID(text_buffer ); + //TODO: check old values + mTEMap[te] = LLLocalTextureObject(NULL, NULL, NULL, LLUUID(text_buffer)); } return TRUE; @@ -463,7 +361,7 @@ BOOL LLWearable::importFile( LLFILE* file ) // Avatar parameter and texture definitions can change over time. // This function returns true if parameters or textures have been added or removed // since this wearable was created. -BOOL LLWearable::isOldVersion() +BOOL LLWearable::isOldVersion() const { LLVOAvatar* avatar = gAgent.getAvatarObject(); llassert( avatar ); @@ -506,7 +404,7 @@ BOOL LLWearable::isOldVersion() S32 te_count = 0; for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { te_count++; if( !is_in_map(mTEMap, te ) ) @@ -530,7 +428,7 @@ BOOL LLWearable::isOldVersion() // * If parameters or textures have been ADDED since the wearable was created, // they are taken to have default values, so we consider the wearable clean // only if those values are the same as the defaults. -BOOL LLWearable::isDirty() +BOOL LLWearable::isDirty() const { LLVOAvatar* avatar = gAgent.getAvatarObject(); llassert( avatar ); @@ -560,18 +458,23 @@ BOOL LLWearable::isDirty() for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - LLViewerImage* avatar_image = avatar->getTEImage( te ); + LLViewerTexture* avatar_image = avatar->getTEImage( te ); if( !avatar_image ) { llassert( 0 ); continue; } - const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) ); - if( avatar_image->getID() != image_id ) + + te_map_t::const_iterator iter = mTEMap.find(te); + if(iter != mTEMap.end()) { - return TRUE; + const LLUUID& image_id = iter->second.getID(); + if (avatar_image->getID() != image_id) + { + return TRUE; + } } } } @@ -612,9 +515,9 @@ void LLWearable::setTexturesToDefaults() mTEMap.clear(); for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - mTEMap[te] = LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ); + mTEMap[te] = LLLocalTextureObject(NULL, NULL, NULL, LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te)); } } } @@ -622,7 +525,7 @@ void LLWearable::setTexturesToDefaults() // Updates the user's avatar's appearance void LLWearable::writeToAvatar( BOOL set_by_user ) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); llassert( avatar ); if( !avatar ) { @@ -659,11 +562,20 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) // Pull texture entries for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - const LLUUID& image_id = get_if_there(mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) ); - LLViewerImage* image = gImageList.getImage( image_id ); - avatar->setLocTexTE( te, image, set_by_user ); + te_map_t::const_iterator iter = mTEMap.find(te); + LLUUID image_id; + if(iter != mTEMap.end()) + { + image_id = iter->second.getID(); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + } + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( image_id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE ); + avatar->setLocalTextureTE(te, image, set_by_user); } } @@ -672,7 +584,8 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) if( gFloaterCustomize ) { LLViewerInventoryItem* item; - item = (LLViewerInventoryItem*)gInventory.getItem(gAgent.getWearableItem(mType)); + // MULTI_WEARABLE: + item = (LLViewerInventoryItem*)gInventory.getItem(gAgentWearables.getWearableItemID(mType,0)); U32 perm_mask = PERM_NONE; BOOL is_complete = FALSE; if(item) @@ -685,7 +598,7 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) } } gFloaterCustomize->setWearable(mType, this, perm_mask, is_complete); - LLFloaterCustomize::setCurrentWearableType( mType ); + gFloaterCustomize->setCurrentWearableType( mType ); } ESex new_sex = avatar->getSex(); @@ -706,7 +619,7 @@ void LLWearable::writeToAvatar( BOOL set_by_user ) // static void LLWearable::removeFromAvatar( EWearableType type, BOOL set_by_user ) { - LLVOAvatar* avatar = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); llassert( avatar ); if( !avatar ) { @@ -733,12 +646,12 @@ void LLWearable::removeFromAvatar( EWearableType type, BOOL set_by_user ) } // Pull textures - LLViewerImage* image = gImageList.getImage( IMG_DEFAULT_AVATAR ); + LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture( IMG_DEFAULT_AVATAR ); for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == type ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == type) { - avatar->setLocTexTE( te, image, set_by_user ); + avatar->setLocalTextureTE(te, image, set_by_user); } } @@ -782,12 +695,12 @@ void LLWearable::readFromAvatar() mTEMap.clear(); for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - LLViewerImage* image = avatar->getTEImage( te ); + LLViewerTexture* image = avatar->getTEImage( te ); if( image ) { - mTEMap[te] = image->getID(); + mTEMap[te] = LLLocalTextureObject(NULL, NULL, NULL, image->getID()); } } } @@ -800,7 +713,7 @@ void LLWearable::readFromAvatar() // Does not copy mAssetID. // Definition version is current: removes obsolete enties and creates default values for new ones. -void LLWearable::copyDataFrom( LLWearable* src ) +void LLWearable::copyDataFrom(const LLWearable* src) { LLVOAvatar* avatar = gAgent.getAvatarObject(); llassert( avatar ); @@ -833,28 +746,67 @@ void LLWearable::copyDataFrom( LLWearable* src ) // Deep copy of mTEMap (copies only those tes that are current, filling in defaults where needed) for( S32 te = 0; te < TEX_NUM_INDICES; te++ ) { - if( LLVOAvatar::getTEWearableType((ETextureIndex) te ) == mType ) + if (LLVOAvatarDictionary::getTEWearableType((ETextureIndex) te) == mType) { - const LLUUID& image_id = get_if_there(src->mTEMap, te, LLVOAvatar::getDefaultTEImageID((ETextureIndex) te ) ); - mTEMap[te] = image_id; + te_map_t::const_iterator iter = mTEMap.find(te); + LLUUID image_id; + if(iter != mTEMap.end()) + { + image_id = iter->second.getID(); + } + else + { + image_id = LLVOAvatarDictionary::getDefaultTextureImageID((ETextureIndex) te); + } + mTEMap[te] = LLLocalTextureObject(NULL, NULL, NULL, image_id); } } } +void LLWearable::setItemID(const LLUUID& item_id) +{ + mItemID = item_id; +} + +const LLUUID& LLWearable::getItemID() const +{ + return mItemID; +} + +LLLocalTextureObject* LLWearable::getLocalTextureObject(S32 index) const +{ + te_map_t::const_iterator iter = mTEMap.find(index); + if( iter != mTEMap.end() ) + { + return (LLLocalTextureObject*) &iter->second; + } + return NULL; +} + +void LLWearable::setLocalTextureObject(S32 index, LLLocalTextureObject *lto) +{ + if( lto ) + { + LLLocalTextureObject obj(*lto); + mTEMap[index] = obj; + } + else + { + mTEMap.erase(index); + } +} + struct LLWearableSaveData { EWearableType mType; }; -void LLWearable::saveNewAsset() +void LLWearable::saveNewAsset() const { // llinfos << "LLWearable::saveNewAsset() type: " << getTypeName() << llendl; //llinfos << *this << llendl; - std::string new_asset_id_string; - mAssetID.toString(new_asset_id_string); - std::string filename; - filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string) + ".wbl"; + const std::string filename = asset_id_to_filename(mAssetID); LLFILE* fp = LLFile::fopen(filename, "wb"); /* Flawfinder: ignore */ BOOL successful_save = FALSE; if(fp && exportFile(fp)) @@ -909,7 +861,7 @@ void LLWearable::saveNewAsset() void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userdata, S32 status, LLExtStat ext_status) // StoreAssetData callback (fixed) { LLWearableSaveData* data = (LLWearableSaveData*)userdata; - const std::string& type_name = LLWearable::typeToTypeName(data->mType); + const std::string& type_name = LLWearableDictionary::getTypeName(data->mType); if(0 == status) { // Success @@ -925,28 +877,16 @@ void LLWearable::onSaveNewAssetComplete(const LLUUID& new_asset_id, void* userda } // Delete temp file - std::string new_asset_id_string; - new_asset_id.toString(new_asset_id_string); - std::string src_filename; - src_filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,new_asset_id_string) + ".wbl"; + const std::string src_filename = asset_id_to_filename(new_asset_id); LLFile::remove(src_filename); // delete the context data delete data; } -BOOL LLWearable::isMatchedToInventoryItem( LLViewerInventoryItem* item ) -{ - return - ( mName == item->getName() ) && - ( mDescription == item->getDescription() ) && - ( mPermissions == item->getPermissions() ) && - ( mSaleInfo == item->getSaleInfo() ); -} - std::ostream& operator<<(std::ostream &s, const LLWearable &w) { - s << "wearable " << LLWearable::typeToTypeName( w.mType ) << "\n"; + s << "wearable " << LLWearableDictionary::getTypeName(w.mType) << "\n"; s << " Name: " << w.mName << "\n"; s << " Desc: " << w.mDescription << "\n"; //w.mPermissions @@ -966,10 +906,47 @@ std::ostream& operator<<(std::ostream &s, const LLWearable &w) iter != w.mTEMap.end(); ++iter) { S32 te = iter->first; - const LLUUID& image_id = iter->second; + const LLUUID& image_id = iter->second.getID(); s << " " << te << " " << image_id << "\n"; } return s; } +std::string terse_F32_to_string(F32 f) +{ + std::string r = llformat("%.2f", f); + S32 len = r.length(); + + // "1.20" -> "1.2" + // "24.00" -> "24." + while (len > 0 && ('0' == r[len - 1])) + { + r.erase(len-1, 1); + len--; + } + if ('.' == r[len - 1]) + { + // "24." -> "24" + r.erase(len-1, 1); + } + else if (('-' == r[0]) && ('0' == r[1])) + { + // "-0.59" -> "-.59" + r.erase(1, 1); + } + else if ('0' == r[0]) + { + // "0.59" -> ".59" + r.erase(0, 1); + } + return r; +} + +std::string asset_id_to_filename(const LLUUID &asset_id) +{ + std::string asset_id_string; + asset_id.toString(asset_id_string); + std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,asset_id_string) + ".wbl"; + return filename; +} diff --git a/indra/newview/llwearable.h b/indra/newview/llwearable.h index 683a8fa928..5f0b235c7f 100644 --- a/indra/newview/llwearable.h +++ b/indra/newview/llwearable.h @@ -19,7 +19,7 @@ * in the file doc/FLOSS-exception.txt in this software distribution, or * online at * http://secondlifegrid.net/programs/open_source/licensing/flossexception - * + * * By copying, modifying or distributing this software, you acknowledge * that you have read and understood your obligations described above, * and agree to abide by those obligations. @@ -38,92 +38,75 @@ #include "llpermissions.h" #include "llsaleinfo.h" #include "llassetstorage.h" +#include "llwearabledictionary.h" +#include "llfile.h" +#include "lllocaltextureobject.h" class LLViewerInventoryItem; -enum EWearableType // If you change this, update LLWearable::getTypeName(), getTypeLabel(), and LLVOAvatar::getTEWearableType() -{ - WT_SHAPE = 0, - WT_SKIN = 1, - WT_HAIR = 2, - WT_EYES = 3, - WT_SHIRT = 4, - WT_PANTS = 5, - WT_SHOES = 6, - WT_SOCKS = 7, - WT_JACKET = 8, - WT_GLOVES = 9, - WT_UNDERSHIRT = 10, - WT_UNDERPANTS = 11, - WT_SKIRT = 12, - WT_COUNT = 13, - WT_INVALID = 255 -}; - class LLWearable { friend class LLWearableList; + + //-------------------------------------------------------------------- + // Constructors and destructors + //-------------------------------------------------------------------- +private: + // Private constructors used by LLWearableList + LLWearable(const LLTransactionID& transactionID); + LLWearable(const LLAssetID& assetID); public: - ~LLWearable(); + virtual ~LLWearable(); - const LLAssetID& getID() const { return mAssetID; } + //-------------------------------------------------------------------- + // Accessors + //-------------------------------------------------------------------- +public: + const LLAssetID& getAssetID() const { return mAssetID; } const LLTransactionID& getTransactionID() const { return mTransactionID; } + EWearableType getType() const { return mType; } + void setType(EWearableType type) { mType = type; } + const std::string& getName() const { return mName; } + void setName(const std::string& name) { mName = name; } + const std::string& getDescription() const { return mDescription; } + void setDescription(const std::string& desc) { mDescription = desc; } + const LLPermissions& getPermissions() const { return mPermissions; } + void setPermissions(const LLPermissions& p) { mPermissions = p; } + const LLSaleInfo& getSaleInfo() const { return mSaleInfo; } + void setSaleInfo(const LLSaleInfo& info) { mSaleInfo = info; } + const std::string& getTypeLabel() const; + const std::string& getTypeName() const; + LLAssetType::EType getAssetType() const; - BOOL isDirty(); - BOOL isOldVersion(); +public: + BOOL isDirty() const; + BOOL isOldVersion() const; void writeToAvatar( BOOL set_by_user ); void readFromAvatar(); void removeFromAvatar( BOOL set_by_user ) { LLWearable::removeFromAvatar( mType, set_by_user ); } static void removeFromAvatar( EWearableType type, BOOL set_by_user ); - BOOL exportFile(LLFILE* file); + BOOL exportFile(LLFILE* file) const; BOOL importFile(LLFILE* file); - - EWearableType getType() const { return mType; } - void setType( EWearableType type ) { mType = type; } - - void setName( const std::string& name ) { mName = name; } - const std::string& getName() const { return mName; } - - void setDescription( const std::string& desc ) { mDescription = desc; } - const std::string& getDescription() const { return mDescription; } - - void setPermissions( const LLPermissions& p ) { mPermissions = p; } - const LLPermissions& getPermissions() const { return mPermissions; } - - void setSaleInfo( const LLSaleInfo& info ) { mSaleInfo = info; } - const LLSaleInfo& getSaleInfo() const { return mSaleInfo; } - - const std::string& getTypeLabel() const { return LLWearable::sTypeLabel[ mType ]; } - const std::string& getTypeName() const { return LLWearable::sTypeName[ mType ]; } - + void setParamsToDefaults(); void setTexturesToDefaults(); - LLAssetType::EType getAssetType() const { return LLWearable::typeToAssetType( mType ); } - - static EWearableType typeNameToType( const std::string& type_name ); - static const std::string& typeToTypeName( EWearableType type ) { return LLWearable::sTypeName[llmin(type,WT_COUNT)]; } - static const std::string& typeToTypeLabel( EWearableType type ) { return LLWearable::sTypeLabel[llmin(type,WT_COUNT)]; } - static LLAssetType::EType typeToAssetType( EWearableType wearable_type ); - - void saveNewAsset(); + void saveNewAsset() const; static void onSaveNewAssetComplete( const LLUUID& asset_uuid, void* user_data, S32 status, LLExtStat ext_status ); - BOOL isMatchedToInventoryItem( LLViewerInventoryItem* item ); - - void copyDataFrom( LLWearable* src ); + void copyDataFrom(const LLWearable* src); static void setCurrentDefinitionVersion( S32 version ) { LLWearable::sCurrentDefinitionVersion = version; } friend std::ostream& operator<<(std::ostream &s, const LLWearable &w); + void setItemID(const LLUUID& item_id); + const LLUUID& getItemID() const; + LLLocalTextureObject* getLocalTextureObject(S32 index) const; + void setLocalTextureObject(S32 index, LLLocalTextureObject *lto); private: - // Private constructor used by LLWearableList - LLWearable(const LLTransactionID& transactionID); - LLWearable(const LLAssetID& assetID); - static S32 sCurrentDefinitionVersion; // Depends on the current state of the avatar_lad.xml. S32 mDefinitionVersion; // Depends on the state of the avatar_lad.xml when this asset was created. std::string mName; @@ -136,11 +119,9 @@ private: typedef std::map param_map_t; param_map_t mVisualParamMap; // maps visual param id to weight - typedef std::map te_map_t; - te_map_t mTEMap; // maps TE to Image ID - - static const std::string sTypeName[ WT_COUNT+1 ]; - static const std::string sTypeLabel[ WT_COUNT+1 ]; + typedef std::map te_map_t; + te_map_t mTEMap; // maps TE to LocalTextureObject + LLUUID mItemID; // ID of the inventory item in the agent's inventory }; #endif // LL_LLWEARABLE_H diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp index 512c03fa4d..1275312676 100644 --- a/indra/newview/llwearablelist.cpp +++ b/indra/newview/llwearablelist.cpp @@ -39,22 +39,18 @@ #include "llagent.h" #include "llvoavatar.h" #include "llviewerinventory.h" -//#include "llfloaterchat.h" #include "llviewerstats.h" #include "llnotify.h" +#include "llinventorymodel.h" +#include "lltrans.h" -// Globals -LLWearableList gWearableList; // Globally constructed; be careful that there's no dependency with gAgent. - - +// Callback struct struct LLWearableArrivedData { - LLWearableArrivedData( - LLAssetType::EType asset_type, + LLWearableArrivedData(LLAssetType::EType asset_type, const std::string& wearable_name, void(*asset_arrived_callback)(LLWearable*, void* userdata), - void* userdata ) - : + void* userdata) : mAssetType( asset_type ), mCallback( asset_arrived_callback ), mUserdata( userdata ), @@ -69,8 +65,6 @@ struct LLWearableArrivedData S32 mRetries; }; - - //////////////////////////////////////////////////////////////////////////// // LLWearableList @@ -80,8 +74,21 @@ LLWearableList::~LLWearableList() mList.clear(); } -void LLWearableList::getAsset( const LLAssetID& assetID, const std::string& wearable_name, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLWearable*, void* userdata), void* userdata ) +void LLWearableList::getAsset(const LLAssetID& _assetID, const std::string& wearable_name, LLAssetType::EType asset_type, void(*asset_arrived_callback)(LLWearable*, void* userdata), void* userdata) { + LLAssetID assetID = _assetID; + + // A bit of a hack since wearables database doesn't contain asset types... + // Perform indirection in case this assetID is in fact a link. This only works + // because of the assumption that all assetIDs and itemIDs are unique (i.e. + // no assetID is also used as an itemID elsewhere); therefore if the assetID + // exists as an itemID in the user's inventory, then this must be a link. + const LLInventoryItem *linked_item = gInventory.getItem(_assetID); + if (linked_item) + { + assetID = linked_item->getAssetUUID(); + asset_type = linked_item->getType(); + } llassert( (asset_type == LLAssetType::AT_CLOTHING) || (asset_type == LLAssetType::AT_BODYPART) ); LLWearable* instance = get_if_there(mList, assetID, (LLWearable*)NULL ); if( instance ) @@ -90,8 +97,7 @@ void LLWearableList::getAsset( const LLAssetID& assetID, const std::string& wear } else { - gAssetStorage->getAssetData( - assetID, + gAssetStorage->getAssetData(assetID, asset_type, LLWearableList::processGetAssetReply, (void*)new LLWearableArrivedData( asset_type, wearable_name, asset_arrived_callback, userdata ), @@ -110,8 +116,7 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID { LL_WARNS("Wearable") << "Bad Wearable Asset: missing file." << LL_ENDL; } - else - if( status >= 0 ) + else if (status >= 0) { // read the file LLFILE* fp = LLFile::fopen(std::string(filename), "rb"); /*Flawfinder: ignore*/ @@ -180,15 +185,14 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID if (wearable) // success { - gWearableList.mList[ uuid ] = wearable; + LLWearableList::instance().mList[ uuid ] = wearable; LL_DEBUGS("Wearable") << "processGetAssetReply()" << LL_ENDL; LL_DEBUGS("Wearable") << wearable << LL_ENDL; } else { LLSD args; - // *TODO:translate - args["TYPE"] = LLAssetType::lookupHumanReadable(data->mAssetType); + args["TYPE"] =LLTrans::getString(LLAssetType::lookupHumanReadable(data->mAssetType)); if (isNewWearable) { LLNotifications::instance().add("InvalidWearable"); @@ -214,42 +218,13 @@ void LLWearableList::processGetAssetReply( const char* filename, const LLAssetID } -// Creates a new wearable just like the old_wearable but with data copied over from item -LLWearable* LLWearableList::createWearableMatchedToInventoryItem( LLWearable* old_wearable, LLViewerInventoryItem* item ) -{ - lldebugs << "LLWearableList::createWearableMatchedToInventoryItem()" << llendl; - - LLTransactionID tid; - LLAssetID new_asset_id; - new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - LLWearable* wearable = new LLWearable( tid ); - wearable->copyDataFrom( old_wearable ); - - wearable->setName( item->getName() ); - wearable->setDescription( item->getDescription() ); - wearable->setPermissions( item->getPermissions() ); - wearable->setSaleInfo( item->getSaleInfo() ); - - mList[ new_asset_id ] = wearable; - - // Send to the dataserver - wearable->saveNewAsset(); - - return wearable; -} - -LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name ) +LLWearable* LLWearableList::createCopyFromAvatar(const LLWearable* old_wearable, const std::string& new_name) { lldebugs << "LLWearableList::createCopyFromAvatar()" << llendl; - LLTransactionID tid; - LLAssetID new_asset_id; - tid.generate(); - new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - LLWearable* wearable = new LLWearable( tid ); + LLWearable *wearable = generateNewWearable(); wearable->copyDataFrom( old_wearable ); + LLPermissions perm(old_wearable->getPermissions()); perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true); wearable->setPermissions(perm); @@ -257,8 +232,6 @@ LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, cons if (!new_name.empty()) wearable->setName(new_name); - mList[ new_asset_id ] = wearable; - // Send to the dataserver wearable->saveNewAsset(); @@ -266,21 +239,16 @@ LLWearable* LLWearableList::createCopyFromAvatar( LLWearable* old_wearable, cons } -LLWearable* LLWearableList::createCopy( LLWearable* old_wearable ) +LLWearable* LLWearableList::createCopy(const LLWearable* old_wearable) { lldebugs << "LLWearableList::createCopy()" << llendl; - LLTransactionID tid; - LLAssetID new_asset_id; - tid.generate(); - new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + LLWearable *wearable = generateNewWearable(); + wearable->copyDataFrom(old_wearable); - LLWearable* wearable = new LLWearable( tid ); - wearable->copyDataFrom( old_wearable ); LLPermissions perm(old_wearable->getPermissions()); perm.setOwnerAndGroup(LLUUID::null, gAgent.getID(), LLUUID::null, true); wearable->setPermissions(perm); - mList[ new_asset_id ] = wearable; // Send to the dataserver wearable->saveNewAsset(); @@ -292,12 +260,7 @@ LLWearable* LLWearableList::createNewWearable( EWearableType type ) { lldebugs << "LLWearableList::createNewWearable()" << llendl; - LLTransactionID tid; - LLAssetID new_asset_id; - tid.generate(); - new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); - - LLWearable* wearable = new LLWearable( tid ); + LLWearable *wearable = generateNewWearable(); wearable->setType( type ); std::string name = "New "; @@ -314,10 +277,19 @@ LLWearable* LLWearableList::createNewWearable( EWearableType type ) wearable->setParamsToDefaults(); wearable->setTexturesToDefaults(); - mList[ new_asset_id ] = wearable; - // Send to the dataserver wearable->saveNewAsset(); return wearable; } + +LLWearable *LLWearableList::generateNewWearable() +{ + LLTransactionID tid; + tid.generate(); + LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID()); + + LLWearable* wearable = new LLWearable(tid); + mList[new_asset_id] = wearable; + return wearable; +} diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h index cda0cb11f9..f844c0f443 100644 --- a/indra/newview/llwearablelist.h +++ b/indra/newview/llwearablelist.h @@ -33,37 +33,37 @@ #ifndef LL_LLWEARABLELIST_H #define LL_LLWEARABLELIST_H +#include "llmemory.h" #include "llwearable.h" #include "lluuid.h" #include "llassetstorage.h" -class LLWearableList +// Globally constructed; be careful that there's no dependency with gAgent. +class LLWearableList : public LLSingleton { public: LLWearableList() {} ~LLWearableList(); - S32 getLength() { return mList.size(); } + S32 getLength() const { return mList.size(); } - void getAsset( - const LLAssetID& assetID, - const std::string& wearable_name, - LLAssetType::EType asset_type, - void(*asset_arrived_callback)(LLWearable*, void* userdata), - void* userdata ); + void getAsset(const LLAssetID& assetID, + const std::string& wearable_name, + LLAssetType::EType asset_type, + void(*asset_arrived_callback)(LLWearable*, void* userdata), + void* userdata); - LLWearable* createWearableMatchedToInventoryItem( LLWearable* old_wearable, LLViewerInventoryItem* item ); - LLWearable* createCopyFromAvatar( LLWearable* old_wearable, const std::string& new_name = std::string() ); - LLWearable* createCopy( LLWearable* old_wearable ); - LLWearable* createNewWearable( EWearableType type ); + LLWearable* createCopyFromAvatar(const LLWearable* old_wearable, const std::string& new_name = std::string()); + LLWearable* createCopy(const LLWearable* old_wearable); + LLWearable* createNewWearable(EWearableType type); // Callback static void processGetAssetReply(const char* filename, const LLAssetID& assetID, void* user_data, S32 status, LLExtStat ext_status); protected: - std::map< LLUUID, LLWearable* > mList; + LLWearable* generateNewWearable(); // used for the create... functions +private: + std::map mList; }; -extern LLWearableList gWearableList; - #endif // LL_LLWEARABLELIST_H diff --git a/indra/newview/llweb.cpp b/indra/newview/llweb.cpp index a5691d8a1c..300a5db7c3 100644 --- a/indra/newview/llweb.cpp +++ b/indra/newview/llweb.cpp @@ -35,10 +35,31 @@ #include "llweb.h" -#include "llviewerwindow.h" +// Library includes +#include "llwindow.h" // spawnWebBrowser() +#include "llviewerwindow.h" #include "llviewercontrol.h" -#include "llfloaterhtmlhelp.h" +#include "llfloatermediabrowser.h" +#include "llfloaterreg.h" +#include "llalertdialog.h" + +class URLLoader : public LLAlertDialog::URLLoader +{ + virtual void load(const std::string& url , bool force_open_externally) + { + if (force_open_externally) + { + LLWeb::loadURLExternal(url); + } + else + { + LLWeb::loadURL(url); + } + } +}; +static URLLoader sAlertURLLoader; + // static void LLWeb::initClass() @@ -55,7 +76,7 @@ void LLWeb::loadURL(const std::string& url) } else { - LLFloaterMediaBrowser::showInstance(url); + LLFloaterReg::showInstance("media_browser",url); } } @@ -93,12 +114,3 @@ std::string LLWeb::escapeURL(const std::string& url) } return escaped_url; } - -// virtual -void LLWeb::URLLoader::load(const std::string& url) -{ - loadURL(url); -} - -// static -LLWeb::URLLoader LLWeb::sAlertURLLoader; diff --git a/indra/newview/llweb.h b/indra/newview/llweb.h index 278821bac5..71cc236621 100644 --- a/indra/newview/llweb.h +++ b/indra/newview/llweb.h @@ -35,7 +35,6 @@ #define LL_LLWEB_H #include -#include "llalertdialog.h" class LLWeb { @@ -54,12 +53,6 @@ public: // Returns escaped (eg, " " to "%20") url static std::string escapeURL(const std::string& url); - class URLLoader : public LLAlertDialog::URLLoader - { - virtual void load(const std::string& url); - }; - - static URLLoader sAlertURLLoader; }; #endif diff --git a/indra/newview/llwind.cpp b/indra/newview/llwind.cpp index ae98bead98..cbee4ddae1 100644 --- a/indra/newview/llwind.cpp +++ b/indra/newview/llwind.cpp @@ -49,7 +49,6 @@ // viewer #include "noise.h" #include "v4color.h" -#include "llagent.h" #include "llworld.h" diff --git a/indra/newview/llwldaycycle.cpp b/indra/newview/llwldaycycle.cpp index 1d17c6047f..10a9703d1a 100644 --- a/indra/newview/llwldaycycle.cpp +++ b/indra/newview/llwldaycycle.cpp @@ -35,8 +35,7 @@ #include "llwldaycycle.h" #include "llsdserialize.h" #include "llwlparammanager.h" - -#include "llviewerwindow.h" +#include "llnotifications.h" #include diff --git a/indra/newview/llwldaycycle.h b/indra/newview/llwldaycycle.h index f045a6d1b0..eed6a78c18 100644 --- a/indra/newview/llwldaycycle.h +++ b/indra/newview/llwldaycycle.h @@ -35,8 +35,6 @@ class LLWLDayCycle; -#include "llfloater.h" - #include #include #include diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index b8a2bf0bd2..7d9d0a6191 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -37,6 +37,7 @@ #include "pipeline.h" #include "llsky.h" +#include "llfloaterreg.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" @@ -51,7 +52,6 @@ #include "llviewercontrol.h" #include "llviewerwindow.h" #include "lldrawpoolwater.h" -#include "llagent.h" #include "llviewerregion.h" #include "llwlparamset.h" @@ -63,6 +63,7 @@ #include "curl/curl.h" LLWLParamManager * LLWLParamManager::sInstance = NULL; +static LLFastTimer::DeclareTimer FTM_UPDATE_WLPARAM("Update Windlight Params"); LLWLParamManager::LLWLParamManager() : @@ -291,7 +292,7 @@ void LLWLParamManager::updateShaderUniforms(LLGLSLShader * shader) void LLWLParamManager::propagateParameters(void) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); LLVector4 sunDir; LLVector4 moonDir; @@ -362,7 +363,7 @@ void LLWLParamManager::propagateParameters(void) void LLWLParamManager::update(LLViewerCamera * cam) { - LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM); + LLFastTimer ftm(FTM_UPDATE_WLPARAM); // update clouds, sun, and general mCurParams.updateCloudScrolling(); @@ -377,17 +378,20 @@ void LLWLParamManager::update(LLViewerCamera * cam) propagateParameters(); // sync menus if they exist - if(LLFloaterWindLight::isOpen()) + LLFloaterWindLight* wlfloater = LLFloaterReg::findTypedInstance("env_windlight"); + if (wlfloater) { - LLFloaterWindLight::instance()->syncMenu(); + wlfloater->syncMenu(); } - if(LLFloaterDayCycle::isOpen()) + LLFloaterDayCycle* dlfloater = LLFloaterReg::findTypedInstance("env_day_cycle"); + if (dlfloater) { - LLFloaterDayCycle::instance()->syncMenu(); + dlfloater->syncMenu(); } - if(LLFloaterEnvSettings::isOpen()) + LLFloaterEnvSettings* envfloater = LLFloaterReg::findTypedInstance("env_settings"); + if (envfloater) { - LLFloaterEnvSettings::instance()->syncMenu(); + envfloater->syncMenu(); } F32 camYaw = cam->getYaw(); diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 3fdef29540..5c6fc2cf21 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -46,8 +46,8 @@ #include "llregionhandle.h" #include "llsurface.h" #include "llviewercamera.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewernetwork.h" #include "llviewerobjectlist.h" #include "llviewerparceloverlay.h" @@ -109,8 +109,8 @@ LLWorld::LLWorld() : *(default_texture++) = MAX_WATER_COLOR.mV[2]; *(default_texture++) = MAX_WATER_COLOR.mV[3]; - mDefaultWaterTexturep = new LLViewerImage(raw, FALSE); - gGL.getTexUnit(0)->bind(mDefaultWaterTexturep.get()); + mDefaultWaterTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + gGL.getTexUnit(0)->bind(mDefaultWaterTexturep); mDefaultWaterTexturep->setAddressMode(LLTexUnit::TAM_CLAMP); } @@ -632,6 +632,7 @@ void LLWorld::updateVisibilities() void LLWorld::updateRegions(F32 max_update_time) { + LLMemType mt_ur(LLMemType::MTYPE_IDLE_UPDATE_REGIONS); LLTimer update_timer; BOOL did_one = FALSE; @@ -961,7 +962,7 @@ void LLWorld::shiftRegions(const LLVector3& offset) LLViewerPartSim::getInstance()->shift(offset); } -LLViewerImage* LLWorld::getDefaultWaterTexture() +LLViewerTexture* LLWorld::getDefaultWaterTexture() { return mDefaultWaterTexturep; } diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index ce83cbd97c..48025c700b 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -42,10 +42,10 @@ #include "llmath.h" #include "v3math.h" -#include "llmemory.h" +#include "llsingleton.h" #include "llstring.h" #include "llviewerpartsim.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llvowater.h" class LLViewerRegion; @@ -141,7 +141,7 @@ public: F32 getLandFarClip() const; void setLandFarClip(const F32 far_clip); - LLViewerImage *getDefaultWaterTexture(); + LLViewerTexture *getDefaultWaterTexture(); void updateWaterObjects(); void shiftRegions(const LLVector3& offset); @@ -192,7 +192,7 @@ private: std::list mHoleWaterObjects; LLPointer mEdgeWaterObjects[8]; - LLPointer mDefaultWaterTexturep; + LLPointer mDefaultWaterTexturep; }; diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 572f31f566..700971dcc4 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -43,9 +43,10 @@ #include "llviewercontrol.h" #include "llfloaterworldmap.h" #include "lltracker.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerregion.h" #include "llregionflags.h" +#include "lltrans.h" const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes @@ -518,9 +519,9 @@ void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) LLWorldMapLayer new_layer; new_layer.LayerDefined = TRUE; msg->getUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block); - new_layer.LayerImage = gImageList.getImage(new_layer.LayerImageID, MIPMAP_TRUE, FALSE); + new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); - gGL.getTexUnit(0)->bind(new_layer.LayerImage.get()); + gGL.getTexUnit(0)->bind(new_layer.LayerImage); new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP); U32 left, right, top, bottom; @@ -633,15 +634,15 @@ void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) siminfo->mMapImageID[agent_flags] = image_id; #ifdef IMMEDIATE_IMAGE_LOAD - siminfo->mCurrentImage = gImageList.getImage(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE); - gGL.getTexUnit(0)->bind(siminfo->mCurrentImage.get()); + siminfo->mCurrentImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); + gGL.getTexUnit(0)->bind(siminfo->mCurrentImage); siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP); #endif if (siminfo->mMapImageID[2].notNull()) { #ifdef IMMEDIATE_IMAGE_LOAD - siminfo->mOverlayImage = gImageList.getImage(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE); + siminfo->mOverlayImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); #endif } else @@ -757,18 +758,13 @@ void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**) case MAP_ITEM_MATURE_EVENT: case MAP_ITEM_ADULT_EVENT: { - struct tm* timep; - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - timep = utc_to_pacific_time(extra, gPacificDaylightTime); - - S32 display_hour = timep->tm_hour % 12; - if (display_hour == 0) display_hour = 12; - - new_item.mToolTip = llformat( "%d:%02d %s", - display_hour, - timep->tm_min, - (timep->tm_hour < 12 ? "AM" : "PM") ); + std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:[" + +LLTrans::getString ("TimeMin")+"] [" + +LLTrans::getString ("TimeAMPM")+"]"; + LLSD substitution; + substitution["datetime"] = (S32) extra; + LLStringUtil::format (timeStr, substitution); + new_item.mToolTip = timeStr; // HACK: store Z in extra2 new_item.mPosGlobal.mdV[VZ] = (F64)extra2; @@ -866,10 +862,10 @@ void LLWorldMap::dump() if (info->mCurrentImage) { llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel() - << " fullwidth " << info->mCurrentImage->getWidth(0) - << " fullheight " << info->mCurrentImage->getHeight(0) - << " maxvirt " << info->mCurrentImage->mMaxVirtualSize - << " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel() + << " fullwidth " << info->mCurrentImage->getFullWidth() + << " fullheight " << info->mCurrentImage->getFullHeight() + << " maxvirt " << info->mCurrentImage->getMaxVirtualSize() + //<< " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel() << llendl; } } diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index bb3c97cfd9..9daee38752 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -36,14 +36,16 @@ #include #include #include +#include #include "v3math.h" #include "v3dmath.h" #include "llframetimer.h" #include "llmapimagetype.h" #include "lluuid.h" -#include "llmemory.h" -#include "llviewerimage.h" +#include "llpointer.h" +#include "llsingleton.h" +#include "llviewertexture.h" #include "lleventinfo.h" #include "v3color.h" @@ -94,8 +96,8 @@ public: LLUUID mMapImageID[MAP_SIM_IMAGE_TYPES]; // Hold a reference to the currently displayed image. - LLPointer mCurrentImage; - LLPointer mOverlayImage; + LLPointer mCurrentImage; + LLPointer mOverlayImage; }; #define MAP_BLOCK_RES 256 @@ -103,7 +105,7 @@ public: struct LLWorldMapLayer { BOOL LayerDefined; - LLPointer LayerImage; + LLPointer LayerImage; LLUUID LayerImageID; LLRect LayerExtents; @@ -114,7 +116,8 @@ struct LLWorldMapLayer class LLWorldMap : public LLSingleton { public: - typedef void(*url_callback_t)(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport); + typedef boost::function + url_callback_t; LLWorldMap(); ~LLWorldMap(); diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 2e18b710a7..67bc205f62 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -39,11 +39,11 @@ #include "llmath.h" // clampf() #include "llregionhandle.h" #include "lleventflags.h" +#include "llfloaterreg.h" #include "llrender.h" #include "llagent.h" #include "llcallingcard.h" -#include "llcolorscheme.h" #include "llviewercontrol.h" #include "llcylinder.h" #include "llfloaterdirectory.h" @@ -54,8 +54,8 @@ #include "lltextureview.h" #include "lltracker.h" #include "llviewercamera.h" -#include "llviewerimage.h" -#include "llviewerimagelist.h" +#include "llviewertexture.h" +#include "llviewertexturelist.h" #include "llviewermenu.h" #include "llviewerparceloverlay.h" #include "llviewerregion.h" @@ -164,8 +164,8 @@ void LLWorldMapView::cleanupClass() sForSaleAdultImage = NULL; } -LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) -: LLPanel(name, rect, BORDER_NO), +LLWorldMapView::LLWorldMapView() +: LLPanel(), mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ), mItemPicked(FALSE), mPanning( FALSE ), @@ -177,47 +177,38 @@ LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) { sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS; clearLastClick(); +} - const S32 DIR_WIDTH = 10; - const S32 DIR_HEIGHT = 10; - LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 ); - LLColor4 minor_color( 1.f, 1.f, 1.f, .7f ); - - mTextBoxNorth = new LLTextBox( std::string("N"), major_dir_rect ); - mTextBoxNorth->setColor( minor_color ); - addChild( mTextBoxNorth ); +BOOL LLWorldMapView::postBuild() +{ + mTextBoxNorth = getChild ("floater_map_north"); + mTextBoxEast = getChild ("floater_map_east"); + mTextBoxWest = getChild ("floater_map_west"); + mTextBoxSouth = getChild ("floater_map_south"); + mTextBoxSouthEast = getChild ("floater_map_southeast"); + mTextBoxNorthEast = getChild ("floater_map_northeast"); + mTextBoxSouthWest = getChild ("floater_map_southwest"); + mTextBoxNorthWest = getChild ("floater_map_northwest"); - mTextBoxEast = new LLTextBox( std::string("E"), major_dir_rect ); - mTextBoxEast->setColor( minor_color ); - addChild( mTextBoxEast ); + mTextBoxNorth->setText(getString("world_map_north")); + mTextBoxEast->setText(getString ("world_map_east")); + mTextBoxWest->setText(getString("world_map_west")); + mTextBoxSouth->setText(getString ("world_map_south")); + mTextBoxSouthEast ->setText(getString ("world_map_southeast")); + mTextBoxNorthEast ->setText(getString ("world_map_northeast")); + mTextBoxSouthWest->setText(getString ("world_map_southwest")); + mTextBoxNorthWest ->setText(getString("world_map_northwest")); - major_dir_rect.mRight += 1 ; - mTextBoxWest = new LLTextBox( std::string("W"), major_dir_rect ); - mTextBoxWest->setColor( minor_color ); - addChild( mTextBoxWest ); - major_dir_rect.mRight -= 1 ; + mTextBoxNorth->reshapeToFitText(); + mTextBoxEast->reshapeToFitText(); + mTextBoxWest->reshapeToFitText(); + mTextBoxSouth->reshapeToFitText(); + mTextBoxSouthEast ->reshapeToFitText(); + mTextBoxNorthEast ->reshapeToFitText(); + mTextBoxSouthWest->reshapeToFitText(); + mTextBoxNorthWest ->reshapeToFitText(); - mTextBoxSouth = new LLTextBox( std::string("S"), major_dir_rect ); - mTextBoxSouth->setColor( minor_color ); - addChild( mTextBoxSouth ); - - LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 ); - - mTextBoxSouthEast = new LLTextBox( std::string("SE"), minor_dir_rect ); - mTextBoxSouthEast->setColor( minor_color ); - addChild( mTextBoxSouthEast ); - - mTextBoxNorthEast = new LLTextBox( std::string("NE"), minor_dir_rect ); - mTextBoxNorthEast->setColor( minor_color ); - addChild( mTextBoxNorthEast ); - - mTextBoxSouthWest = new LLTextBox( std::string("SW"), minor_dir_rect ); - mTextBoxSouthWest->setColor( minor_color ); - addChild( mTextBoxSouthWest ); - - mTextBoxNorthWest = new LLTextBox( std::string("NW"), minor_dir_rect ); - mTextBoxNorthWest->setColor( minor_color ); - addChild( mTextBoxNorthWest ); + return true; } @@ -293,6 +284,8 @@ BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info) void LLWorldMapView::draw() { + static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white); + LLTextureView::clearDebugImages(); F64 current_time = LLTimer::getElapsedSeconds(); @@ -339,7 +332,7 @@ void LLWorldMapView::draw() continue; } LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx]; - LLViewerImage *current_image = layer->LayerImage; + LLViewerFetchedTexture *current_image = layer->LayerImage; if (current_image->isMissingAsset()) { @@ -374,10 +367,10 @@ void LLWorldMapView::draw() continue; } - current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER); + current_image->setBoostLevel(LLViewerTexture::BOOST_MAP_LAYER); current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY])); - if (!current_image->getHasGLTexture()) + if (!current_image->hasValidGLTexture()) { continue; // better to draw nothing than the default image } @@ -441,8 +434,8 @@ void LLWorldMapView::draw() U64 handle = (*it).first; LLSimInfo* info = (*it).second; - LLViewerImage* simimage = info->mCurrentImage; - LLViewerImage* overlayimage = info->mOverlayImage; + LLViewerFetchedTexture* simimage = info->mCurrentImage; + LLViewerFetchedTexture* overlayimage = info->mOverlayImage; if (gMapScale < SIM_MAP_SCALE) { @@ -479,7 +472,7 @@ void LLWorldMapView::draw() bool sim_visible = (gMapScale >= map_scale_cutoff) && (simimage != NULL) && - (simimage->getHasGLTexture()); + (simimage->hasValidGLTexture()); if (sim_visible) { @@ -517,7 +510,7 @@ void LLWorldMapView::draw() (textures_requested_this_tick < MAX_REQUEST_PER_TICK))) { textures_requested_this_tick++; - info->mCurrentImage = gImageList.getImage(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE); + info->mCurrentImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); info->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP); simimage = info->mCurrentImage; gGL.getTexUnit(0)->bind(simimage); @@ -530,7 +523,7 @@ void LLWorldMapView::draw() (textures_requested_this_tick < MAX_REQUEST_PER_TICK))) { textures_requested_this_tick++; - info->mOverlayImage = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE); + info->mOverlayImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); info->mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP); overlayimage = info->mOverlayImage; gGL.getTexUnit(0)->bind(overlayimage); @@ -553,13 +546,13 @@ void LLWorldMapView::draw() S32 draw_size = llround(gMapScale); if (simimage != NULL) { - simimage->setBoostLevel(LLViewerImage::BOOST_MAP); + simimage->setBoostLevel(LLViewerTexture::BOOST_MAP); simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); } if (overlayimage != NULL) { - overlayimage->setBoostLevel(LLViewerImage::BOOST_MAP); + overlayimage->setBoostLevel(LLViewerTexture::BOOST_MAP); overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); } @@ -588,7 +581,7 @@ void LLWorldMapView::draw() gGL.vertex3f(right, top, 0.f); gGL.end(); - if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->getHasGLTexture()) + if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasValidGLTexture()) { gGL.getTexUnit(0)->bind(overlayimage); gGL.color4f(1.f, 1.f, 1.f, alpha); @@ -698,6 +691,7 @@ void LLWorldMapView::draw() LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); // If map texture is still loading, @@ -713,6 +707,7 @@ void LLWorldMapView::draw() LLColor4::white, LLFontGL::LEFT, LLFontGL::BASELINE, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } } @@ -801,7 +796,7 @@ void LLWorldMapView::draw() LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus(); if ( LLTracker::TRACKING_AVATAR == tracking_status ) { - drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor, TRUE, LLTracker::getLabel(), "" ); + drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color, TRUE, LLTracker::getLabel(), "" ); } else if ( LLTracker::TRACKING_LANDMARK == tracking_status || LLTracker::TRACKING_LOCATION == tracking_status ) @@ -811,7 +806,7 @@ void LLWorldMapView::draw() LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); if (!pos_global.isExactlyZero()) { - drawTracking( pos_global, gTrackColor, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() ); + drawTracking( pos_global, map_track_color, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() ); } } else if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation) @@ -820,14 +815,14 @@ void LLWorldMapView::draw() { // We know this location to be invalid LLColor4 loading_color(0.0, 0.5, 1.0, 1.0); - drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, "Invalid Location", ""); + drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("InvalidLocation"), ""); } else { double value = fmod(current_time, 2); value = 0.5 + 0.5*cos(value * 3.14159f); LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0); - drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, "Loading...", ""); + drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("Loading"), ""); } } // #endif used to be here @@ -913,10 +908,10 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i void LLWorldMapView::drawAgents() { - F32 agents_scale = (gMapScale * 0.9f) / 256.f; + static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); + static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white); - LLColor4 avatar_color = gColors.getColor( "MapAvatar" ); - // LLColor4 friend_color = gColors.getColor( "MapFriend" ); + F32 agents_scale = (gMapScale * 0.9f) / 256.f; for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) { @@ -939,8 +934,8 @@ void LLWorldMapView::drawAgents() S32 agent_count = info.mExtra; sim_agent_count += info.mExtra; // Here's how we'd choose the color if info.mID were available but it's not being sent: - //LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? friend_color : avatar_color; - drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, avatar_color); + //LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? map_avatar_friend_color : map_avatar_color; + drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, map_avatar_color); } LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim } @@ -955,7 +950,7 @@ void LLWorldMapView::drawAgents() region_center[VY] += REGION_WIDTH_METERS / 2; // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1; - drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, avatar_color); + drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, map_avatar_color); } } } @@ -1142,7 +1137,7 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x, text_y, LLColor4::white, LLFontGL::HCENTER, - LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); + LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); if (tooltip != "") { @@ -1153,7 +1148,7 @@ void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& text_x, text_y, LLColor4::white, LLFontGL::HCENTER, - LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); + LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } } } @@ -1233,12 +1228,11 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic msg += region_flags; } - S32 SLOP = 4; - localPointToScreen( - x - SLOP, y - SLOP, - &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) ); - sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP; - sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP; + const S32 SLOP = 9; + S32 screen_x, screen_y; + + localPointToScreen(x, y, &screen_x, &screen_y); + sticky_rect_screen->setCenterAndSize(screen_x, screen_y, SLOP, SLOP); } return TRUE; } @@ -1338,6 +1332,7 @@ void LLWorldMapView::drawIconName(F32 x_pixels, color, LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); text_y -= llround(LLFontGL::getFontSansSerif()->getLineHeight()); @@ -1349,6 +1344,7 @@ void LLWorldMapView::drawIconName(F32 x_pixels, color, LLFontGL::HCENTER, LLFontGL::TOP, + LLFontGL::NORMAL, LLFontGL::DROP_SHADOW); } @@ -1886,27 +1882,27 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) case MAP_ITEM_MATURE_EVENT: case MAP_ITEM_ADULT_EVENT: { - gFloaterWorldMap->close(); + LLFloaterReg::hideInstance("world_map"); // This is an ungainly hack std::string uuid_str; S32 event_id; id.toString(uuid_str); uuid_str = uuid_str.substr(28); sscanf(uuid_str.c_str(), "%X", &event_id); - LLFloaterDirectory::showEvents(event_id); + LLFloaterReg::showInstance("search", LLSD().insert("panel", "event").insert("id", event_id)); break; } case MAP_ITEM_LAND_FOR_SALE: case MAP_ITEM_LAND_FOR_SALE_ADULT: { - gFloaterWorldMap->close(); - LLFloaterDirectory::showLandForSale(id); + LLFloaterReg::hideInstance("world_map"); + LLFloaterReg::showInstance("search", LLSD().insert("panel", "land").insert("id", id)); break; } case MAP_ITEM_CLASSIFIED: { - gFloaterWorldMap->close(); - LLFloaterDirectory::showClassified(id); + LLFloaterReg::hideInstance("world_map"); + LLFloaterReg::showInstance("search", LLSD().insert("panel", "classified").insert("id", id)); break; } default: diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h index 1717b76beb..41c9772694 100644 --- a/indra/newview/llworldmapview.h +++ b/indra/newview/llworldmapview.h @@ -39,7 +39,7 @@ #include "v3math.h" #include "v3dmath.h" #include "v4color.h" -#include "llviewerimage.h" +#include "llviewertexture.h" #include "llmapimagetype.h" #include "llworldmap.h" @@ -50,7 +50,7 @@ const S32 DEFAULT_TRACKING_ARROW_SIZE = 16; class LLColor4; class LLColor4U; class LLCoordGL; -class LLViewerImage; +class LLViewerTexture; class LLTextBox; @@ -60,9 +60,11 @@ public: static void initClass(); static void cleanupClass(); - LLWorldMapView(const std::string& name, const LLRect& rect ); + LLWorldMapView(); virtual ~LLWorldMapView(); - + + virtual BOOL postBuild(); + virtual void reshape(S32 width, S32 height, BOOL called_from_parent = TRUE ); virtual void setVisible(BOOL visible); diff --git a/indra/newview/macview_Prefix.h b/indra/newview/macview_Prefix.h index 8cbabb5103..0fcdf2da4f 100644 --- a/indra/newview/macview_Prefix.h +++ b/indra/newview/macview_Prefix.h @@ -63,20 +63,17 @@ #include "lldrawable.h" #include "llfirstuse.h" #include "llfloater.h" -#include "llfloateravatarinfo.h" #include "llfloaterbuildoptions.h" #include "llfloaterchat.h" #include "llfloatercustomize.h" #include "llfloaterdirectory.h" #include "llfloatergroups.h" -#include "llfloatermap.h" #include "llfloaterworldmap.h" #include "llfloatermute.h" #include "llconversation.h" #include "llfloatertools.h" #include "llhudeffectlookat.h" #include "llhudmanager.h" -#include "llinventoryview.h" #include "lljoystickbutton.h" #include "llmenugl.h" #include "llmorphview.h" @@ -92,7 +89,6 @@ #include "lltoolgrab.h" #include "lltoolmgr.h" #include "lltoolpie.h" -#include "lltoolview.h" #include "llui.h" // for make_ui_sound #include "llviewercamera.h" #include "llviewermenu.h" diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index ebf2f91aa2..b0c3e8d711 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -35,15 +35,15 @@ #include "pipeline.h" // library includes -#include "audioengine.h" // For MAX_BUFFERS for debugging. +#include "llaudioengine.h" // For MAX_BUFFERS for debugging. #include "imageids.h" #include "llerror.h" #include "llviewercontrol.h" #include "llfasttimer.h" #include "llfontgl.h" -#include "llmemory.h" #include "llmemtype.h" #include "llnamevalue.h" +#include "llpointer.h" #include "llprimitive.h" #include "llvolume.h" #include "material_codes.h" @@ -52,6 +52,7 @@ #include "llui.h" #include "llglheaders.h" #include "llrender.h" +#include "llwindow.h" // swapBuffers() // newview includes #include "llagent.h" @@ -65,7 +66,7 @@ #include "llface.h" #include "llfeaturemanager.h" #include "llfloatertelehub.h" -#include "llframestats.h" +#include "llfloaterreg.h" #include "llgldbg.h" #include "llhudmanager.h" #include "lllightconstants.h" @@ -76,13 +77,13 @@ #include "lltool.h" #include "lltoolmgr.h" #include "llviewercamera.h" -#include "llviewerimagelist.h" +#include "llviewertexturelist.h" #include "llviewerobject.h" #include "llviewerobjectlist.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" // for audio debugging. #include "llviewerwindow.h" // For getSpinAxis -#include "llvoavatar.h" +#include "llvoavatarself.h" #include "llvoground.h" #include "llvosky.h" #include "llvotree.h" @@ -93,8 +94,8 @@ #include "llvopartgroup.h" #include "llworld.h" #include "llcubemap.h" -#include "lldebugmessagebox.h" #include "llviewershadermgr.h" +#include "llviewerstats.h" #include "llviewerjoystick.h" #include "llviewerdisplay.h" #include "llwlparammanager.h" @@ -121,8 +122,7 @@ const U32 REFLECTION_MAP_RES = 128; const S32 MAX_OCCLUDER_COUNT = 2; extern S32 gBoxFrame; -extern BOOL gRenderLightGlows; -extern BOOL gHideSelectedObjects; +//extern BOOL gHideSelectedObjects; extern BOOL gDisplaySwapBuffers; extern BOOL gDebugGL; @@ -138,6 +138,33 @@ BOOL gDebugPipeline = FALSE; LLPipeline gPipeline; const LLMatrix4* gGLLastMatrix = NULL; +LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry"); +LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass"); +LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible"); +LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion"); +LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny"); +LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple"); +LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain"); +LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees"); +LLFastTimer::DeclareTimer FTM_RENDER_UI("UI"); +LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water"); +LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky"); +LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects"); +LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars"); +LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump"); +LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright"); +LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow"); +LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update"); +LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool"); +LLFastTimer::DeclareTimer FTM_POOLS("Pools"); +LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO"); +LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State"); +LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline"); +LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy"); + +static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables"); +static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort"); + //---------------------------------------- std::string gPoolNames[] = { @@ -317,7 +344,7 @@ LLPipeline::LLPipeline() : void LLPipeline::init() { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT); sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD"); sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); @@ -337,7 +364,7 @@ void LLPipeline::init() getPool(LLDrawPool::POOL_BUMP); getPool(LLDrawPool::POOL_GLOW); - mTrianglesDrawnStat.reset(); + LLViewerStats::getInstance()->mTrianglesDrawnStat.reset(); resetFrameStats(); mRenderTypeMask = 0xffffffff; // All render types start on @@ -466,8 +493,8 @@ void LLPipeline::resizeScreenTexture() { if (gPipeline.canUseVertexShaders() && assertInitialized()) { - GLuint resX = gViewerWindow->getWindowDisplayWidth(); - GLuint resY = gViewerWindow->getWindowDisplayHeight(); + GLuint resX = gViewerWindow->getWorldViewWidth(); + GLuint resY = gViewerWindow->getWorldViewHeight(); U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor"); if (res_mod > 1 && res_mod < resX && res_mod < resY) @@ -577,6 +604,7 @@ void LLPipeline::releaseGLBuffers() void LLPipeline::createGLBuffers() { + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS); assertInitialized(); updateRenderDeferred(); @@ -592,6 +620,9 @@ void LLPipeline::createGLBuffers() stop_glerror(); + GLuint resX = gViewerWindow->getWorldViewWidth(); + GLuint resY = gViewerWindow->getWorldViewHeight(); + if (LLPipeline::sRenderGlow) { //screen space glow buffers const U32 glow_res = llmax(1, @@ -601,13 +632,10 @@ void LLPipeline::createGLBuffers() { mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE); } + + allocateScreenBuffer(resX,resY); } - - GLuint resX = gViewerWindow->getWindowDisplayWidth(); - GLuint resY = gViewerWindow->getWindowDisplayHeight(); - allocateScreenBuffer(resX,resY); - if (sRenderDeferred) { mSunShadow[0].allocate(1024,1024, 0, TRUE, FALSE); @@ -639,6 +667,7 @@ void LLPipeline::createGLBuffers() void LLPipeline::restoreGL() { + LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL); assertInitialized(); if (mVertexShadersEnabled) @@ -693,6 +722,7 @@ BOOL LLPipeline::canUseWindLightShadersOnObjects() const void LLPipeline::unloadShaders() { + LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS); LLViewerShaderMgr::instance()->unloadShaders(); mVertexShadersLoaded = 0; @@ -724,6 +754,7 @@ S32 LLPipeline::getMaxLightingDetail() const S32 LLPipeline::setLightingDetail(S32 level) { + LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL); assertInitialized(); if (level < 0) @@ -748,9 +779,9 @@ S32 LLPipeline::setLightingDetail(S32 level) class LLOctreeDirtyTexture : public LLOctreeTraveler { public: - const std::set& mTextures; + const std::set& mTextures; - LLOctreeDirtyTexture(const std::set& textures) : mTextures(textures) { } + LLOctreeDirtyTexture(const std::set& textures) : mTextures(textures) { } virtual void visit(const LLOctreeNode* node) { @@ -763,7 +794,8 @@ public: for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j) { LLDrawInfo* params = *j; - if (mTextures.find(params->mTexture) != mTextures.end()) + LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture); + if (tex && mTextures.find(tex) != mTextures.end()) { group->setState(LLSpatialGroup::GEOM_DIRTY); } @@ -780,7 +812,7 @@ public: }; // Called when a texture changes # of channels (causes faces to move to alpha pool) -void LLPipeline::dirtyPoolObjectTextures(const std::set& textures) +void LLPipeline::dirtyPoolObjectTextures(const std::set& textures) { assertInitialized(); @@ -812,7 +844,7 @@ void LLPipeline::dirtyPoolObjectTextures(const std::set& texture } } -LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0) +LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) { assertInitialized(); @@ -884,7 +916,7 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerImage *tex0) } -LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerImage *tex0) +LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0) { LLMemType mt(LLMemType::MTYPE_PIPELINE); LLDrawPool *poolp = findPool(type, tex0); @@ -901,7 +933,7 @@ LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerImage *tex0) // static -LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerImage* imagep) +LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) { LLMemType mt(LLMemType::MTYPE_PIPELINE); U32 type = getPoolTypeFromTE(te, imagep); @@ -909,9 +941,9 @@ LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerImage* i } //static -U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* imagep) +U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE); if (!te || !imagep) { @@ -921,7 +953,7 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* image bool alpha = te->getColor().mV[3] < 0.999f; if (imagep) { - alpha = alpha || (imagep->getComponents() == 4 && ! imagep->mIsMediaTexture) || (imagep->getComponents() == 2); + alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2); } if (alpha) @@ -941,7 +973,7 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* image void LLPipeline::addPool(LLDrawPool *new_poolp) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL); assertInitialized(); mPools.insert(new_poolp); addToQuickLookup( new_poolp ); @@ -949,7 +981,7 @@ void LLPipeline::addPool(LLDrawPool *new_poolp) void LLPipeline::allocDrawable(LLViewerObject *vobj) { - LLMemType mt(LLMemType::MTYPE_DRAWABLE); + LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE); LLDrawable *drawable = new LLDrawable(); vobj->mDrawable = drawable; @@ -968,7 +1000,7 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj) void LLPipeline::unlinkDrawable(LLDrawable *drawable) { - LLFastTimer t(LLFastTimer::FTM_PIPELINE); + LLFastTimer t(FTM_PIPELINE); assertInitialized(); @@ -1010,6 +1042,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable) U32 LLPipeline::addObject(LLViewerObject *vobj) { + LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT); if (gNoRender) { return 0; @@ -1029,8 +1062,8 @@ U32 LLPipeline::addObject(LLViewerObject *vobj) void LLPipeline::createObjects(F32 max_dtime) { - LLFastTimer ftm(LLFastTimer::FTM_GEO_UPDATE); - LLMemType mt(LLMemType::MTYPE_DRAWABLE); + LLFastTimer ftm(FTM_GEO_UPDATE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS); LLTimer update_timer; @@ -1093,7 +1126,7 @@ void LLPipeline::resetFrameStats() { assertInitialized(); - mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); + LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f); if (mBatchCount > 0) { @@ -1195,10 +1228,13 @@ void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list) } } +static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree"); +static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move"); + void LLPipeline::updateMove() { - LLFastTimer t(LLFastTimer::FTM_UPDATE_MOVE); - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer t(FTM_UPDATE_MOVE); + LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE); if (gSavedSettings.getBOOL("FreezeTime")) { @@ -1243,7 +1279,7 @@ void LLPipeline::updateMove() //balance octrees { - LLFastTimer ot(LLFastTimer::FTM_OCTREE_BALANCE); + LLFastTimer ot(FTM_OCTREE_BALANCE); for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); iter != LLWorld::getInstance()->getRegionList().end(); ++iter) @@ -1348,11 +1384,12 @@ BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& return res; } +static LLFastTimer::DeclareTimer FTM_CULL("Object Culling"); void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip) { - LLFastTimer t(LLFastTimer::FTM_CULL); - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer t(FTM_CULL); + LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL); grabReferences(result); @@ -1563,10 +1600,10 @@ BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority) void LLPipeline::updateGeom(F32 max_dtime) { LLTimer update_timer; - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM); LLPointer drawablep; - LLFastTimer t(LLFastTimer::FTM_GEO_UPDATE); + LLFastTimer t(FTM_GEO_UPDATE); assertInitialized(); @@ -1666,7 +1703,7 @@ void LLPipeline::updateGeom(F32 max_dtime) void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE); if(!drawablep || drawablep->isDead()) { return; @@ -1686,7 +1723,7 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera) void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED); if (!drawablep) { @@ -1732,7 +1769,7 @@ void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion) void LLPipeline::markShift(LLDrawable *drawablep) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT); if (!drawablep || drawablep->isDead()) { @@ -1755,7 +1792,7 @@ void LLPipeline::markShift(LLDrawable *drawablep) void LLPipeline::shiftObjects(const LLVector3 &offset) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS); assertInitialized(); @@ -1795,7 +1832,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset) void LLPipeline::markTextured(LLDrawable *drawablep) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED); if (drawablep && !drawablep->isDead() && assertInitialized()) { @@ -1805,7 +1842,7 @@ void LLPipeline::markTextured(LLDrawable *drawablep) void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD); if (drawablep && !drawablep->isDead() && assertInitialized()) { @@ -1834,6 +1871,8 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f } } +static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order"); + void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) { const U32 face_mask = (1 << LLPipeline::RENDER_TYPE_AVATAR) | @@ -1846,12 +1885,12 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) if (mRenderTypeMask & face_mask) { //clear faces from face pools - LLFastTimer t(LLFastTimer::FTM_RESET_DRAWORDER); + LLFastTimer t(FTM_RESET_DRAWORDER); gPipeline.resetDrawOrders(); } - LLFastTimer ftm(LLFastTimer::FTM_STATESORT); - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLFastTimer ftm(FTM_STATESORT); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); //LLVertexBuffer::unbind(); @@ -1906,7 +1945,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } { - LLFastTimer ftm(LLFastTimer::FTM_STATESORT_DRAWABLE); + LLFastTimer ftm(FTM_STATESORT_DRAWABLE); for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter) { @@ -1919,7 +1958,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) } { - LLFastTimer ftm(LLFastTimer::FTM_CLIENT_COPY); + LLFastTimer ftm(FTM_CLIENT_COPY); LLVertexBuffer::clientCopy(); } @@ -1928,7 +1967,7 @@ void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result) void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); if (!sSkipUpdate && group->changeLOD()) { for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i) @@ -1942,7 +1981,7 @@ void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera) void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); if (!sSkipUpdate && bridge->getSpatialGroup()->changeLOD()) { bool force_update = false; @@ -1952,7 +1991,7 @@ void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera) void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT); if (!drawablep || drawablep->isDead() @@ -1961,7 +2000,7 @@ void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera) return; } - if (gHideSelectedObjects) + if (LLSelectMgr::getInstance()->mHideSelectedObjects) { if (drawablep->getVObj().notNull() && drawablep->getVObj()->isSelected()) @@ -2181,8 +2220,8 @@ void renderSoundHighlights(LLDrawable* drawablep) void LLPipeline::postSort(LLCamera& camera) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLFastTimer ftm(LLFastTimer::FTM_STATESORT_POSTSORT); + LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT); + LLFastTimer ftm(FTM_STATESORT_POSTSORT); assertInitialized(); @@ -2294,7 +2333,7 @@ void LLPipeline::postSort(LLCamera& camera) } // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus - if (gSavedSettings.getBOOL("BeaconAlwaysOn") && !sShadowRender) + if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender) { if (sRenderScriptedTouchBeacons) { @@ -2375,7 +2414,8 @@ void LLPipeline::postSort(LLCamera& camera) void render_hud_elements() { - LLFastTimer t(LLFastTimer::FTM_RENDER_UI); + LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS); + LLFastTimer t(FTM_RENDER_UI); gPipeline.disableLights(); LLGLDisable fog(GL_FOG); @@ -2419,7 +2459,7 @@ void render_hud_elements() void LLPipeline::renderHighlights() { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL); assertInitialized(); @@ -2441,7 +2481,7 @@ void LLPipeline::renderHighlights() // Make sure the selection image gets downloaded and decoded if (!mFaceSelectImagep) { - mFaceSelectImagep = gImageList.getImage(IMG_FACE_SELECT); + mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT); } mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA); @@ -2471,7 +2511,7 @@ void LLPipeline::renderHighlights() for (S32 i = 0; i < count; i++) { LLFace* facep = mHighlightFaces[i]; - facep->renderSelected(LLViewerImage::sNullImagep, color); + facep->renderSelected(LLViewerTexture::sNullImagep, color); } } @@ -2487,8 +2527,8 @@ void LLPipeline::renderHighlights() void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); - LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY); + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM); + LLFastTimer t(FTM_RENDER_GEOMETRY); assertInitialized(); @@ -2512,7 +2552,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) // stop_glerror(); - gFrameStats.start(LLFrameStats::RENDER_SYNC); LLVertexBuffer::unbind(); @@ -2538,7 +2577,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) if(forceVBOUpdate) gSky.mVOSkyp->updateDummyVertexBuffer() ; - gFrameStats.start(LLFrameStats::RENDER_GEOM); // Initialize lots of GL state to "safe" values glMatrixMode(GL_TEXTURE); @@ -2562,8 +2600,8 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) sUnderWaterRender = FALSE; } - gGL.getTexUnit(0)->bind(LLViewerImage::sDefaultImagep); - LLViewerImage::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); + gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep); + LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP); ////////////////////////////////////////////// // @@ -2589,7 +2627,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) } else { - LLFastTimer t(LLFastTimer::FTM_POOLS); + LLFastTimer t(FTM_POOLS); // HACK: don't calculate local lights if we're rendering the HUD! // Removing this check will cause bad flickering when there are @@ -2621,7 +2659,7 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); @@ -2648,6 +2686,10 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth); if (depth > 3) { + if (gDebugSession) + { + ll_fail("GL matrix stack corrupted."); + } llerrs << "GL matrix stack corrupted!" << llendl; } std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i); @@ -2749,9 +2791,11 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate) void LLPipeline::renderGeomDeferred(LLCamera& camera) { LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred"); - LLFastTimer t(LLFastTimer::FTM_RENDER_GEOMETRY); - LLFastTimer t2(LLFastTimer::FTM_POOLS); + LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED); + LLFastTimer t(FTM_RENDER_GEOMETRY); + + LLFastTimer t2(FTM_POOLS); LLGLEnable cull(GL_CULL_FACE); @@ -2793,7 +2837,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); @@ -2850,7 +2894,8 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera) void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { - LLFastTimer t(LLFastTimer::FTM_POOLS); + LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF); + LLFastTimer t(FTM_POOLS); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -2883,7 +2928,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) pool_set_t::iterator iter2 = iter1; if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0) { - LLFastTimer t(LLFastTimer::FTM_POOLRENDER); + LLFastTimer t(FTM_POOLRENDER); gGLLastMatrix = NULL; glLoadMatrixd(gGLModelView); @@ -2961,6 +3006,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) void LLPipeline::renderGeomShadow(LLCamera& camera) { + LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW); U32 cur_type = 0; LLGLEnable cull(GL_CULL_FACE); @@ -3222,7 +3268,7 @@ void LLPipeline::renderForSelect(std::set& objects, BOOL render stateSort((*iter)->mDrawable, *LLViewerCamera::getInstance()); } - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_SELECT); @@ -3297,7 +3343,7 @@ void LLPipeline::renderForSelect(std::set& objects, BOOL render LLDrawable* drawable = vobj->mDrawable; if (vobj->isDead() || vobj->isHUDAttachment() || - (gHideSelectedObjects && vobj->isSelected()) || + (LLSelectMgr::getInstance()->mHideSelectedObjects && vobj->isSelected()) || drawable->isDead() || !hasRenderType(drawable->getRenderType())) { @@ -3387,7 +3433,7 @@ void LLPipeline::renderForSelect(std::set& objects, BOOL render void LLPipeline::rebuildPools() { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS); assertInitialized(); @@ -3427,7 +3473,7 @@ void LLPipeline::rebuildPools() void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) { - LLMemType mt(LLMemType::MTYPE_PIPELINE); + LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP); assertInitialized(); @@ -4098,18 +4144,21 @@ void LLPipeline::setupHWLights(LLDrawPool* pool) void LLPipeline::enableLights(U32 mask) { assertInitialized(); + if (mLightingDetail == 0) { mask &= 0xf003; // sun and backlight only (and fullbright bit) } if (mLightMask != mask) { + stop_glerror(); if (!mLightMask) { glEnable(GL_LIGHTING); } if (mask) { + stop_glerror(); for (S32 i=0; i<8; i++) { if (mask & (1<getWindowDisplayWidth()*2, - (F32) gViewerWindow->getWindowDisplayHeight()*2); + LLVector2 tc2((F32) gViewerWindow->getWorldViewWidth()*2, + (F32) gViewerWindow->getWorldViewHeight()*2); if (res_mod > 1) { @@ -4991,7 +5046,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) gGL.setColorMask(true, true); - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM); + LLFastTimer ftm(FTM_RENDER_BLOOM); gGL.color4f(1,1,1,1); LLGLDepthTest depth(GL_FALSE); LLGLDisable blend(GL_BLEND); @@ -5066,7 +5121,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) { { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); mGlow[2].bindTarget(); mGlow[2].clear(); } @@ -5138,7 +5193,7 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); mGlow[i%2].bindTarget(); mGlow[i%2].clear(); } @@ -5180,11 +5235,15 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) if (LLRenderTarget::sUseFBO) { - LLFastTimer ftm(LLFastTimer::FTM_RENDER_BLOOM_FBO); + LLFastTimer ftm(FTM_RENDER_BLOOM_FBO); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); } - gViewerWindow->setupViewport(); + gGLViewport[0] = gViewerWindow->getWorldViewRect().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRect().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRect().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRect().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); gGL.flush(); @@ -5193,8 +5252,8 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield) - tc2.setVec((F32) gViewerWindow->getWindowDisplayWidth(), - (F32) gViewerWindow->getWindowDisplayHeight()); + tc2.setVec((F32) gViewerWindow->getWorldViewWidth(), + (F32) gViewerWindow->getWorldViewHeight()); if (res_mod > 1) { @@ -5787,15 +5846,15 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) { if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate) { - LLVOAvatar* agent = gAgent.getAvatarObject(); + LLVOAvatarSelf* avatar = gAgent.getAvatarObject(); if (gAgent.getCameraAnimating() || gAgent.getCameraMode() != CAMERA_MODE_MOUSELOOK) { - agent = NULL; + avatar = NULL; } - if (agent) + if (avatar) { - agent->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); + avatar->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON); } LLVertexBuffer::unbind(); @@ -5985,7 +6044,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) } glClearColor(0.f, 0.f, 0.f, 0.f); - gViewerWindow->setupViewport(); + gViewerWindow->setup3DViewport(); mRenderTypeMask = type_mask; LLDrawPoolWater::sNeedsReflectionUpdate = FALSE; LLDrawPoolWater::sNeedsDistortionUpdate = FALSE; @@ -5996,9 +6055,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in) LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); - if (agent) + if (avatar) { - agent->updateAttachmentVisibility(gAgent.getCameraMode()); + avatar->updateAttachmentVisibility(gAgent.getCameraMode()); } } } @@ -6070,6 +6129,10 @@ glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max) return ret; } +static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows"); +static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow"); +static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow"); + void LLPipeline::generateSunShadow(LLCamera& camera) { @@ -6318,7 +6381,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) mShadowCamera[j+4] = shadow_cam; } - LLFastTimer t(LLFastTimer::FTM_SHADOW_RENDER); + LLFastTimer t(FTM_SHADOW_RENDER); stop_glerror(); @@ -6356,7 +6419,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) gDeferredShadowProgram.bind(); { - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_SIMPLE); + LLFastTimer ftm(FTM_SHADOW_SIMPLE); LLGLDisable test(GL_ALPHA_TEST); gGL.getTexUnit(0)->disable(); for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i) @@ -6367,7 +6430,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) } { - LLFastTimer ftm(LLFastTimer::FTM_SHADOW_ALPHA); + LLFastTimer ftm(FTM_SHADOW_ALPHA); LLGLEnable test(GL_ALPHA_TEST); gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f); renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE); @@ -6430,6 +6493,7 @@ void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL textu void LLPipeline::generateImpostor(LLVOAvatar* avatar) { + LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR); LLGLState::checkStates(); LLGLState::checkTextureChannels(); LLGLState::checkClientArrays(); @@ -6670,3 +6734,4 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups() return sCull->endAlphaGroups(); } + diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 1a32b30831..8f6867aa01 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -33,20 +33,20 @@ #ifndef LL_PIPELINE_H #define LL_PIPELINE_H +#include "llcamera.h" #include "llerror.h" #include "lldarrayptr.h" #include "lldqueueptr.h" -#include "llstat.h" #include "lldrawpool.h" #include "llspatialpartition.h" #include "m4math.h" -#include "llmemory.h" +#include "llpointer.h" #include "lldrawpool.h" #include "llgl.h" #include "lldrawable.h" #include "llrendertarget.h" -class LLViewerImage; +class LLViewerTexture; class LLEdge; class LLFace; class LLViewerObject; @@ -78,6 +78,27 @@ glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, glh::matrix4f gl_perspective(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar); glh::matrix4f gl_lookat(LLVector3 eye, LLVector3 center, LLVector3 up); +extern LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY; +extern LLFastTimer::DeclareTimer FTM_RENDER_GRASS; +extern LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE; +extern LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION; +extern LLFastTimer::DeclareTimer FTM_RENDER_SHINY; +extern LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE; +extern LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN; +extern LLFastTimer::DeclareTimer FTM_RENDER_TREES; +extern LLFastTimer::DeclareTimer FTM_RENDER_UI; +extern LLFastTimer::DeclareTimer FTM_RENDER_WATER; +extern LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY; +extern LLFastTimer::DeclareTimer FTM_RENDER_ALPHA; +extern LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS; +extern LLFastTimer::DeclareTimer FTM_RENDER_BUMP; +extern LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT; +extern LLFastTimer::DeclareTimer FTM_RENDER_GLOW; +extern LLFastTimer::DeclareTimer FTM_STATESORT; +extern LLFastTimer::DeclareTimer FTM_PIPELINE; +extern LLFastTimer::DeclareTimer FTM_CLIENT_COPY; + + class LLPipeline { public: @@ -104,15 +125,15 @@ public: /// @brief Get a draw pool from pool type (POOL_SIMPLE, POOL_MEDIA) and texture. /// @return Draw pool, or NULL if not found. - LLDrawPool *findPool(const U32 pool_type, LLViewerImage *tex0 = NULL); + LLDrawPool *findPool(const U32 pool_type, LLViewerTexture *tex0 = NULL); /// @brief Get a draw pool for faces of the appropriate type and texture. Create if necessary. /// @return Always returns a draw pool. - LLDrawPool *getPool(const U32 pool_type, LLViewerImage *tex0 = NULL); + LLDrawPool *getPool(const U32 pool_type, LLViewerTexture *tex0 = NULL); /// @brief Figures out draw pool type from texture entry. Creates pool if necessary. - static LLDrawPool* getPoolFromTE(const LLTextureEntry* te, LLViewerImage* te_image); - static U32 getPoolTypeFromTE(const LLTextureEntry* te, LLViewerImage* imagep); + static LLDrawPool* getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* te_image); + static U32 getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep); void addPool(LLDrawPool *poolp); // Only to be used by LLDrawPool classes for splitting pools! void removePool( LLDrawPool* poolp ); @@ -150,7 +171,7 @@ public: ); // Something about these textures has changed. Dirty them. - void dirtyPoolObjectTextures(const std::set& textures); + void dirtyPoolObjectTextures(const std::set& textures); void resetDrawOrders(); @@ -383,7 +404,6 @@ public: S32 mMeanBatchSize; S32 mTrianglesDrawn; S32 mNumVisibleNodes; - LLStat mTrianglesDrawnStat; S32 mVerticesRelit; S32 mLightingChanges; @@ -562,9 +582,9 @@ public: protected: std::vector mSelectedFaces; - LLPointer mFaceSelectImagep; - LLPointer mBloomImagep; - LLPointer mBloomImage2p; + LLPointer mFaceSelectImagep; + LLPointer mBloomImagep; + LLPointer mBloomImage2p; U32 mLightMask; U32 mLightMovingMask; diff --git a/indra/newview/res/bitmap2.bmp b/indra/newview/res/bitmap2.bmp new file mode 100644 index 0000000000..770b07558c Binary files /dev/null and b/indra/newview/res/bitmap2.bmp differ diff --git a/indra/newview/res/install_icon.BMP b/indra/newview/res/install_icon.BMP new file mode 100644 index 0000000000..09df573870 Binary files /dev/null and b/indra/newview/res/install_icon.BMP differ diff --git a/indra/newview/res/loginbackground.bmp b/indra/newview/res/loginbackground.bmp new file mode 100644 index 0000000000..288a0b0398 Binary files /dev/null and b/indra/newview/res/loginbackground.bmp differ diff --git a/indra/newview/res/uninstall_icon.BMP b/indra/newview/res/uninstall_icon.BMP new file mode 100644 index 0000000000..562b56676a Binary files /dev/null and b/indra/newview/res/uninstall_icon.BMP differ diff --git a/indra/newview/res/viewerRes.rc b/indra/newview/res/viewerRes.rc index 352d5cab55..9a0938b879 100644 --- a/indra/newview/res/viewerRes.rc +++ b/indra/newview/res/viewerRes.rc @@ -138,8 +138,8 @@ TOOLMEDIAOPEN CURSOR "toolmediaopen.cur" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,24,4,0 - PRODUCTVERSION 1,24,4,0 + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -156,12 +156,12 @@ BEGIN BEGIN VALUE "CompanyName", "Linden Lab" VALUE "FileDescription", "Second Life" - VALUE "FileVersion", "1.24.4.0" + VALUE "FileVersion", "2.0.0.0" VALUE "InternalName", "Second Life" - VALUE "LegalCopyright", "Copyright © 2001-2008, Linden Research, Inc." + VALUE "LegalCopyright", "Copyright � 2001-2008, Linden Research, Inc." VALUE "OriginalFilename", "SecondLife.exe" VALUE "ProductName", "Second Life" - VALUE "ProductVersion", "1.24.4.0" + VALUE "ProductVersion", "2.0.0.0" END END BLOCK "VarFileInfo" diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index cf9466fad3..c739d4d455 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -1,3 +1,674 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/textures/bottomtray/DownArrow.png b/indra/newview/skins/default/textures/bottomtray/DownArrow.png new file mode 100644 index 0000000000..82f58b22b9 Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/DownArrow.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/Unread_IM.png b/indra/newview/skins/default/textures/bottomtray/Unread_IM.png new file mode 100644 index 0000000000..a355917fca Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/Unread_IM.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png new file mode 100644 index 0000000000..cd18ae310d Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl1.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png new file mode 100644 index 0000000000..b0ed6ee8eb Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl2.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl3.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl3.png new file mode 100644 index 0000000000..14ec77b99a Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Lvl3.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_Off.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Off.png new file mode 100644 index 0000000000..48be51e9af Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/VoicePTT_Off.png differ diff --git a/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png b/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png new file mode 100644 index 0000000000..be4881b64c Binary files /dev/null and b/indra/newview/skins/default/textures/bottomtray/VoicePTT_On.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Off.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Off.png new file mode 100644 index 0000000000..19c842b816 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Over.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Over.png new file mode 100644 index 0000000000..e47f913db1 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Press.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Press.png new file mode 100644 index 0000000000..b9879dcc8a Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowClosed_Press.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Off.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Off.png new file mode 100644 index 0000000000..d506cda5c9 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Over.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Over.png new file mode 100644 index 0000000000..e2c67de9c0 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Press.png b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Press.png new file mode 100644 index 0000000000..08f7493a02 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_ArrowOpened_Press.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_Off.png b/indra/newview/skins/default/textures/containers/Accordion_Off.png new file mode 100644 index 0000000000..414f4509c6 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_Over.png b/indra/newview/skins/default/textures/containers/Accordion_Over.png new file mode 100644 index 0000000000..5416d73310 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Accordion_Press.png b/indra/newview/skins/default/textures/containers/Accordion_Press.png new file mode 100644 index 0000000000..1578e0dfc5 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Accordion_Press.png differ diff --git a/indra/newview/skins/default/textures/containers/Container.png b/indra/newview/skins/default/textures/containers/Container.png new file mode 100644 index 0000000000..511eb94386 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Container.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Left_Off.png b/indra/newview/skins/default/textures/containers/TabTop_Left_Off.png new file mode 100644 index 0000000000..1951413f8d Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Left_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Left_Over.png b/indra/newview/skins/default/textures/containers/TabTop_Left_Over.png new file mode 100644 index 0000000000..295cd89a57 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Left_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Left_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_Left_Selected.png new file mode 100644 index 0000000000..8364716e02 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Left_Selected.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Middle_Off.png b/indra/newview/skins/default/textures/containers/TabTop_Middle_Off.png new file mode 100644 index 0000000000..21f1c2d8a8 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Middle_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Middle_Over.png b/indra/newview/skins/default/textures/containers/TabTop_Middle_Over.png new file mode 100644 index 0000000000..0758cbcf0d Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Middle_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Middle_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_Middle_Selected.png new file mode 100644 index 0000000000..3946917c7c Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Middle_Selected.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Right_Off.png b/indra/newview/skins/default/textures/containers/TabTop_Right_Off.png new file mode 100644 index 0000000000..eeef28e5a5 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Right_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Right_Over.png b/indra/newview/skins/default/textures/containers/TabTop_Right_Over.png new file mode 100644 index 0000000000..c2cbc2b1e5 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Right_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/TabTop_Right_Selected.png b/indra/newview/skins/default/textures/containers/TabTop_Right_Selected.png new file mode 100644 index 0000000000..b0f1f16398 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/TabTop_Right_Selected.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Left_Off.png b/indra/newview/skins/default/textures/containers/Toolbar_Left_Off.png new file mode 100644 index 0000000000..41b5d24d87 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Left_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Left_Over.png b/indra/newview/skins/default/textures/containers/Toolbar_Left_Over.png new file mode 100644 index 0000000000..083acc0156 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Left_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Left_Selected.png b/indra/newview/skins/default/textures/containers/Toolbar_Left_Selected.png new file mode 100644 index 0000000000..ee4649a8f9 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Left_Selected.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Off.png b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Off.png new file mode 100644 index 0000000000..55c02160e3 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Over.png b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Over.png new file mode 100644 index 0000000000..2f6ea90196 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png new file mode 100644 index 0000000000..642113b135 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Middle_Selected.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Right_Off.png b/indra/newview/skins/default/textures/containers/Toolbar_Right_Off.png new file mode 100644 index 0000000000..01fd765c3d Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Right_Off.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Right_Over.png b/indra/newview/skins/default/textures/containers/Toolbar_Right_Over.png new file mode 100644 index 0000000000..74e00635f1 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Right_Over.png differ diff --git a/indra/newview/skins/default/textures/containers/Toolbar_Right_Selected.png b/indra/newview/skins/default/textures/containers/Toolbar_Right_Selected.png new file mode 100644 index 0000000000..8a0d98a780 Binary files /dev/null and b/indra/newview/skins/default/textures/containers/Toolbar_Right_Selected.png differ diff --git a/indra/newview/skins/default/textures/icons/AddItem_Off.png b/indra/newview/skins/default/textures/icons/AddItem_Off.png new file mode 100644 index 0000000000..52d4f9bc80 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/AddItem_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/AddItem_Over.png b/indra/newview/skins/default/textures/icons/AddItem_Over.png new file mode 100644 index 0000000000..cad6e8d52f Binary files /dev/null and b/indra/newview/skins/default/textures/icons/AddItem_Over.png differ diff --git a/indra/newview/skins/default/textures/icons/AddItem_Press.png b/indra/newview/skins/default/textures/icons/AddItem_Press.png new file mode 100644 index 0000000000..acc898e5f4 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/AddItem_Press.png differ diff --git a/indra/newview/skins/default/textures/icons/BackArrow_Off.png b/indra/newview/skins/default/textures/icons/BackArrow_Off.png new file mode 100644 index 0000000000..ff32192856 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/BackArrow_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/BackArrow_Over.png b/indra/newview/skins/default/textures/icons/BackArrow_Over.png new file mode 100644 index 0000000000..b36e03a8cf Binary files /dev/null and b/indra/newview/skins/default/textures/icons/BackArrow_Over.png differ diff --git a/indra/newview/skins/default/textures/icons/ForwardArrow_Off.png b/indra/newview/skins/default/textures/icons/ForwardArrow_Off.png new file mode 100644 index 0000000000..e9b72b0401 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ForwardArrow_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/ForwardArrow_Press.png b/indra/newview/skins/default/textures/icons/ForwardArrow_Press.png new file mode 100644 index 0000000000..c7b2c769ae Binary files /dev/null and b/indra/newview/skins/default/textures/icons/ForwardArrow_Press.png differ diff --git a/indra/newview/skins/default/textures/icons/Info.png b/indra/newview/skins/default/textures/icons/Info.png new file mode 100644 index 0000000000..e52560281b Binary files /dev/null and b/indra/newview/skins/default/textures/icons/Info.png differ diff --git a/indra/newview/skins/default/textures/icons/OptionsMenu_Off.png b/indra/newview/skins/default/textures/icons/OptionsMenu_Off.png new file mode 100644 index 0000000000..25b055bfc0 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/OptionsMenu_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/OptionsMenu_Over.png b/indra/newview/skins/default/textures/icons/OptionsMenu_Over.png new file mode 100644 index 0000000000..fcabd4c6d3 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/OptionsMenu_Over.png differ diff --git a/indra/newview/skins/default/textures/icons/OptionsMenu_Press.png b/indra/newview/skins/default/textures/icons/OptionsMenu_Press.png new file mode 100644 index 0000000000..6e91dd7159 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/OptionsMenu_Press.png differ diff --git a/indra/newview/skins/default/textures/icons/TrashItem_Off.png b/indra/newview/skins/default/textures/icons/TrashItem_Off.png new file mode 100644 index 0000000000..bb64920ec4 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/TrashItem_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/TrashItem_Over.png b/indra/newview/skins/default/textures/icons/TrashItem_Over.png new file mode 100644 index 0000000000..1a0eea6c67 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/TrashItem_Over.png differ diff --git a/indra/newview/skins/default/textures/icons/TrashItem_Press.png b/indra/newview/skins/default/textures/icons/TrashItem_Press.png new file mode 100644 index 0000000000..c62f833d86 Binary files /dev/null and b/indra/newview/skins/default/textures/icons/TrashItem_Press.png differ diff --git a/indra/newview/skins/default/textures/icons/VoicePTT_Lvl1.png b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl1.png new file mode 100644 index 0000000000..cd18ae310d Binary files /dev/null and b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl1.png differ diff --git a/indra/newview/skins/default/textures/icons/VoicePTT_Lvl2.png b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl2.png new file mode 100644 index 0000000000..b0ed6ee8eb Binary files /dev/null and b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl2.png differ diff --git a/indra/newview/skins/default/textures/icons/VoicePTT_Lvl3.png b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl3.png new file mode 100644 index 0000000000..14ec77b99a Binary files /dev/null and b/indra/newview/skins/default/textures/icons/VoicePTT_Lvl3.png differ diff --git a/indra/newview/skins/default/textures/icons/VoicePTT_Off.png b/indra/newview/skins/default/textures/icons/VoicePTT_Off.png new file mode 100644 index 0000000000..48be51e9af Binary files /dev/null and b/indra/newview/skins/default/textures/icons/VoicePTT_Off.png differ diff --git a/indra/newview/skins/default/textures/icons/VoicePTT_On.png b/indra/newview/skins/default/textures/icons/VoicePTT_On.png new file mode 100644 index 0000000000..be4881b64c Binary files /dev/null and b/indra/newview/skins/default/textures/icons/VoicePTT_On.png differ diff --git a/indra/newview/skins/default/textures/image_edit_icon.tga b/indra/newview/skins/default/textures/image_edit_icon.tga new file mode 100644 index 0000000000..8666f0bbe6 Binary files /dev/null and b/indra/newview/skins/default/textures/image_edit_icon.tga differ diff --git a/indra/newview/skins/default/textures/jump_left_in.tga b/indra/newview/skins/default/textures/jump_left_in.tga new file mode 100644 index 0000000000..e0656c901d Binary files /dev/null and b/indra/newview/skins/default/textures/jump_left_in.tga differ diff --git a/indra/newview/skins/default/textures/jump_left_out.tga b/indra/newview/skins/default/textures/jump_left_out.tga new file mode 100644 index 0000000000..fb6dac0c3d Binary files /dev/null and b/indra/newview/skins/default/textures/jump_left_out.tga differ diff --git a/indra/newview/skins/default/textures/jump_right_in.tga b/indra/newview/skins/default/textures/jump_right_in.tga new file mode 100644 index 0000000000..010c748c2a Binary files /dev/null and b/indra/newview/skins/default/textures/jump_right_in.tga differ diff --git a/indra/newview/skins/default/textures/jump_right_out.tga b/indra/newview/skins/default/textures/jump_right_out.tga new file mode 100644 index 0000000000..33355262d4 Binary files /dev/null and b/indra/newview/skins/default/textures/jump_right_out.tga differ diff --git a/indra/newview/skins/default/textures/menu_separator.png b/indra/newview/skins/default/textures/menu_separator.png new file mode 100644 index 0000000000..89dcdcdff5 Binary files /dev/null and b/indra/newview/skins/default/textures/menu_separator.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png b/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png new file mode 100644 index 0000000000..19569501fe Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Left_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Left_Over.png b/indra/newview/skins/default/textures/navbar/Arrow_Left_Over.png new file mode 100644 index 0000000000..a91b74819f Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Left_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png b/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png new file mode 100644 index 0000000000..3648c42656 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Right_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Arrow_Right_Over.png b/indra/newview/skins/default/textures/navbar/Arrow_Right_Over.png new file mode 100644 index 0000000000..a2caf227a7 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Arrow_Right_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png new file mode 100644 index 0000000000..e27dbe2cad Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Active.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png new file mode 100644 index 0000000000..82d044d817 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png new file mode 100644 index 0000000000..7909d54f2b Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png b/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png new file mode 100644 index 0000000000..6670667022 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Favorite_Star_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png b/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png new file mode 100644 index 0000000000..5ab4abc5b8 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/FileMenu_Divider.png differ diff --git a/indra/newview/skins/default/textures/navbar/Help_Over.png b/indra/newview/skins/default/textures/navbar/Help_Over.png new file mode 100644 index 0000000000..b9bc0d0f87 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Help_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Help_Press.png b/indra/newview/skins/default/textures/navbar/Help_Press.png new file mode 100644 index 0000000000..ed3695f9d5 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Help_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/Home_Off.png b/indra/newview/skins/default/textures/navbar/Home_Off.png new file mode 100644 index 0000000000..fe3bc63b77 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Home_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Home_Over.png b/indra/newview/skins/default/textures/navbar/Home_Over.png new file mode 100644 index 0000000000..d9c6b3842e Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Home_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Off.png b/indra/newview/skins/default/textures/navbar/Info_Off.png new file mode 100644 index 0000000000..64722255a3 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Off.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Over.png b/indra/newview/skins/default/textures/navbar/Info_Over.png new file mode 100644 index 0000000000..84f1d03129 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Over.png differ diff --git a/indra/newview/skins/default/textures/navbar/Info_Press.png b/indra/newview/skins/default/textures/navbar/Info_Press.png new file mode 100644 index 0000000000..169105829e Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Info_Press.png differ diff --git a/indra/newview/skins/default/textures/navbar/NavBar_BG.png b/indra/newview/skins/default/textures/navbar/NavBar_BG.png new file mode 100644 index 0000000000..1df61751a8 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/NavBar_BG.png differ diff --git a/indra/newview/skins/default/textures/navbar/Row_Selection.png b/indra/newview/skins/default/textures/navbar/Row_Selection.png new file mode 100644 index 0000000000..fc4f0c07ef Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Row_Selection.png differ diff --git a/indra/newview/skins/default/textures/navbar/Search.png b/indra/newview/skins/default/textures/navbar/Search.png new file mode 100644 index 0000000000..c43519d5f1 Binary files /dev/null and b/indra/newview/skins/default/textures/navbar/Search.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/avatar_free_mode.png b/indra/newview/skins/default/textures/quick_tips/avatar_free_mode.png new file mode 100644 index 0000000000..be7c87efb6 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/avatar_free_mode.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_free_mode.png b/indra/newview/skins/default/textures/quick_tips/camera_free_mode.png new file mode 100644 index 0000000000..9a3f3703b2 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_free_mode.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_orbit_mode.png b/indra/newview/skins/default/textures/quick_tips/camera_orbit_mode.png new file mode 100644 index 0000000000..dd72cc0162 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_orbit_mode.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_pan_mode.png b/indra/newview/skins/default/textures/quick_tips/camera_pan_mode.png new file mode 100644 index 0000000000..b537dcbe46 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_pan_mode.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_preset_front_view.png b/indra/newview/skins/default/textures/quick_tips/camera_preset_front_view.png new file mode 100644 index 0000000000..7674a75ac3 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_preset_front_view.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_preset_group_view.png b/indra/newview/skins/default/textures/quick_tips/camera_preset_group_view.png new file mode 100644 index 0000000000..9c9b923a5a Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_preset_group_view.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/camera_preset_rear_view.png b/indra/newview/skins/default/textures/quick_tips/camera_preset_rear_view.png new file mode 100644 index 0000000000..15c3053491 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/camera_preset_rear_view.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_fly_first.png b/indra/newview/skins/default/textures/quick_tips/move_fly_first.png new file mode 100644 index 0000000000..b6e2ce60e4 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_fly_first.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_fly_second.png b/indra/newview/skins/default/textures/quick_tips/move_fly_second.png new file mode 100644 index 0000000000..84b63cc338 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_fly_second.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_run_first.png b/indra/newview/skins/default/textures/quick_tips/move_run_first.png new file mode 100644 index 0000000000..16093dc683 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_run_first.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_run_second.png b/indra/newview/skins/default/textures/quick_tips/move_run_second.png new file mode 100644 index 0000000000..19fa43ec32 Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_run_second.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_walk_first.png b/indra/newview/skins/default/textures/quick_tips/move_walk_first.png new file mode 100644 index 0000000000..92d120d53e Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_walk_first.png differ diff --git a/indra/newview/skins/default/textures/quick_tips/move_walk_second.png b/indra/newview/skins/default/textures/quick_tips/move_walk_second.png new file mode 100644 index 0000000000..f8e28722be Binary files /dev/null and b/indra/newview/skins/default/textures/quick_tips/move_walk_second.png differ diff --git a/indra/newview/skins/default/textures/show_btn.tga b/indra/newview/skins/default/textures/show_btn.tga new file mode 100644 index 0000000000..5f05f377e3 Binary files /dev/null and b/indra/newview/skins/default/textures/show_btn.tga differ diff --git a/indra/newview/skins/default/textures/show_btn_selected.tga b/indra/newview/skins/default/textures/show_btn_selected.tga new file mode 100644 index 0000000000..00a2f34a37 Binary files /dev/null and b/indra/newview/skins/default/textures/show_btn_selected.tga differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.png new file mode 100644 index 0000000000..2dc32a576b Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.png new file mode 100644 index 0000000000..bea218a2fb Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Appearance_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Close_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Close_Off.png new file mode 100644 index 0000000000..bc4e00c646 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Close_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Off.png new file mode 100644 index 0000000000..1e7d7beafa Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Selected.png new file mode 100644 index 0000000000..a70d3abbbf Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Home_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Off.png new file mode 100644 index 0000000000..2d36f70361 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Selected.png new file mode 100644 index 0000000000..3c20459126 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Me_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Open_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Open_Off.png new file mode 100644 index 0000000000..4556602f58 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Open_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Off.png new file mode 100644 index 0000000000..c272372a39 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Selected.png new file mode 100644 index 0000000000..3828752606 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_People_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Off.png new file mode 100644 index 0000000000..d7ec33af55 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Selected.png new file mode 100644 index 0000000000..dd7e361ea9 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Places_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Off.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Off.png new file mode 100644 index 0000000000..e56eda9802 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Selected.png b/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Selected.png new file mode 100644 index 0000000000..d4ac451c8e Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TabIcon_Things_Selected.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Off.png b/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Off.png new file mode 100644 index 0000000000..918be7555f Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Off.png differ diff --git a/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Selected.png b/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Selected.png new file mode 100644 index 0000000000..b3316386b9 Binary files /dev/null and b/indra/newview/skins/default/textures/taskpanel/TaskPanel_Tab_Selected.png differ diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 34c9dea7e6..0bd5f114ed 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -1,74 +1,359 @@ + + + + + + + - - - - - - - - - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -96,6 +381,7 @@ + @@ -103,18 +389,21 @@ + + + - + @@ -126,6 +415,8 @@ + + @@ -141,13 +432,13 @@ - + - + - + @@ -157,17 +448,17 @@ - + - - - + + + - + @@ -198,11 +489,11 @@ - + - + @@ -213,7 +504,7 @@ - + @@ -225,7 +516,7 @@ - + @@ -233,144 +524,30 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/textures/transparent.j2c b/indra/newview/skins/default/textures/transparent.j2c new file mode 100644 index 0000000000..1068e940b9 Binary files /dev/null and b/indra/newview/skins/default/textures/transparent.j2c differ diff --git a/indra/newview/skins/default/textures/voice_meter_dot.j2c b/indra/newview/skins/default/textures/voice_meter_dot.j2c new file mode 100644 index 0000000000..e536c3338a Binary files /dev/null and b/indra/newview/skins/default/textures/voice_meter_dot.j2c differ diff --git a/indra/newview/skins/default/textures/voice_meter_rings.j2c b/indra/newview/skins/default/textures/voice_meter_rings.j2c new file mode 100644 index 0000000000..17e7c6c6a1 Binary files /dev/null and b/indra/newview/skins/default/textures/voice_meter_rings.j2c differ diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Down.png b/indra/newview/skins/default/textures/widgets/Arrow_Down.png new file mode 100644 index 0000000000..e10f6472eb Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Arrow_Down.png differ diff --git a/indra/newview/skins/default/textures/widgets/Arrow_Up.png b/indra/newview/skins/default/textures/widgets/Arrow_Up.png new file mode 100644 index 0000000000..48df69d82e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Arrow_Up.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png b/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png new file mode 100644 index 0000000000..c1ee210099 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Off.png b/indra/newview/skins/default/textures/widgets/Checkbox_Off.png new file mode 100644 index 0000000000..2525405f37 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On.png b/indra/newview/skins/default/textures/widgets/Checkbox_On.png new file mode 100644 index 0000000000..2d9dba1592 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png b/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png new file mode 100644 index 0000000000..beaa7bcbf6 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_On_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On_Over.png b/indra/newview/skins/default/textures/widgets/Checkbox_On_Over.png new file mode 100644 index 0000000000..bc504d130e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png b/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png new file mode 100644 index 0000000000..5bced95a89 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_On_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Over.png b/indra/newview/skins/default/textures/widgets/Checkbox_Over.png new file mode 100644 index 0000000000..5a7162addf Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/Checkbox_Press.png b/indra/newview/skins/default/textures/widgets/Checkbox_Press.png new file mode 100644 index 0000000000..44be193678 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Checkbox_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png b/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png new file mode 100644 index 0000000000..d0fff1b3c3 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ComboButton_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Off.png b/indra/newview/skins/default/textures/widgets/ComboButton_Off.png new file mode 100644 index 0000000000..80402458b7 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ComboButton_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_On.png b/indra/newview/skins/default/textures/widgets/ComboButton_On.png new file mode 100644 index 0000000000..b42cc7542e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ComboButton_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png b/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png new file mode 100644 index 0000000000..bbc0657487 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ComboButton_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/DisclosureArrow_Closed_Over.png b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Closed_Over.png new file mode 100644 index 0000000000..45bcb0464e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Closed_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Off.png b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Off.png new file mode 100644 index 0000000000..75057938d2 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Over.png b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Over.png new file mode 100644 index 0000000000..dabbd85b34 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DisclosureArrow_Opened_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png b/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png new file mode 100644 index 0000000000..b295752ea9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DropDown_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Off.png b/indra/newview/skins/default/textures/widgets/DropDown_Off.png new file mode 100644 index 0000000000..4764ed4ee2 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DropDown_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/DropDown_On.png b/indra/newview/skins/default/textures/widgets/DropDown_On.png new file mode 100644 index 0000000000..10262d3979 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DropDown_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/DropDown_Press.png b/indra/newview/skins/default/textures/widgets/DropDown_Press.png new file mode 100644 index 0000000000..16cb25cc77 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/DropDown_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/ListItem_Over.png b/indra/newview/skins/default/textures/widgets/ListItem_Over.png new file mode 100644 index 0000000000..4b2b9ab3e5 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ListItem_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ListItem_Select.png b/indra/newview/skins/default/textures/widgets/ListItem_Select.png new file mode 100644 index 0000000000..317c672441 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ListItem_Select.png differ diff --git a/indra/newview/skins/default/textures/widgets/ProgressBar.png b/indra/newview/skins/default/textures/widgets/ProgressBar.png new file mode 100644 index 0000000000..edf11ac1f5 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ProgressBar.png differ diff --git a/indra/newview/skins/default/textures/widgets/ProgressTrack.png b/indra/newview/skins/default/textures/widgets/ProgressTrack.png new file mode 100644 index 0000000000..bb6d9f4144 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ProgressTrack.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png b/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png new file mode 100644 index 0000000000..04e91bdaab Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Off.png b/indra/newview/skins/default/textures/widgets/PushButton_Off.png new file mode 100644 index 0000000000..1ee0329e66 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_On.png b/indra/newview/skins/default/textures/widgets/PushButton_On.png new file mode 100644 index 0000000000..661d1c5611 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_On_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_On_Over.png new file mode 100644 index 0000000000..064a4c4f7f Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_On_Selected.png b/indra/newview/skins/default/textures/widgets/PushButton_On_Selected.png new file mode 100644 index 0000000000..48e8aa2eab Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_On_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_Over.png new file mode 100644 index 0000000000..c227f07513 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Press.png b/indra/newview/skins/default/textures/widgets/PushButton_Press.png new file mode 100644 index 0000000000..0a4a3a6ad9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Selected.png b/indra/newview/skins/default/textures/widgets/PushButton_Selected.png new file mode 100644 index 0000000000..0a4a3a6ad9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Selected_Disabled.png b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Disabled.png new file mode 100644 index 0000000000..661d1c5611 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Selected_Over.png b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Over.png new file mode 100644 index 0000000000..064a4c4f7f Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png new file mode 100644 index 0000000000..48e8aa2eab Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/PushButton_Selected_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png b/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png new file mode 100644 index 0000000000..a1052684b9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Off.png b/indra/newview/skins/default/textures/widgets/RadioButton_Off.png new file mode 100644 index 0000000000..c58e0305ef Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On.png b/indra/newview/skins/default/textures/widgets/RadioButton_On.png new file mode 100644 index 0000000000..c09a2197c7 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png b/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png new file mode 100644 index 0000000000..d7d444fd0c Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_On_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On_Over.png b/indra/newview/skins/default/textures/widgets/RadioButton_On_Over.png new file mode 100644 index 0000000000..3e7d803a28 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png b/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png new file mode 100644 index 0000000000..a707e8ceb8 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_On_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Over.png b/indra/newview/skins/default/textures/widgets/RadioButton_Over.png new file mode 100644 index 0000000000..a5c8cbe293 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/RadioButton_Press.png b/indra/newview/skins/default/textures/widgets/RadioButton_Press.png new file mode 100644 index 0000000000..33eaa14030 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/RadioButton_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Down.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Down.png new file mode 100644 index 0000000000..186822da43 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Down.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Down_Over.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Down_Over.png new file mode 100644 index 0000000000..605d159eaa Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Down_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Left.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Left.png new file mode 100644 index 0000000000..42f999a451 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Left.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Left_Over.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Left_Over.png new file mode 100644 index 0000000000..c79547dffd Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Left_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Right.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Right.png new file mode 100644 index 0000000000..176ffcdbb9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Right.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Right_Over.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Right_Over.png new file mode 100644 index 0000000000..e353542ad9 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Right_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Up.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Up.png new file mode 100644 index 0000000000..4d245eb57a Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Up.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollArrow_Up_Over.png b/indra/newview/skins/default/textures/widgets/ScrollArrow_Up_Over.png new file mode 100644 index 0000000000..dd2fceb716 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollArrow_Up_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png new file mode 100644 index 0000000000..8a085aa966 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz_Over.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz_Over.png new file mode 100644 index 0000000000..cf78ea3924 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollThumb_Horiz_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png new file mode 100644 index 0000000000..fc7fd93e7a Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert_Over.png b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert_Over.png new file mode 100644 index 0000000000..53587197da Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollThumb_Vert_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollTrack_Horiz.png b/indra/newview/skins/default/textures/widgets/ScrollTrack_Horiz.png new file mode 100644 index 0000000000..4f31c48c02 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollTrack_Horiz.png differ diff --git a/indra/newview/skins/default/textures/widgets/ScrollTrack_Vert.png b/indra/newview/skins/default/textures/widgets/ScrollTrack_Vert.png new file mode 100644 index 0000000000..f89ee3f68f Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/ScrollTrack_Vert.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Disabled.png new file mode 100644 index 0000000000..3b39c51a77 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Off.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Off.png new file mode 100644 index 0000000000..57ed79d733 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On.png new file mode 100644 index 0000000000..7afb9c99c3 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Disabled.png new file mode 100644 index 0000000000..77c4224539 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Over.png new file mode 100644 index 0000000000..8b93dd551e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Selected.png new file mode 100644 index 0000000000..3f207cbea2 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_On_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Over.png new file mode 100644 index 0000000000..5b8878e0cb Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Press.png new file mode 100644 index 0000000000..379953216b Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected.png new file mode 100644 index 0000000000..379953216b Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Disabled.png new file mode 100644 index 0000000000..77c4224539 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Over.png new file mode 100644 index 0000000000..8b93dd551e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Press.png new file mode 100644 index 0000000000..3f207cbea2 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Left_Selected_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png new file mode 100644 index 0000000000..deb87c8489 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On.png new file mode 100644 index 0000000000..220df9db25 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Over.png new file mode 100644 index 0000000000..5bbcdcb0b4 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Press.png new file mode 100644 index 0000000000..dde367f05e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_On_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Over.png new file mode 100644 index 0000000000..d4f30b9adb Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png new file mode 100644 index 0000000000..ca7027da91 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png new file mode 100644 index 0000000000..220df9db25 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Over.png new file mode 100644 index 0000000000..5bbcdcb0b4 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png new file mode 100644 index 0000000000..dde367f05e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Middle_Selected_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Disabled.png new file mode 100644 index 0000000000..8e6b9c8c6f Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Off.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Off.png new file mode 100644 index 0000000000..b1521199ff Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On.png new file mode 100644 index 0000000000..467c43fc90 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Over.png new file mode 100644 index 0000000000..2049736897 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Selected.png new file mode 100644 index 0000000000..1574f48b28 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_On_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Over.png new file mode 100644 index 0000000000..2717e7d7b0 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Press.png new file mode 100644 index 0000000000..3883518033 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected.png new file mode 100644 index 0000000000..3883518033 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Disabled.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Disabled.png new file mode 100644 index 0000000000..ab31f6ded7 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Over.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Over.png new file mode 100644 index 0000000000..2049736897 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Press.png b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Press.png new file mode 100644 index 0000000000..1574f48b28 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SegmentedBtn_Right_Selected_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png new file mode 100644 index 0000000000..b627232012 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderThumb_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png new file mode 100644 index 0000000000..b627232012 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderThumb_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Over.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Over.png new file mode 100644 index 0000000000..b6f900d3bd Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderThumb_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png b/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png new file mode 100644 index 0000000000..7081f9cfe0 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderThumb_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png b/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png new file mode 100644 index 0000000000..232006ee5a Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderTrack_Horiz.png differ diff --git a/indra/newview/skins/default/textures/widgets/SliderTrack_Vert.png b/indra/newview/skins/default/textures/widgets/SliderTrack_Vert.png new file mode 100644 index 0000000000..cd002b3973 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/SliderTrack_Vert.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png b/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png new file mode 100644 index 0000000000..cf0d8ee2c1 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Down_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Down_Over.png b/indra/newview/skins/default/textures/widgets/Stepper_Down_Over.png new file mode 100644 index 0000000000..01e0a2d9f1 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Down_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png b/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png new file mode 100644 index 0000000000..fe3a7beafd Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Down_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png b/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png new file mode 100644 index 0000000000..133589b8a6 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Up_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Up_Over.png b/indra/newview/skins/default/textures/widgets/Stepper_Up_Over.png new file mode 100644 index 0000000000..2ce84ea5be Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Up_Over.png differ diff --git a/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png b/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png new file mode 100644 index 0000000000..e83babc519 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/Stepper_Up_Press.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Active.png b/indra/newview/skins/default/textures/widgets/TextField_Active.png new file mode 100644 index 0000000000..ca6daab4e0 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Active.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Disabled.png b/indra/newview/skins/default/textures/widgets/TextField_Disabled.png new file mode 100644 index 0000000000..3d205a3f2e Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Off.png b/indra/newview/skins/default/textures/widgets/TextField_Off.png new file mode 100644 index 0000000000..911d907acc Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Off.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Search_Active.png b/indra/newview/skins/default/textures/widgets/TextField_Search_Active.png new file mode 100644 index 0000000000..fa79cb6260 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Search_Active.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Search_Disabled.png b/indra/newview/skins/default/textures/widgets/TextField_Search_Disabled.png new file mode 100644 index 0000000000..8b504af101 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Search_Disabled.png differ diff --git a/indra/newview/skins/default/textures/widgets/TextField_Search_Off.png b/indra/newview/skins/default/textures/widgets/TextField_Search_Off.png new file mode 100644 index 0000000000..862b13d219 Binary files /dev/null and b/indra/newview/skins/default/textures/widgets/TextField_Search_Off.png differ diff --git a/indra/newview/skins/default/textures/windows/Flyout.png b/indra/newview/skins/default/textures/windows/Flyout.png new file mode 100644 index 0000000000..5596b194c9 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Flyout.png differ diff --git a/indra/newview/skins/default/textures/windows/Flyout_Pointer.png b/indra/newview/skins/default/textures/windows/Flyout_Pointer.png new file mode 100644 index 0000000000..69fc08ceaa Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Flyout_Pointer.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Close_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Close_Foreground.png new file mode 100644 index 0000000000..5dd0852a72 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Close_Foreground.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Close_Press.png b/indra/newview/skins/default/textures/windows/Icon_Close_Press.png new file mode 100644 index 0000000000..ea547fca6f Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Close_Press.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Close_Toast.png b/indra/newview/skins/default/textures/windows/Icon_Close_Toast.png new file mode 100644 index 0000000000..ecf01c617a Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Close_Toast.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Dock_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Dock_Foreground.png new file mode 100644 index 0000000000..4207ba68e5 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Dock_Foreground.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Dock_Press.png b/indra/newview/skins/default/textures/windows/Icon_Dock_Press.png new file mode 100644 index 0000000000..2d09475783 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Dock_Press.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear_Background.png b/indra/newview/skins/default/textures/windows/Icon_Gear_Background.png new file mode 100644 index 0000000000..db74b93afd Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Gear_Background.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Gear_Foreground.png new file mode 100644 index 0000000000..1032e45f7e Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Gear_Foreground.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear_Over.png b/indra/newview/skins/default/textures/windows/Icon_Gear_Over.png new file mode 100644 index 0000000000..01dbde102b Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Gear_Over.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Gear_Press.png b/indra/newview/skins/default/textures/windows/Icon_Gear_Press.png new file mode 100644 index 0000000000..6614bdd165 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Gear_Press.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Undock_Foreground.png b/indra/newview/skins/default/textures/windows/Icon_Undock_Foreground.png new file mode 100644 index 0000000000..9a71d16a3f Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Undock_Foreground.png differ diff --git a/indra/newview/skins/default/textures/windows/Icon_Undock_Press.png b/indra/newview/skins/default/textures/windows/Icon_Undock_Press.png new file mode 100644 index 0000000000..3ab8c3666a Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Icon_Undock_Press.png differ diff --git a/indra/newview/skins/default/textures/windows/Resize_Corner.png b/indra/newview/skins/default/textures/windows/Resize_Corner.png new file mode 100644 index 0000000000..16ed63e428 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Resize_Corner.png differ diff --git a/indra/newview/skins/default/textures/windows/Toast_CloseBtn.png b/indra/newview/skins/default/textures/windows/Toast_CloseBtn.png new file mode 100644 index 0000000000..78b137cdaf Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Toast_CloseBtn.png differ diff --git a/indra/newview/skins/default/textures/windows/Toast_Over.png b/indra/newview/skins/default/textures/windows/Toast_Over.png new file mode 100644 index 0000000000..807e8e553c Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Toast_Over.png differ diff --git a/indra/newview/skins/default/textures/windows/Window_Background.png b/indra/newview/skins/default/textures/windows/Window_Background.png new file mode 100644 index 0000000000..e9f15e76b9 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Window_Background.png differ diff --git a/indra/newview/skins/default/textures/windows/Window_Foreground.png b/indra/newview/skins/default/textures/windows/Window_Foreground.png new file mode 100644 index 0000000000..e76e9f3c79 Binary files /dev/null and b/indra/newview/skins/default/textures/windows/Window_Foreground.png differ diff --git a/indra/newview/skins/default/textures/world/NoEntryLines.png b/indra/newview/skins/default/textures/world/NoEntryLines.png new file mode 100644 index 0000000000..18e270bde5 Binary files /dev/null and b/indra/newview/skins/default/textures/world/NoEntryLines.png differ diff --git a/indra/newview/skins/default/textures/world/NoEntryPassLines.png b/indra/newview/skins/default/textures/world/NoEntryPassLines.png new file mode 100644 index 0000000000..e4b8fc6ae2 Binary files /dev/null and b/indra/newview/skins/default/textures/world/NoEntryPassLines.png differ diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml index 9f3a61d0c5..6b52da04d0 100644 --- a/indra/newview/skins/default/xui/da/floater_about.xml +++ b/indra/newview/skins/default/xui/da/floater_about.xml @@ -1,5 +1,5 @@ - + Second Life er gjort muligt for dig af Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl and many others. diff --git a/indra/newview/skins/default/xui/da/floater_about_land.xml b/indra/newview/skins/default/xui/da/floater_about_land.xml index df7d5fe8ff..15ebffa302 100644 --- a/indra/newview/skins/default/xui/da/floater_about_land.xml +++ b/indra/newview/skins/default/xui/da/floater_about_land.xml @@ -340,42 +340,18 @@ Kun større parceller kan vises i søgning. - - Alle kategorier - - - Linden Location - - - Kunst & kultur - - - Business - - - Uddannelse - - - Spil - - - Afslapning - - - Nybegynder venligt - - - Parker & natur - - - Beboelse - - - Indkøb - - - Andet - + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_avatar_picker.xml b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml new file mode 100644 index 0000000000..b0472eb7e2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_avatar_picker.xml @@ -0,0 +1,208 @@ + + + + '[TEXT]' not found + + + No-one near + + + No results + + + Searching... + + + + + Type part of the resident's name: + + + + + + New Permissions + + + + + Next owner can: + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_bumps.xml b/indra/newview/skins/default/xui/en/floater_bumps.xml new file mode 100644 index 0000000000..4fb2fe24cc --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_bumps.xml @@ -0,0 +1,47 @@ + + + + None detected + + + [TIME] [FIRST] [LAST] bumped you + + + [TIME] [FIRST] [LAST] pushed you with a script + + + [TIME] [FIRST] [LAST] hit you with an object + + + [TIME] [FIRST] [LAST] hit you with a scripted object + + + [TIME] [FIRST] [LAST] hit you with a physical object + + + [[hour,datetime,slt]:[min,datetime,slt]] + + + diff --git a/indra/newview/skins/default/xui/en/floater_buy_contents.xml b/indra/newview/skins/default/xui/en/floater_buy_contents.xml new file mode 100644 index 0000000000..0930043659 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_buy_contents.xml @@ -0,0 +1,94 @@ + + + + (no copy) + + + (no modify) + + + (no transfer) + + + [NAME] contains: + + + + + + + Buy for L$[AMOUNT] from [NAME]? + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_choose_group.xml b/indra/newview/skins/default/xui/en/floater_choose_group.xml new file mode 100644 index 0000000000..428afcff52 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_choose_group.xml @@ -0,0 +1,49 @@ + + + + Choose a group: + + + + + + + + + + Sim Name: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Estate ID: + + + + Parent ID: + + + + + + Grid Pos: + + + + + + + + + Redirect to Grid: + + + + + + + + + Billable Factor: + + + + + + L$ per m²: + + + + + + + + + + + + + (no target) + + + Sim Name: + + + Welsh + + + + + + + + + + + + + + (no target) + + + + + + + + + + + Destination: + + + + + + + Request: + + + + + + + + + Parameter: + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_hardware_settings.xml b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml new file mode 100644 index 0000000000..b7733c6388 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_hardware_settings.xml @@ -0,0 +1,162 @@ + + + + Filtering: + + + + Antialiasing: + + + + + + + + + + + (brightness, lower = brighter, 0 = default) + + + Enable VBO: + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml new file mode 100644 index 0000000000..37c6cbf391 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_inventory.xml @@ -0,0 +1,424 @@ + + + + Inventory + + + Items... + + + Fetched + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml new file mode 100644 index 0000000000..467168ebd8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_inventory_item_properties.xml @@ -0,0 +1,455 @@ + + + + (unknown) + + + (public) + + + You can: + + + Owner can: + + + [wkday,datetime,local] [mth,datetime,local] [day,datetime,local] [hour,datetime,local]:[min,datetime,local]:[second,datetime,local] [year,datetime,local] + + + + Name: + + + + Description: + + + + Creator: + + + Nicole Linden + + + diff --git a/indra/newview/skins/default/xui/en/floater_land_holdings.xml b/indra/newview/skins/default/xui/en/floater_land_holdings.xml new file mode 100644 index 0000000000..60677ca0df --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_land_holdings.xml @@ -0,0 +1,168 @@ + + + + [AREA] m² + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_mem_leaking.xml b/indra/newview/skins/default/xui/en/floater_mem_leaking.xml new file mode 100644 index 0000000000..da698f276b --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_mem_leaking.xml @@ -0,0 +1,128 @@ + + + + + + + + + + Current leaked memory: [SIZE] KB + + + [NOTE1] + + + [NOTE2] + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_moveview.xml b/indra/newview/skins/default/xui/en/floater_moveview.xml new file mode 100644 index 0000000000..17d12c89b7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_moveview.xml @@ -0,0 +1,184 @@ + + + + Walk Forward (press Up Arrow or W) + + + Walk Backwards (press Down Arrow or S) + + + Run Forward (press Up Arrow or W) + + + Run Backwards (press Down Arrow or S) + + + Fly Forward (press Up Arrow or W) + + + Fly Backwards (press Down Arrow or S) + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_openobject.xml b/indra/newview/skins/default/xui/en/floater_openobject.xml new file mode 100644 index 0000000000..e0ac2c1d51 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_openobject.xml @@ -0,0 +1,63 @@ + + + + + [DESC]: + + + + diff --git a/indra/newview/skins/default/xui/en/floater_pay.xml b/indra/newview/skins/default/xui/en/floater_pay.xml new file mode 100644 index 0000000000..96195c9ba1 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_pay.xml @@ -0,0 +1,129 @@ + + + + + + + Next owner can: + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_post_process.xml b/indra/newview/skins/default/xui/en/floater_post_process.xml new file mode 100644 index 0000000000..5a36ed5fd6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_post_process.xml @@ -0,0 +1,420 @@ + + + + + + + Brightness + + + + Saturation + + + + Contrast + + + + Contrast Base Color + + + + + + + + + + Light Amplification Multiple + + + + Noise Size + + + + Noise Strength + + + + + + + Luminosity Extraction + + + + Bloom Size + + + + Bloom Strength + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_preview_animation.xml b/indra/newview/skins/default/xui/en/floater_preview_animation.xml new file mode 100644 index 0000000000..e9342b772f --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_preview_animation.xml @@ -0,0 +1,59 @@ + + + + Animation: [NAME] + + + Description: + + + + diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml new file mode 100644 index 0000000000..1d2978adb8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -0,0 +1,394 @@ + + + + unknown + + + Snapshot destination + + + + + + + + File size: [SIZE] KB + + + + Object Name: + + + + + Owner Name: + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/floater_tos.xml b/indra/newview/skins/default/xui/en/floater_tos.xml new file mode 100644 index 0000000000..54facbb659 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_tos.xml @@ -0,0 +1,80 @@ + + + + http://secondlife.com/app/tos/ + + + + + + + + + + + + Events: + + + + + + + + + + + + + + + + + + + + + Search Results: + + + + + + + + Location: + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/fonts.xml b/indra/newview/skins/default/xui/en/fonts.xml new file mode 100644 index 0000000000..ced8ba83f7 --- /dev/null +++ b/indra/newview/skins/default/xui/en/fonts.xml @@ -0,0 +1,120 @@ + + + + + DejaVuSansCondensed.ttf + + MSGOTHIC.TTC + gulim.ttc + simhei.ttf + ArialUni.ttf + + + ヒラギノ角ゴ Pro W3.otf + ヒラギノ角ゴ ProN W3.otf + AppleGothic.dfont + AppleGothic.ttf + åŽæ–‡ç»†é»‘.ttf + + + + + Helvetica.dfont + + arial.ttf + + + Helvetica.dfont + + + + + Helvetica.dfont + + arialbd.ttf + + + Helvetica.dfont + + + + + DejaVuSansMono.ttf + + + + DejaVuSans.ttf + + + + DejaVuSansBold.ttf + + + + DejaVuSansOblique.ttf + + + + DejaVuSansBoldOblique.ttf + + + + arial.ttf + + + + arialbd.ttf + + + + ariali.ttf + + + + arialbi.ttf + + + + times.ttf + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/inspect_avatar.xml b/indra/newview/skins/default/xui/en/inspect_avatar.xml new file mode 100644 index 0000000000..cee789d435 --- /dev/null +++ b/indra/newview/skins/default/xui/en/inspect_avatar.xml @@ -0,0 +1,84 @@ + + + + + + + Codex Linden + + + The Guild + + +3 year-old account, Payment info on file +Languages: English, Spanish; +5 Sexterity Vest + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/panel_audio_device.xml b/indra/newview/skins/default/xui/en/panel_audio_device.xml new file mode 100644 index 0000000000..5f495ef8ce --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_audio_device.xml @@ -0,0 +1,153 @@ + + + + Default + + + Audio Devices + + + Input device (microphone): + + + + Output device (speakers): + + + + Input Level + + + Adjust the slider to control how loud you sound to other Residents. To test the input level, simply speak into your microphone. + + + + Please wait + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml new file mode 100644 index 0000000000..3de3365539 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml @@ -0,0 +1,65 @@ + + + + + + + + + Boris Linden + + + + Away + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_notes.xml b/indra/newview/skins/default/xui/en/panel_notes.xml new file mode 100644 index 0000000000..12badfccf0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_notes.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml new file mode 100644 index 0000000000..01602dc906 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_profile.xml @@ -0,0 +1,383 @@ + + + + [ACCTTYPE] [PAYMENTINFO] [AGEVERIFICATION] + + + + + + + + + + + + http://www.secondlife.com/account/billing.php?lang=en + + + + http://www.secondlife.com/account/partners.php?lang=en + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. + + + + + + + Lorem ipsum dolor sit amet, consectetur adlkjpiscing elit moose moose. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet. adipiscing elit. Aenean rigviverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet sorbet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. + + + + Homepage: + + + + + + + + + + + + + + + Lorem ipsum dolor sit amet, consectetur adlkjpiscing elit moose moose. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet. adipiscing elit. Aenean rigviverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet sorbet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/check_box.xml b/indra/newview/skins/default/xui/en/widgets/check_box.xml new file mode 100644 index 0000000000..bbb5e9b56a --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/check_box.xml @@ -0,0 +1,19 @@ + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/color_swatch.xml b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml new file mode 100644 index 0000000000..178c890c61 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/color_swatch.xml @@ -0,0 +1,8 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/combo_box.xml b/indra/newview/skins/default/xui/en/widgets/combo_box.xml new file mode 100644 index 0000000000..d7369d0726 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/combo_box.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/drop_down.xml b/indra/newview/skins/default/xui/en/widgets/drop_down.xml new file mode 100644 index 0000000000..602250ace6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/drop_down.xml @@ -0,0 +1,20 @@ + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/filter_editor.xml b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml new file mode 100644 index 0000000000..d7736832a3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/filter_editor.xml @@ -0,0 +1,8 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/flyout_button.xml b/indra/newview/skins/default/xui/en/widgets/flyout_button.xml new file mode 100644 index 0000000000..a5043c5c14 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/flyout_button.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml new file mode 100644 index 0000000000..26af76d8a3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/gesture_combo_box.xml @@ -0,0 +1,30 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/icon.xml b/indra/newview/skins/default/xui/en/widgets/icon.xml new file mode 100644 index 0000000000..adb743a628 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/icon.xml @@ -0,0 +1,7 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/line_editor.xml b/indra/newview/skins/default/xui/en/widgets/line_editor.xml new file mode 100644 index 0000000000..8b4126952e --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/line_editor.xml @@ -0,0 +1,19 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/list_view.xml b/indra/newview/skins/default/xui/en/widgets/list_view.xml new file mode 100644 index 0000000000..c66aeb57a0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/list_view.xml @@ -0,0 +1,6 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/location_input.xml b/indra/newview/skins/default/xui/en/widgets/location_input.xml new file mode 100644 index 0000000000..8f4d0edf95 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/location_input.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/menu.xml b/indra/newview/skins/default/xui/en/widgets/menu.xml new file mode 100644 index 0000000000..58543338f6 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/menu.xml @@ -0,0 +1,7 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/menu_item_call.xml b/indra/newview/skins/default/xui/en/widgets/menu_item_call.xml new file mode 100644 index 0000000000..24bda97f44 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/menu_item_call.xml @@ -0,0 +1,6 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/menu_item_check.xml b/indra/newview/skins/default/xui/en/widgets/menu_item_check.xml new file mode 100644 index 0000000000..f6b06cb50b --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/menu_item_check.xml @@ -0,0 +1,6 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/menu_item_separator.xml b/indra/newview/skins/default/xui/en/widgets/menu_item_separator.xml new file mode 100644 index 0000000000..e5cea476da --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/menu_item_separator.xml @@ -0,0 +1,6 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/multi_slider.xml b/indra/newview/skins/default/xui/en/widgets/multi_slider.xml new file mode 100644 index 0000000000..e0900b48f3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/multi_slider.xml @@ -0,0 +1,6 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/multi_slider_bar.xml b/indra/newview/skins/default/xui/en/widgets/multi_slider_bar.xml new file mode 100644 index 0000000000..04a2cd635c --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/multi_slider_bar.xml @@ -0,0 +1,10 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/name_editor.xml b/indra/newview/skins/default/xui/en/widgets/name_editor.xml new file mode 100644 index 0000000000..21ba5c77f8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/name_editor.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/output_monitor.xml b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml new file mode 100644 index 0000000000..505c7ba936 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/output_monitor.xml @@ -0,0 +1,9 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/panel.xml b/indra/newview/skins/default/xui/en/widgets/panel.xml new file mode 100644 index 0000000000..b81a70b845 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/panel.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/progress_bar.xml b/indra/newview/skins/default/xui/en/widgets/progress_bar.xml new file mode 100644 index 0000000000..339e53fbb8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/progress_bar.xml @@ -0,0 +1,12 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/radio_group.xml b/indra/newview/skins/default/xui/en/widgets/radio_group.xml new file mode 100644 index 0000000000..ad7ef5bffc --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/radio_group.xml @@ -0,0 +1,6 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/radio_item.xml b/indra/newview/skins/default/xui/en/widgets/radio_item.xml new file mode 100644 index 0000000000..dd848f3acd --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/radio_item.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/scroll_bar.xml b/indra/newview/skins/default/xui/en/widgets/scroll_bar.xml new file mode 100644 index 0000000000..48bc021e6d --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/scroll_bar.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/scroll_container.xml b/indra/newview/skins/default/xui/en/widgets/scroll_container.xml new file mode 100644 index 0000000000..86356ff563 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/scroll_container.xml @@ -0,0 +1,5 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/scroll_list.xml b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml new file mode 100644 index 0000000000..e3a53eee4d --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/scroll_list.xml @@ -0,0 +1,16 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/search_editor.xml b/indra/newview/skins/default/xui/en/widgets/search_editor.xml new file mode 100644 index 0000000000..15b23ea9b3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/search_editor.xml @@ -0,0 +1,15 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/side_tray.xml b/indra/newview/skins/default/xui/en/widgets/side_tray.xml new file mode 100644 index 0000000000..8b4a5afbe9 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/side_tray.xml @@ -0,0 +1,8 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml new file mode 100644 index 0000000000..4f2261c953 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/simple_text_editor.xml @@ -0,0 +1,23 @@ + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/slider.xml b/indra/newview/skins/default/xui/en/widgets/slider.xml new file mode 100644 index 0000000000..f735d09476 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/slider.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/slider_bar.xml b/indra/newview/skins/default/xui/en/widgets/slider_bar.xml new file mode 100644 index 0000000000..bc1ca339a2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/slider_bar.xml @@ -0,0 +1,9 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/spinner.xml b/indra/newview/skins/default/xui/en/widgets/spinner.xml new file mode 100644 index 0000000000..7d1a5118cb --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/spinner.xml @@ -0,0 +1,16 @@ + + + + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/split_button.xml b/indra/newview/skins/default/xui/en/widgets/split_button.xml new file mode 100644 index 0000000000..b0367b599b --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/split_button.xml @@ -0,0 +1,24 @@ + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/tab_container.xml b/indra/newview/skins/default/xui/en/widgets/tab_container.xml new file mode 100644 index 0000000000..7aad55fb37 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/tab_container.xml @@ -0,0 +1,9 @@ + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/text.xml b/indra/newview/skins/default/xui/en/widgets/text.xml new file mode 100644 index 0000000000..3d98cd66f9 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/text.xml @@ -0,0 +1,16 @@ + + diff --git a/indra/newview/skins/default/xui/en/widgets/text_editor.xml b/indra/newview/skins/default/xui/en/widgets/text_editor.xml new file mode 100644 index 0000000000..deaade04f8 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/text_editor.xml @@ -0,0 +1,4 @@ + + + diff --git a/indra/newview/skins/default/xui/en/widgets/texture_picker.xml b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml new file mode 100644 index 0000000000..33c3475eb2 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/texture_picker.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/indra/newview/skins/default/xui/en/widgets/view_border.xml b/indra/newview/skins/default/xui/en/widgets/view_border.xml new file mode 100644 index 0000000000..0b0a9beb95 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/view_border.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/indra/newview/skins/default/xui/en/widgets/web_browser.xml b/indra/newview/skins/default/xui/en/widgets/web_browser.xml new file mode 100644 index 0000000000..118d63bbf0 --- /dev/null +++ b/indra/newview/skins/default/xui/en/widgets/web_browser.xml @@ -0,0 +1,2 @@ + + diff --git a/indra/newview/skins/default/xui/en/xui_version.xml b/indra/newview/skins/default/xui/en/xui_version.xml new file mode 100644 index 0000000000..0e777751d3 --- /dev/null +++ b/indra/newview/skins/default/xui/en/xui_version.xml @@ -0,0 +1,4 @@ + + + 1.0 + diff --git a/indra/newview/skins/default/xui/es/floater_about.xml b/indra/newview/skins/default/xui/es/floater_about.xml index e59b5a6fb4..3e0f6513cc 100644 --- a/indra/newview/skins/default/xui/es/floater_about.xml +++ b/indra/newview/skins/default/xui/es/floater_about.xml @@ -1,5 +1,5 @@ - + Le ofrecen Second Life Philip, Tessa, Andrew, Cory, James, Ben, Char, Charlie, Colin, Dan, Daniel, Doug, Eric, Hamlet, Haney, Eve, Hunter, Ian, Jeff, Jennifer, Jim, John, Lee, Mark, Peter, Phoenix, Richard, Robin, Xenon, Steve, Tanya, Eddie, Avi, Frank, Bruce, Aaron, Alice, Bob, Debra, Eileen, Helen, Janet, Louie, Leviathania, Stefan, Ray, Kevin, Tom, Mikeb, MikeT, Burgess, Elena, Tracy, Bill, Todd, Ryan, Zach, Sarah, Nova, Tim, Stephanie, Michael, Evan, Nicolas, Catherine, Rachelle, Dave, Holly, Bub, Kelly, Magellan, Ramzi, Don, Sabin, Jill, Rheya, Jeska, Torley, Kona, Callum, Charity, Ventrella, Jack, Vektor, Iris, Chris, Nicole, Mick, Reuben, Blue, Babbage, Yedwab, Deana, Lauren, Brent, Pathfinder, Chadrick, Altruima, Jesse, Teeny, Monroe, Icculus, David, Tess, Lizzie, Patsy, Isaac, Lawrence, Cyn, Bo, Gia, Annette, Marius, Tbone, Jonathan, Karen, Ginsu, Satoko, Yuko, Makiko, Thomas, Harry, Seth, Alexei, Brian, Guy, Runitai, Ethan, Data, Cornelius, Kenny, Swiss, Zero, Natria, Wendy, Stephen, Teeple, Thumper, Lucy, Dee, Mia, Liana, Warren, Branka, Aura, beez, Milo, Hermia, Red, Thrax, Joe, Sally, Magenta, Mogura, Paul, Jose, Rejean, Henrik, Lexie, Amber, Logan, Xan, Nora, Morpheus, Donovan, Leyla, MichaelFrancis, Beast, Cube, Bucky, Joshua, Stryfe, Harmony, Teresa, Claudia, Walker, Glenn, Fritz, Fordak, June, Cleopetra, Jean, Ivy, Betsy, Roosevelt, Spike, Ken, Which, Tofu, Chiyo, Rob, Zee, dustin, George, Del, Matthew, Cat, Jacqui, Lightfoot, Adrian, Viola, Alfred, Noel, Irfan, Sunil, Yool, Rika, Jane, Xtreme, Frontier, a2, Neo, Siobhan, Yoz, Justin, Elle, Qarl, Benjamin, Isabel, Gulliver, Everett, Christopher, Izzy, Stephany, Garry, Sejong, Sean, Tobin, Iridium, Meta, Anthony, Jeremy, JP, Jake, Maurice, Madhavi, Leopard, Kyle, Joon, Kari, Bert, Belinda, Jon, Kristi, Bridie, Pramod, KJ, Socrates, Maria, Ivan, Aric, Yamasaki, Adreanne, Jay, MitchK, Ceren, Coco, Durl, Jenny, Periapse, Kartic, Storrs, Lotte, Sandy, Rohn, Colossus, Zen, BigPapi, Brad, Pastrami, Kurz, Mani, Neuro, Jaime, MJ, Rowan, Sgt, Elvis, Gecko, Samuel, Sardonyx, Leo, Bryan, Niko, Soft, Poppy, Rachel, Aki, Angelo, Banzai, Alexa, Sue, CeeLo, Bender, CG, Gillian, Pelle, Nick, Echo, Zara, Christine, Shamiran, Emma, Blake, Keiko, Plexus, Joppa, Sidewinder, Erica, Ashlei, Twilight, Kristen, Brett, Q, Enus, Simon, Bevis, Kraft, Kip, Chandler, Ron, LauraP, Ram, KyleJM, Scouse, Prospero, Melissa, Marty, Nat, Hamilton, Kend, Lordan, Jimmy, Kosmo, Seraph, Green, Ekim, Wiggo, JT, Rome, Doris, Miz, Benoc, Whump, Trinity, Patch, Kate, TJ, Bao, Joohwan, Christy, Sofia, Matias, Cogsworth, Johan, Oreh, Cheah, Angela, Brandy, Mango, Lan, Aleks, Gloria, Heidy, Mitchell, Space, Colton, Bambers, Einstein, Maggie, Malbers, Rose, Winnie, Stella, Milton, Rothman, Niall, Marin, Allison, Katie, Dawn, Katt, Dusty, Kalpana, Judy, Andrea, Ambroff, Infinity, Gail, Rico, Raymond, Yi, William, Christa, M, Teagan, Scout, Molly, Dante, Corr, Dynamike, Usi, Kaylee, Vidtuts, Lil, Danica, Sascha, Kelv, Jacob, Nya, Rodney, Brandon, Elsie, Blondin, Grant, Katrin, Nyx, Gabriel, Locklainn, Claire, Devin, Minerva, Monty, Austin, Bradford, Si, Keira, H, Caitlin, Dita, Makai, Jenn, Ann, Meredith, Clare, Joy, Praveen, Cody, Edmund, Ruthe, Sirena, Gayathri, Spider, FJ, Davidoff, Tian, Jennie, Louise, Oskar, Landon, Noelle, Jarv, Ingrid, Al, Sommer, Doc, Aria, Huin, Gray, Lili, Vir, DJ, Yang, T, Simone, Maestro, Scott, Charlene, Quixote, Amanda, Susan, Zed, Anne, Enkidu, Esbee, Joroan, Katelin, Roxie, Tay, Scarlet, Kevin, Johnny, Wolfgang, Andren, Bob, Howard, Merov, Rand, Ray, Michon, Newell, Galen, Dessie, Les, Michon, Jenelle, Geo, Siz, Shapiro, Pete, Calyle, Selene, Allen, Phoebe, Goldin, Kimmora, Dakota, Slaton, Lindquist, Zoey, Hari, Othello, Rohit, Sheldon, Petra, Viale, Gordon, Kaye, Pink, Ferny, Emerson, Davy, Bri, Chan, Juan, Robert, Terrence, Nathan, Carl, y otros muchos. diff --git a/indra/newview/skins/default/xui/es/floater_animation_preview.xml b/indra/newview/skins/default/xui/es/floater_animation_preview.xml index de01c5c54b..5a03aa6370 100644 --- a/indra/newview/skins/default/xui/es/floater_animation_preview.xml +++ b/indra/newview/skins/default/xui/es/floater_animation_preview.xml @@ -14,127 +14,53 @@ Posición de las manos - - Extendidas - - - Relajadas - - - Ambas señalan - - - Puño - - - La izquierda relajada - - - La izquierda señala - - - Puño en la izquierda - - - La derecha relajada - - - La derecha señala - - - Puño en la derecha - - - La derecha saluda - - - Escribiendo - - - Paz en la derecha - + + + + + + + + + + + + + Expresión - - [Nada] - - - Aaaaah - - - Con miedo - - - Enfadada - - - Gran sonrisa - - - Aburrida - - - Llorar - - - Desdén - - - Avergonzada - - - Fruncir el ceño - - - Besar - - - Reír - - - Sacar la lengua - - - Rechazo - - - Triste - - - Encogerse de hombros - - - Sonrisa - - - Sorpresa - - - Guiño - - - Preocupación - + + + + + + + + + + + + + + + + + + + + Vista previa mientras - - Estar de pie - - - Caminar - - - Estar sentado - - - Volar - + + + + diff --git a/indra/newview/skins/default/xui/es/floater_buy_land.xml b/indra/newview/skins/default/xui/es/floater_buy_land.xml index b926b59195..7ee15955eb 100644 --- a/indra/newview/skins/default/xui/es/floater_buy_land.xml +++ b/indra/newview/skins/default/xui/es/floater_buy_land.xml @@ -75,15 +75,9 @@ incluyendo los objetos Sólo pueden ser propietarios de terreno los miembros premium. - - 9.95 US$/mes, facturados mensualmente - - - 7.50 US$/mes, facturados cuatrimestralmente - - - 6.00 US$/mes, facturados anualmente - + + + Aumenta su cuota mensual por uso de terreno a 40 US$/mes. diff --git a/indra/newview/skins/default/xui/es/floater_customize.xml b/indra/newview/skins/default/xui/es/floater_customize.xml index 58aea9a380..5efc989eff 100644 --- a/indra/newview/skins/default/xui/es/floater_customize.xml +++ b/indra/newview/skins/default/xui/es/floater_customize.xml @@ -14,12 +14,8 @@